Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/codegen.h"
6 :
7 : #if defined(V8_OS_AIX)
8 : #include <fenv.h> // NOLINT(build/c++11)
9 : #endif
10 :
11 : #include <memory>
12 :
13 : #include "src/ast/prettyprinter.h"
14 : #include "src/bootstrapper.h"
15 : #include "src/compilation-info.h"
16 : #include "src/counters.h"
17 : #include "src/debug/debug.h"
18 : #include "src/eh-frame.h"
19 : #include "src/objects-inl.h"
20 : #include "src/runtime/runtime.h"
21 :
22 : namespace v8 {
23 : namespace internal {
24 :
25 :
26 : #if defined(V8_OS_WIN)
27 : double modulo(double x, double y) {
28 : // Workaround MS fmod bugs. ECMA-262 says:
29 : // dividend is finite and divisor is an infinity => result equals dividend
30 : // dividend is a zero and divisor is nonzero finite => result equals dividend
31 : if (!(std::isfinite(x) && (!std::isfinite(y) && !std::isnan(y))) &&
32 : !(x == 0 && (y != 0 && std::isfinite(y)))) {
33 : x = fmod(x, y);
34 : }
35 : return x;
36 : }
37 : #else // POSIX
38 :
39 3934543 : double modulo(double x, double y) {
40 : #if defined(V8_OS_AIX)
41 : // AIX raises an underflow exception for (Number.MIN_VALUE % Number.MAX_VALUE)
42 : feclearexcept(FE_ALL_EXCEPT);
43 : double result = std::fmod(x, y);
44 : int exception = fetestexcept(FE_UNDERFLOW);
45 : return (exception ? x : result);
46 : #else
47 3934543 : return std::fmod(x, y);
48 : #endif
49 : }
50 : #endif // defined(V8_OS_WIN)
51 :
52 :
53 : #define UNARY_MATH_FUNCTION(name, generator) \
54 : static UnaryMathFunctionWithIsolate fast_##name##_function = nullptr; \
55 : double std_##name(double x, Isolate* isolate) { return std::name(x); } \
56 : void init_fast_##name##_function(Isolate* isolate) { \
57 : if (FLAG_fast_math) fast_##name##_function = generator(isolate); \
58 : if (!fast_##name##_function) fast_##name##_function = std_##name; \
59 : } \
60 : void lazily_initialize_fast_##name(Isolate* isolate) { \
61 : if (!fast_##name##_function) init_fast_##name##_function(isolate); \
62 : } \
63 : double fast_##name(double x, Isolate* isolate) { \
64 : return (*fast_##name##_function)(x, isolate); \
65 : }
66 :
67 14 : UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction)
68 :
69 : #undef UNARY_MATH_FUNCTION
70 :
71 :
72 : #ifdef DEBUG
73 :
74 : Comment::Comment(Assembler* assembler, const char* msg)
75 : : assembler_(assembler), msg_(msg) {
76 : assembler_->RecordComment(msg);
77 : }
78 :
79 :
80 : Comment::~Comment() {
81 : if (msg_[0] == '[') assembler_->RecordComment("]");
82 : }
83 :
84 : #endif // DEBUG
85 :
86 :
87 3437113 : void CodeGenerator::MakeCodePrologue(CompilationInfo* info, const char* kind) {
88 : bool print_ast = false;
89 : const char* ftype;
90 :
91 3437113 : if (info->isolate()->bootstrapper()->IsActive()) {
92 : print_ast = FLAG_print_builtin_ast;
93 : ftype = "builtin";
94 : } else {
95 : print_ast = FLAG_print_ast;
96 : ftype = "user-defined";
97 : }
98 :
99 3437113 : if (FLAG_trace_codegen || print_ast) {
100 0 : std::unique_ptr<char[]> name = info->GetDebugName();
101 : PrintF("[generating %s code for %s function: %s]\n", kind, ftype,
102 0 : name.get());
103 : }
104 :
105 : #ifdef DEBUG
106 : if (info->parse_info() && print_ast) {
107 : PrintF("--- AST ---\n%s\n",
108 : AstPrinter(info->isolate()).PrintProgram(info->literal()));
109 : }
110 : #endif // DEBUG
111 3437113 : }
112 :
113 2272043 : Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
114 : EhFrameWriter* eh_frame_writer,
115 6168805 : CompilationInfo* info,
116 : Handle<Object> self_reference) {
117 2272048 : Isolate* isolate = info->isolate();
118 :
119 : // Allocate and install the code.
120 : CodeDesc desc;
121 : Code::Flags flags = info->code_flags();
122 : bool is_crankshafted =
123 3896759 : Code::ExtractKindFromFlags(flags) == Code::OPTIMIZED_FUNCTION ||
124 : info->IsStub();
125 2272043 : masm->GetCode(&desc);
126 2272042 : if (eh_frame_writer) eh_frame_writer->GetEhFrame(&desc);
127 :
128 : Handle<Code> code = isolate->factory()->NewCode(
129 : desc, flags, self_reference, false, is_crankshafted,
130 4544088 : info->prologue_offset(), info->is_debug() && !is_crankshafted);
131 : isolate->counters()->total_compiled_code_size()->Increment(
132 2272048 : code->instruction_size());
133 2272052 : return code;
134 : }
135 :
136 : // Print function's source if it was not printed before.
137 : // Return a sequential id under which this function was printed.
138 0 : static int PrintFunctionSource(CompilationInfo* info,
139 0 : std::vector<Handle<SharedFunctionInfo>>* printed,
140 : int inlining_id,
141 : Handle<SharedFunctionInfo> shared) {
142 : // Outermost function has source id -1 and inlined functions take
143 : // source ids starting from 0.
144 : int source_id = -1;
145 0 : if (inlining_id != SourcePosition::kNotInlined) {
146 0 : for (unsigned i = 0; i < printed->size(); i++) {
147 0 : if (printed->at(i).is_identical_to(shared)) {
148 0 : return i;
149 : }
150 : }
151 0 : source_id = static_cast<int>(printed->size());
152 0 : printed->push_back(shared);
153 : }
154 :
155 : Isolate* isolate = info->isolate();
156 0 : if (!shared->script()->IsUndefined(isolate)) {
157 : Handle<Script> script(Script::cast(shared->script()), isolate);
158 :
159 0 : if (!script->source()->IsUndefined(isolate)) {
160 0 : CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
161 : Object* source_name = script->name();
162 0 : OFStream os(tracing_scope.file());
163 0 : os << "--- FUNCTION SOURCE (";
164 0 : if (source_name->IsString()) {
165 0 : os << String::cast(source_name)->ToCString().get() << ":";
166 : }
167 0 : os << shared->DebugName()->ToCString().get() << ") id{";
168 0 : os << info->optimization_id() << "," << source_id << "} start{";
169 0 : os << shared->start_position() << "} ---\n";
170 : {
171 : DisallowHeapAllocation no_allocation;
172 : int start = shared->start_position();
173 0 : int len = shared->end_position() - start;
174 : String::SubStringRange source(String::cast(script->source()), start,
175 : len);
176 0 : for (const auto& c : source) {
177 0 : os << AsReversiblyEscapedUC16(c);
178 : }
179 : }
180 :
181 0 : os << "\n--- END ---\n";
182 : }
183 : }
184 :
185 0 : return source_id;
186 : }
187 :
188 : // Print information for the given inlining: which function was inlined and
189 : // where the inlining occured.
190 0 : static void PrintInlinedFunctionInfo(
191 0 : CompilationInfo* info, int source_id, int inlining_id,
192 : const CompilationInfo::InlinedFunctionHolder& h) {
193 0 : CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
194 0 : OFStream os(tracing_scope.file());
195 0 : os << "INLINE (" << h.shared_info->DebugName()->ToCString().get() << ") id{"
196 0 : << info->optimization_id() << "," << source_id << "} AS " << inlining_id
197 0 : << " AT ";
198 0 : const SourcePosition position = h.position.position;
199 0 : if (position.IsKnown()) {
200 0 : os << "<" << position.InliningId() << ":" << position.ScriptOffset() << ">";
201 : } else {
202 0 : os << "<?>";
203 : }
204 : os << std::endl;
205 0 : }
206 :
207 : // Print the source of all functions that participated in this optimizing
208 : // compilation. For inlined functions print source position of their inlining.
209 0 : static void DumpParticipatingSource(CompilationInfo* info) {
210 : AllowDeferredHandleDereference allow_deference_for_print_code;
211 :
212 : std::vector<Handle<SharedFunctionInfo>> printed;
213 0 : printed.reserve(info->inlined_functions().size());
214 :
215 : PrintFunctionSource(info, &printed, SourcePosition::kNotInlined,
216 0 : info->shared_info());
217 0 : const auto& inlined = info->inlined_functions();
218 0 : for (unsigned id = 0; id < inlined.size(); id++) {
219 : const int source_id =
220 0 : PrintFunctionSource(info, &printed, id, inlined[id].shared_info);
221 0 : PrintInlinedFunctionInfo(info, source_id, id, inlined[id]);
222 : }
223 0 : }
224 :
225 2272042 : void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
226 2272042 : if (FLAG_print_opt_source && info->IsOptimizing()) {
227 0 : DumpParticipatingSource(info);
228 : }
229 :
230 : #ifdef ENABLE_DISASSEMBLER
231 : AllowDeferredHandleDereference allow_deference_for_print_code;
232 : Isolate* isolate = info->isolate();
233 : bool print_code =
234 : isolate->bootstrapper()->IsActive()
235 : ? FLAG_print_builtin_code
236 : : (FLAG_print_code || (info->IsStub() && FLAG_print_code_stubs) ||
237 : (info->IsOptimizing() && FLAG_print_opt_code &&
238 : info->shared_info()->PassesFilter(FLAG_print_opt_code_filter)) ||
239 : (info->IsWasm() && FLAG_print_wasm_code));
240 : if (print_code) {
241 : std::unique_ptr<char[]> debug_name = info->GetDebugName();
242 : CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
243 : OFStream os(tracing_scope.file());
244 :
245 : // Print the source code if available.
246 : bool print_source =
247 : info->parse_info() && (code->kind() == Code::OPTIMIZED_FUNCTION ||
248 : code->kind() == Code::FUNCTION);
249 : if (print_source) {
250 : Handle<SharedFunctionInfo> shared = info->shared_info();
251 : Handle<Script> script = info->script();
252 : if (!script->IsUndefined(isolate) &&
253 : !script->source()->IsUndefined(isolate)) {
254 : os << "--- Raw source ---\n";
255 : StringCharacterStream stream(String::cast(script->source()),
256 : shared->start_position());
257 : // fun->end_position() points to the last character in the stream. We
258 : // need to compensate by adding one to calculate the length.
259 : int source_len = shared->end_position() - shared->start_position() + 1;
260 : for (int i = 0; i < source_len; i++) {
261 : if (stream.HasMore()) {
262 : os << AsReversiblyEscapedUC16(stream.GetNext());
263 : }
264 : }
265 : os << "\n\n";
266 : }
267 : }
268 : if (info->IsOptimizing()) {
269 : if (FLAG_print_unopt_code && info->parse_info()) {
270 : os << "--- Unoptimized code ---\n";
271 : info->closure()->shared()->code()->Disassemble(debug_name.get(), os);
272 : }
273 : os << "--- Optimized code ---\n"
274 : << "optimization_id = " << info->optimization_id() << "\n";
275 : } else {
276 : os << "--- Code ---\n";
277 : }
278 : if (print_source) {
279 : Handle<SharedFunctionInfo> shared = info->shared_info();
280 : os << "source_position = " << shared->start_position() << "\n";
281 : }
282 : code->Disassemble(debug_name.get(), os);
283 : os << "--- End code ---\n";
284 : }
285 : #endif // ENABLE_DISASSEMBLER
286 2272042 : }
287 :
288 : } // namespace internal
289 : } // namespace v8
|