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 3912950 : 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 3912950 : 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 : #define __ ACCESS_MASM(masm_)
73 :
74 : #ifdef DEBUG
75 :
76 : Comment::Comment(MacroAssembler* masm, const char* msg)
77 : : masm_(masm), msg_(msg) {
78 : __ RecordComment(msg);
79 : }
80 :
81 :
82 : Comment::~Comment() {
83 : if (msg_[0] == '[') __ RecordComment("]");
84 : }
85 :
86 : #endif // DEBUG
87 :
88 : #undef __
89 :
90 :
91 3434775 : void CodeGenerator::MakeCodePrologue(CompilationInfo* info, const char* kind) {
92 : bool print_ast = false;
93 : const char* ftype;
94 :
95 3434775 : if (info->isolate()->bootstrapper()->IsActive()) {
96 : print_ast = FLAG_print_builtin_ast;
97 : ftype = "builtin";
98 : } else {
99 : print_ast = FLAG_print_ast;
100 : ftype = "user-defined";
101 : }
102 :
103 3434775 : if (FLAG_trace_codegen || print_ast) {
104 0 : std::unique_ptr<char[]> name = info->GetDebugName();
105 : PrintF("[generating %s code for %s function: %s]\n", kind, ftype,
106 0 : name.get());
107 : }
108 :
109 : #ifdef DEBUG
110 : if (info->parse_info() && print_ast) {
111 : PrintF("--- AST ---\n%s\n",
112 : AstPrinter(info->isolate()).PrintProgram(info->literal()));
113 : }
114 : #endif // DEBUG
115 3434775 : }
116 :
117 2270647 : Handle<Code> CodeGenerator::MakeCodeEpilogue(MacroAssembler* masm,
118 : EhFrameWriter* eh_frame_writer,
119 6165098 : CompilationInfo* info,
120 : Handle<Object> self_reference) {
121 2270649 : Isolate* isolate = info->isolate();
122 :
123 : // Allocate and install the code.
124 : CodeDesc desc;
125 : Code::Flags flags = info->code_flags();
126 : bool is_crankshafted =
127 3894451 : Code::ExtractKindFromFlags(flags) == Code::OPTIMIZED_FUNCTION ||
128 : info->IsStub();
129 2270647 : masm->GetCode(&desc);
130 2270647 : if (eh_frame_writer) eh_frame_writer->GetEhFrame(&desc);
131 :
132 : Handle<Code> code = isolate->factory()->NewCode(
133 : desc, flags, self_reference, false, is_crankshafted,
134 4541294 : info->prologue_offset(), info->is_debug() && !is_crankshafted);
135 : isolate->counters()->total_compiled_code_size()->Increment(
136 2270649 : code->instruction_size());
137 2270649 : return code;
138 : }
139 :
140 : // Print function's source if it was not printed before.
141 : // Return a sequential id under which this function was printed.
142 0 : static int PrintFunctionSource(CompilationInfo* info,
143 0 : std::vector<Handle<SharedFunctionInfo>>* printed,
144 : int inlining_id,
145 : Handle<SharedFunctionInfo> shared) {
146 : // Outermost function has source id -1 and inlined functions take
147 : // source ids starting from 0.
148 : int source_id = -1;
149 0 : if (inlining_id != SourcePosition::kNotInlined) {
150 0 : for (unsigned i = 0; i < printed->size(); i++) {
151 0 : if (printed->at(i).is_identical_to(shared)) {
152 0 : return i;
153 : }
154 : }
155 0 : source_id = static_cast<int>(printed->size());
156 0 : printed->push_back(shared);
157 : }
158 :
159 : Isolate* isolate = info->isolate();
160 0 : if (!shared->script()->IsUndefined(isolate)) {
161 : Handle<Script> script(Script::cast(shared->script()), isolate);
162 :
163 0 : if (!script->source()->IsUndefined(isolate)) {
164 0 : CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
165 : Object* source_name = script->name();
166 0 : OFStream os(tracing_scope.file());
167 0 : os << "--- FUNCTION SOURCE (";
168 0 : if (source_name->IsString()) {
169 0 : os << String::cast(source_name)->ToCString().get() << ":";
170 : }
171 0 : os << shared->DebugName()->ToCString().get() << ") id{";
172 0 : os << info->optimization_id() << "," << source_id << "} start{";
173 0 : os << shared->start_position() << "} ---\n";
174 : {
175 : DisallowHeapAllocation no_allocation;
176 : int start = shared->start_position();
177 0 : int len = shared->end_position() - start;
178 : String::SubStringRange source(String::cast(script->source()), start,
179 : len);
180 0 : for (const auto& c : source) {
181 0 : os << AsReversiblyEscapedUC16(c);
182 : }
183 : }
184 :
185 0 : os << "\n--- END ---\n";
186 : }
187 : }
188 :
189 0 : return source_id;
190 : }
191 :
192 : // Print information for the given inlining: which function was inlined and
193 : // where the inlining occured.
194 0 : static void PrintInlinedFunctionInfo(
195 0 : CompilationInfo* info, int source_id, int inlining_id,
196 : const CompilationInfo::InlinedFunctionHolder& h) {
197 0 : CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
198 0 : OFStream os(tracing_scope.file());
199 0 : os << "INLINE (" << h.shared_info->DebugName()->ToCString().get() << ") id{"
200 0 : << info->optimization_id() << "," << source_id << "} AS " << inlining_id
201 0 : << " AT ";
202 0 : const SourcePosition position = h.position.position;
203 0 : if (position.IsKnown()) {
204 0 : os << "<" << position.InliningId() << ":" << position.ScriptOffset() << ">";
205 : } else {
206 0 : os << "<?>";
207 : }
208 : os << std::endl;
209 0 : }
210 :
211 : // Print the source of all functions that participated in this optimizing
212 : // compilation. For inlined functions print source position of their inlining.
213 0 : static void DumpParticipatingSource(CompilationInfo* info) {
214 : AllowDeferredHandleDereference allow_deference_for_print_code;
215 :
216 : std::vector<Handle<SharedFunctionInfo>> printed;
217 0 : printed.reserve(info->inlined_functions().size());
218 :
219 : PrintFunctionSource(info, &printed, SourcePosition::kNotInlined,
220 0 : info->shared_info());
221 0 : const auto& inlined = info->inlined_functions();
222 0 : for (unsigned id = 0; id < inlined.size(); id++) {
223 : const int source_id =
224 0 : PrintFunctionSource(info, &printed, id, inlined[id].shared_info);
225 0 : PrintInlinedFunctionInfo(info, source_id, id, inlined[id]);
226 : }
227 0 : }
228 :
229 2270646 : void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
230 2270646 : if (FLAG_print_opt_source && info->IsOptimizing()) {
231 0 : DumpParticipatingSource(info);
232 : }
233 :
234 : #ifdef ENABLE_DISASSEMBLER
235 : AllowDeferredHandleDereference allow_deference_for_print_code;
236 : Isolate* isolate = info->isolate();
237 : bool print_code =
238 : isolate->bootstrapper()->IsActive()
239 : ? FLAG_print_builtin_code
240 : : (FLAG_print_code || (info->IsStub() && FLAG_print_code_stubs) ||
241 : (info->IsOptimizing() && FLAG_print_opt_code &&
242 : info->shared_info()->PassesFilter(FLAG_print_opt_code_filter)) ||
243 : (info->IsWasm() && FLAG_print_wasm_code));
244 : if (print_code) {
245 : std::unique_ptr<char[]> debug_name = info->GetDebugName();
246 : CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
247 : OFStream os(tracing_scope.file());
248 :
249 : // Print the source code if available.
250 : bool print_source =
251 : info->parse_info() && (code->kind() == Code::OPTIMIZED_FUNCTION ||
252 : code->kind() == Code::FUNCTION);
253 : if (print_source) {
254 : Handle<SharedFunctionInfo> shared = info->shared_info();
255 : Handle<Script> script = info->script();
256 : if (!script->IsUndefined(isolate) &&
257 : !script->source()->IsUndefined(isolate)) {
258 : os << "--- Raw source ---\n";
259 : StringCharacterStream stream(String::cast(script->source()),
260 : shared->start_position());
261 : // fun->end_position() points to the last character in the stream. We
262 : // need to compensate by adding one to calculate the length.
263 : int source_len = shared->end_position() - shared->start_position() + 1;
264 : for (int i = 0; i < source_len; i++) {
265 : if (stream.HasMore()) {
266 : os << AsReversiblyEscapedUC16(stream.GetNext());
267 : }
268 : }
269 : os << "\n\n";
270 : }
271 : }
272 : if (info->IsOptimizing()) {
273 : if (FLAG_print_unopt_code && info->parse_info()) {
274 : os << "--- Unoptimized code ---\n";
275 : info->closure()->shared()->code()->Disassemble(debug_name.get(), os);
276 : }
277 : os << "--- Optimized code ---\n"
278 : << "optimization_id = " << info->optimization_id() << "\n";
279 : } else {
280 : os << "--- Code ---\n";
281 : }
282 : if (print_source) {
283 : Handle<SharedFunctionInfo> shared = info->shared_info();
284 : os << "source_position = " << shared->start_position() << "\n";
285 : }
286 : code->Disassemble(debug_name.get(), os);
287 : os << "--- End code ---\n";
288 : }
289 : #endif // ENABLE_DISASSEMBLER
290 2270646 : }
291 :
292 : } // namespace internal
293 : } // namespace v8
|