OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler.h" | 5 #include "src/compiler.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <memory> | 8 #include <memory> |
9 | 9 |
10 #include "src/asmjs/asm-js.h" | 10 #include "src/asmjs/asm-js.h" |
(...skipping 22 matching lines...) Expand all Loading... |
33 #include "src/parsing/rewriter.h" | 33 #include "src/parsing/rewriter.h" |
34 #include "src/parsing/scanner-character-streams.h" | 34 #include "src/parsing/scanner-character-streams.h" |
35 #include "src/runtime-profiler.h" | 35 #include "src/runtime-profiler.h" |
36 #include "src/snapshot/code-serializer.h" | 36 #include "src/snapshot/code-serializer.h" |
37 #include "src/vm-state-inl.h" | 37 #include "src/vm-state-inl.h" |
38 | 38 |
39 namespace v8 { | 39 namespace v8 { |
40 namespace internal { | 40 namespace internal { |
41 | 41 |
42 | 42 |
43 #define PARSE_INFO_GETTER(type, name) \ | |
44 type CompilationInfo::name() const { \ | |
45 CHECK(parse_info()); \ | |
46 return parse_info()->name(); \ | |
47 } | |
48 | |
49 | |
50 #define PARSE_INFO_GETTER_WITH_DEFAULT(type, name, def) \ | |
51 type CompilationInfo::name() const { \ | |
52 return parse_info() ? parse_info()->name() : def; \ | |
53 } | |
54 | |
55 | |
56 PARSE_INFO_GETTER(Handle<Script>, script) | |
57 PARSE_INFO_GETTER(FunctionLiteral*, literal) | |
58 PARSE_INFO_GETTER_WITH_DEFAULT(DeclarationScope*, scope, nullptr) | |
59 PARSE_INFO_GETTER_WITH_DEFAULT(Handle<Context>, context, | |
60 Handle<Context>::null()) | |
61 PARSE_INFO_GETTER(Handle<SharedFunctionInfo>, shared_info) | |
62 | |
63 #undef PARSE_INFO_GETTER | |
64 #undef PARSE_INFO_GETTER_WITH_DEFAULT | |
65 | 43 |
66 // A wrapper around a CompilationInfo that detaches the Handles from | 44 // A wrapper around a CompilationInfo that detaches the Handles from |
67 // the underlying DeferredHandleScope and stores them in info_ on | 45 // the underlying DeferredHandleScope and stores them in info_ on |
68 // destruction. | 46 // destruction. |
69 class CompilationHandleScope final { | 47 class CompilationHandleScope final { |
70 public: | 48 public: |
71 explicit CompilationHandleScope(CompilationInfo* info) | 49 explicit CompilationHandleScope(CompilationInfo* info) |
72 : deferred_(info->isolate()), info_(info) {} | 50 : deferred_(info->isolate()), info_(info) {} |
73 ~CompilationHandleScope() { info_->set_deferred_handles(deferred_.Detach()); } | 51 ~CompilationHandleScope() { info_->set_deferred_handles(deferred_.Detach()); } |
74 | 52 |
75 private: | 53 private: |
76 DeferredHandleScope deferred_; | 54 DeferredHandleScope deferred_; |
77 CompilationInfo* info_; | 55 CompilationInfo* info_; |
78 }; | 56 }; |
79 | 57 |
80 // Helper that times a scoped region and records the elapsed time. | 58 // Helper that times a scoped region and records the elapsed time. |
81 struct ScopedTimer { | 59 struct ScopedTimer { |
82 explicit ScopedTimer(base::TimeDelta* location) : location_(location) { | 60 explicit ScopedTimer(base::TimeDelta* location) : location_(location) { |
83 DCHECK(location_ != NULL); | 61 DCHECK(location_ != NULL); |
84 timer_.Start(); | 62 timer_.Start(); |
85 } | 63 } |
86 | 64 |
87 ~ScopedTimer() { *location_ += timer_.Elapsed(); } | 65 ~ScopedTimer() { *location_ += timer_.Elapsed(); } |
88 | 66 |
89 base::ElapsedTimer timer_; | 67 base::ElapsedTimer timer_; |
90 base::TimeDelta* location_; | 68 base::TimeDelta* location_; |
91 }; | 69 }; |
92 | 70 |
93 // ---------------------------------------------------------------------------- | 71 // ---------------------------------------------------------------------------- |
94 // Implementation of CompilationInfo | |
95 | |
96 bool CompilationInfo::has_shared_info() const { | |
97 return parse_info_ && !parse_info_->shared_info().is_null(); | |
98 } | |
99 | |
100 CompilationInfo::CompilationInfo(ParseInfo* parse_info, | |
101 Handle<JSFunction> closure) | |
102 : CompilationInfo(parse_info, {}, Code::ComputeFlags(Code::FUNCTION), BASE, | |
103 parse_info->isolate(), parse_info->zone()) { | |
104 closure_ = closure; | |
105 | |
106 // Compiling for the snapshot typically results in different code than | |
107 // compiling later on. This means that code recompiled with deoptimization | |
108 // support won't be "equivalent" (as defined by SharedFunctionInfo:: | |
109 // EnableDeoptimizationSupport), so it will replace the old code and all | |
110 // its type feedback. To avoid this, always compile functions in the snapshot | |
111 // with deoptimization support. | |
112 if (isolate_->serializer_enabled()) EnableDeoptimizationSupport(); | |
113 | |
114 if (FLAG_function_context_specialization) MarkAsFunctionContextSpecializing(); | |
115 if (FLAG_turbo_inlining) MarkAsInliningEnabled(); | |
116 if (FLAG_turbo_source_positions) MarkAsSourcePositionsEnabled(); | |
117 if (FLAG_turbo_splitting) MarkAsSplittingEnabled(); | |
118 } | |
119 | |
120 CompilationInfo::CompilationInfo(Vector<const char> debug_name, | |
121 Isolate* isolate, Zone* zone, | |
122 Code::Flags code_flags) | |
123 : CompilationInfo(nullptr, debug_name, code_flags, STUB, isolate, zone) {} | |
124 | |
125 CompilationInfo::CompilationInfo(ParseInfo* parse_info, | |
126 Vector<const char> debug_name, | |
127 Code::Flags code_flags, Mode mode, | |
128 Isolate* isolate, Zone* zone) | |
129 : parse_info_(parse_info), | |
130 isolate_(isolate), | |
131 flags_(0), | |
132 code_flags_(code_flags), | |
133 mode_(mode), | |
134 osr_ast_id_(BailoutId::None()), | |
135 zone_(zone), | |
136 deferred_handles_(nullptr), | |
137 dependencies_(isolate, zone), | |
138 bailout_reason_(kNoReason), | |
139 prologue_offset_(Code::kPrologueOffsetNotSet), | |
140 track_positions_(FLAG_hydrogen_track_positions || | |
141 isolate->is_profiling()), | |
142 parameter_count_(0), | |
143 optimization_id_(-1), | |
144 osr_expr_stack_height_(0), | |
145 debug_name_(debug_name) {} | |
146 | |
147 CompilationInfo::~CompilationInfo() { | |
148 if (GetFlag(kDisableFutureOptimization) && has_shared_info()) { | |
149 shared_info()->DisableOptimization(bailout_reason()); | |
150 } | |
151 dependencies()->Rollback(); | |
152 delete deferred_handles_; | |
153 } | |
154 | |
155 | |
156 int CompilationInfo::num_parameters() const { | |
157 return !IsStub() ? scope()->num_parameters() : parameter_count_; | |
158 } | |
159 | |
160 | |
161 int CompilationInfo::num_parameters_including_this() const { | |
162 return num_parameters() + (is_this_defined() ? 1 : 0); | |
163 } | |
164 | |
165 | |
166 bool CompilationInfo::is_this_defined() const { return !IsStub(); } | |
167 | |
168 | |
169 // Primitive functions are unlikely to be picked up by the stack-walking | |
170 // profiler, so they trigger their own optimization when they're called | |
171 // for the SharedFunctionInfo::kCallsUntilPrimitiveOptimization-th time. | |
172 bool CompilationInfo::ShouldSelfOptimize() { | |
173 return FLAG_crankshaft && | |
174 !(literal()->flags() & AstProperties::kDontSelfOptimize) && | |
175 !literal()->dont_optimize() && | |
176 literal()->scope()->AllowsLazyCompilation() && | |
177 !shared_info()->optimization_disabled(); | |
178 } | |
179 | |
180 void CompilationInfo::ReopenHandlesInNewHandleScope() { | |
181 closure_ = Handle<JSFunction>(*closure_); | |
182 } | |
183 | |
184 bool CompilationInfo::has_simple_parameters() { | |
185 return scope()->has_simple_parameters(); | |
186 } | |
187 | |
188 std::unique_ptr<char[]> CompilationInfo::GetDebugName() const { | |
189 if (parse_info() && parse_info()->literal()) { | |
190 AllowHandleDereference allow_deref; | |
191 return parse_info()->literal()->debug_name()->ToCString(); | |
192 } | |
193 if (parse_info() && !parse_info()->shared_info().is_null()) { | |
194 return parse_info()->shared_info()->DebugName()->ToCString(); | |
195 } | |
196 Vector<const char> name_vec = debug_name_; | |
197 if (name_vec.is_empty()) name_vec = ArrayVector("unknown"); | |
198 std::unique_ptr<char[]> name(new char[name_vec.length() + 1]); | |
199 memcpy(name.get(), name_vec.start(), name_vec.length()); | |
200 name[name_vec.length()] = '\0'; | |
201 return name; | |
202 } | |
203 | |
204 StackFrame::Type CompilationInfo::GetOutputStackFrameType() const { | |
205 switch (output_code_kind()) { | |
206 case Code::STUB: | |
207 case Code::BYTECODE_HANDLER: | |
208 case Code::HANDLER: | |
209 case Code::BUILTIN: | |
210 #define CASE_KIND(kind) case Code::kind: | |
211 IC_KIND_LIST(CASE_KIND) | |
212 #undef CASE_KIND | |
213 return StackFrame::STUB; | |
214 case Code::WASM_FUNCTION: | |
215 return StackFrame::WASM; | |
216 case Code::JS_TO_WASM_FUNCTION: | |
217 return StackFrame::JS_TO_WASM; | |
218 case Code::WASM_TO_JS_FUNCTION: | |
219 return StackFrame::WASM_TO_JS; | |
220 default: | |
221 UNIMPLEMENTED(); | |
222 return StackFrame::NONE; | |
223 } | |
224 } | |
225 | |
226 int CompilationInfo::GetDeclareGlobalsFlags() const { | |
227 DCHECK(DeclareGlobalsLanguageMode::is_valid(parse_info()->language_mode())); | |
228 return DeclareGlobalsEvalFlag::encode(parse_info()->is_eval()) | | |
229 DeclareGlobalsNativeFlag::encode(parse_info()->is_native()) | | |
230 DeclareGlobalsLanguageMode::encode(parse_info()->language_mode()); | |
231 } | |
232 | |
233 SourcePositionTableBuilder::RecordingMode | |
234 CompilationInfo::SourcePositionRecordingMode() const { | |
235 return parse_info() && parse_info()->is_native() | |
236 ? SourcePositionTableBuilder::OMIT_SOURCE_POSITIONS | |
237 : SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS; | |
238 } | |
239 | |
240 bool CompilationInfo::ExpectsJSReceiverAsReceiver() { | |
241 return is_sloppy(parse_info()->language_mode()) && !parse_info()->is_native(); | |
242 } | |
243 | |
244 bool CompilationInfo::has_native_context() const { | |
245 return !closure().is_null() && (closure()->native_context() != nullptr); | |
246 } | |
247 | |
248 Context* CompilationInfo::native_context() const { | |
249 return has_native_context() ? closure()->native_context() : nullptr; | |
250 } | |
251 | |
252 bool CompilationInfo::has_global_object() const { return has_native_context(); } | |
253 | |
254 JSGlobalObject* CompilationInfo::global_object() const { | |
255 return has_global_object() ? native_context()->global_object() : nullptr; | |
256 } | |
257 | |
258 void CompilationInfo::AddInlinedFunction( | |
259 Handle<SharedFunctionInfo> inlined_function) { | |
260 inlined_functions_.push_back(InlinedFunctionHolder( | |
261 inlined_function, handle(inlined_function->code()))); | |
262 } | |
263 | |
264 Code::Kind CompilationInfo::output_code_kind() const { | |
265 return Code::ExtractKindFromFlags(code_flags_); | |
266 } | |
267 | |
268 // ---------------------------------------------------------------------------- | |
269 // Implementation of CompilationJob | 72 // Implementation of CompilationJob |
270 | 73 |
271 CompilationJob::Status CompilationJob::PrepareJob() { | 74 CompilationJob::Status CompilationJob::PrepareJob() { |
272 DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id())); | 75 DCHECK(ThreadId::Current().Equals(info()->isolate()->thread_id())); |
273 DisallowJavascriptExecution no_js(isolate()); | 76 DisallowJavascriptExecution no_js(isolate()); |
274 | 77 |
275 if (FLAG_trace_opt && info()->IsOptimizing()) { | 78 if (FLAG_trace_opt && info()->IsOptimizing()) { |
276 OFStream os(stdout); | 79 OFStream os(stdout); |
277 os << "[compiling method " << Brief(*info()->closure()) << " using " | 80 os << "[compiling method " << Brief(*info()->closure()) << " using " |
278 << compiler_name_; | 81 << compiler_name_; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
311 DisallowCodeDependencyChange no_dependency_change; | 114 DisallowCodeDependencyChange no_dependency_change; |
312 DisallowJavascriptExecution no_js(isolate()); | 115 DisallowJavascriptExecution no_js(isolate()); |
313 DCHECK(!info()->dependencies()->HasAborted()); | 116 DCHECK(!info()->dependencies()->HasAborted()); |
314 | 117 |
315 // Delegate to the underlying implementation. | 118 // Delegate to the underlying implementation. |
316 DCHECK(state() == State::kReadyToFinalize); | 119 DCHECK(state() == State::kReadyToFinalize); |
317 ScopedTimer t(&time_taken_to_finalize_); | 120 ScopedTimer t(&time_taken_to_finalize_); |
318 return UpdateState(FinalizeJobImpl(), State::kSucceeded); | 121 return UpdateState(FinalizeJobImpl(), State::kSucceeded); |
319 } | 122 } |
320 | 123 |
| 124 CompilationJob::Status CompilationJob::RetryOptimization(BailoutReason reason) { |
| 125 DCHECK(info_->IsOptimizing()); |
| 126 info_->RetryOptimization(reason); |
| 127 state_ = State::kFailed; |
| 128 return FAILED; |
| 129 } |
| 130 |
| 131 CompilationJob::Status CompilationJob::AbortOptimization(BailoutReason reason) { |
| 132 DCHECK(info_->IsOptimizing()); |
| 133 info_->AbortOptimization(reason); |
| 134 state_ = State::kFailed; |
| 135 return FAILED; |
| 136 } |
| 137 |
321 void CompilationJob::RecordUnoptimizedCompilationStats() const { | 138 void CompilationJob::RecordUnoptimizedCompilationStats() const { |
322 int code_size; | 139 int code_size; |
323 if (info()->has_bytecode_array()) { | 140 if (info()->has_bytecode_array()) { |
324 code_size = info()->bytecode_array()->SizeIncludingMetadata(); | 141 code_size = info()->bytecode_array()->SizeIncludingMetadata(); |
325 } else { | 142 } else { |
326 code_size = info()->code()->SizeIncludingMetadata(); | 143 code_size = info()->code()->SizeIncludingMetadata(); |
327 } | 144 } |
328 | 145 |
329 Counters* counters = isolate()->counters(); | 146 Counters* counters = isolate()->counters(); |
330 // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually. | 147 // TODO(4280): Rename counters from "baseline" to "unoptimized" eventually. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", | 179 PrintF("Compiled: %d functions with %d byte source size in %fms.\n", |
363 compiled_functions, code_size, compilation_time); | 180 compiled_functions, code_size, compilation_time); |
364 } | 181 } |
365 if (FLAG_hydrogen_stats) { | 182 if (FLAG_hydrogen_stats) { |
366 isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_prepare_, | 183 isolate()->GetHStatistics()->IncrementSubtotals(time_taken_to_prepare_, |
367 time_taken_to_execute_, | 184 time_taken_to_execute_, |
368 time_taken_to_finalize_); | 185 time_taken_to_finalize_); |
369 } | 186 } |
370 } | 187 } |
371 | 188 |
| 189 Isolate* CompilationJob::isolate() const { return info()->isolate(); } |
| 190 |
372 namespace { | 191 namespace { |
373 | 192 |
374 void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object, | 193 void AddWeakObjectToCodeDependency(Isolate* isolate, Handle<HeapObject> object, |
375 Handle<Code> code) { | 194 Handle<Code> code) { |
376 Handle<WeakCell> cell = Code::WeakCellFor(code); | 195 Handle<WeakCell> cell = Code::WeakCellFor(code); |
377 Heap* heap = isolate->heap(); | 196 Heap* heap = isolate->heap(); |
378 if (heap->InNewSpace(*object)) { | 197 if (heap->InNewSpace(*object)) { |
379 heap->AddWeakNewSpaceObjectToCodeDependency(object, cell); | 198 heap->AddWeakNewSpaceObjectToCodeDependency(object, cell); |
380 } else { | 199 } else { |
381 Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object)); | 200 Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(object)); |
(...skipping 1693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2075 DCHECK(shared->is_compiled()); | 1894 DCHECK(shared->is_compiled()); |
2076 function->set_literals(cached.literals); | 1895 function->set_literals(cached.literals); |
2077 } else if (shared->is_compiled()) { | 1896 } else if (shared->is_compiled()) { |
2078 // TODO(mvstanton): pass pretenure flag to EnsureLiterals. | 1897 // TODO(mvstanton): pass pretenure flag to EnsureLiterals. |
2079 JSFunction::EnsureLiterals(function); | 1898 JSFunction::EnsureLiterals(function); |
2080 } | 1899 } |
2081 } | 1900 } |
2082 | 1901 |
2083 } // namespace internal | 1902 } // namespace internal |
2084 } // namespace v8 | 1903 } // namespace v8 |
OLD | NEW |