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 #ifndef V8_COMPILER_H_ | 5 #ifndef V8_COMPILER_H_ |
6 #define V8_COMPILER_H_ | 6 #define V8_COMPILER_H_ |
7 | 7 |
8 #include <memory> | 8 #include <memory> |
9 | 9 |
10 #include "src/allocation.h" | 10 #include "src/allocation.h" |
11 #include "src/bailout-reason.h" | 11 #include "src/bailout-reason.h" |
12 #include "src/compilation-dependencies.h" | |
13 #include "src/contexts.h" | 12 #include "src/contexts.h" |
14 #include "src/frames.h" | |
15 #include "src/isolate.h" | 13 #include "src/isolate.h" |
16 #include "src/source-position-table.h" | |
17 #include "src/source-position.h" | |
18 #include "src/zone.h" | 14 #include "src/zone.h" |
19 | 15 |
20 namespace v8 { | 16 namespace v8 { |
21 namespace internal { | 17 namespace internal { |
22 | 18 |
23 // Forward declarations. | 19 // Forward declarations. |
24 class CompilationInfo; | 20 class CompilationInfo; |
25 class CompilationJob; | 21 class CompilationJob; |
26 class JavaScriptFrame; | 22 class JavaScriptFrame; |
27 class ParseInfo; | 23 class ParseInfo; |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 // Please note this interface is the only part dealing with {Code} objects | 130 // Please note this interface is the only part dealing with {Code} objects |
135 // directly. Other methods are agnostic to {Code} and can use an interpreter | 131 // directly. Other methods are agnostic to {Code} and can use an interpreter |
136 // instead of generating JIT code for a function at all. | 132 // instead of generating JIT code for a function at all. |
137 | 133 |
138 // Generate and return optimized code for OSR, or empty handle on failure. | 134 // Generate and return optimized code for OSR, or empty handle on failure. |
139 MUST_USE_RESULT static MaybeHandle<Code> GetOptimizedCodeForOSR( | 135 MUST_USE_RESULT static MaybeHandle<Code> GetOptimizedCodeForOSR( |
140 Handle<JSFunction> function, BailoutId osr_ast_id, | 136 Handle<JSFunction> function, BailoutId osr_ast_id, |
141 JavaScriptFrame* osr_frame); | 137 JavaScriptFrame* osr_frame); |
142 }; | 138 }; |
143 | 139 |
144 | |
145 // CompilationInfo encapsulates some information known at compile time. It | |
146 // is constructed based on the resources available at compile-time. | |
147 class CompilationInfo final { | |
148 public: | |
149 // Various configuration flags for a compilation, as well as some properties | |
150 // of the compiled code produced by a compilation. | |
151 enum Flag { | |
152 kDeferredCalling = 1 << 0, | |
153 kNonDeferredCalling = 1 << 1, | |
154 kSavesCallerDoubles = 1 << 2, | |
155 kRequiresFrame = 1 << 3, | |
156 kMustNotHaveEagerFrame = 1 << 4, | |
157 kDeoptimizationSupport = 1 << 5, | |
158 kDebug = 1 << 6, | |
159 kSerializing = 1 << 7, | |
160 kFunctionContextSpecializing = 1 << 8, | |
161 kFrameSpecializing = 1 << 9, | |
162 kNativeContextSpecializing = 1 << 10, | |
163 kInliningEnabled = 1 << 11, | |
164 kDisableFutureOptimization = 1 << 12, | |
165 kSplittingEnabled = 1 << 13, | |
166 kDeoptimizationEnabled = 1 << 14, | |
167 kSourcePositionsEnabled = 1 << 15, | |
168 kBailoutOnUninitialized = 1 << 16, | |
169 kOptimizeFromBytecode = 1 << 17, | |
170 kTypeFeedbackEnabled = 1 << 18, | |
171 kAccessorInliningEnabled = 1 << 19, | |
172 }; | |
173 | |
174 CompilationInfo(ParseInfo* parse_info, Handle<JSFunction> closure); | |
175 CompilationInfo(Vector<const char> debug_name, Isolate* isolate, Zone* zone, | |
176 Code::Flags code_flags); | |
177 ~CompilationInfo(); | |
178 | |
179 ParseInfo* parse_info() const { return parse_info_; } | |
180 | |
181 // ----------------------------------------------------------- | |
182 // TODO(titzer): inline and delete accessors of ParseInfo | |
183 // ----------------------------------------------------------- | |
184 Handle<Script> script() const; | |
185 FunctionLiteral* literal() const; | |
186 DeclarationScope* scope() const; | |
187 Handle<Context> context() const; | |
188 Handle<SharedFunctionInfo> shared_info() const; | |
189 bool has_shared_info() const; | |
190 // ----------------------------------------------------------- | |
191 | |
192 Isolate* isolate() const { | |
193 return isolate_; | |
194 } | |
195 Zone* zone() { return zone_; } | |
196 bool is_osr() const { return !osr_ast_id_.IsNone(); } | |
197 Handle<JSFunction> closure() const { return closure_; } | |
198 Handle<Code> code() const { return code_; } | |
199 Code::Flags code_flags() const { return code_flags_; } | |
200 BailoutId osr_ast_id() const { return osr_ast_id_; } | |
201 JavaScriptFrame* osr_frame() const { return osr_frame_; } | |
202 int num_parameters() const; | |
203 int num_parameters_including_this() const; | |
204 bool is_this_defined() const; | |
205 | |
206 void set_parameter_count(int parameter_count) { | |
207 DCHECK(IsStub()); | |
208 parameter_count_ = parameter_count; | |
209 } | |
210 | |
211 bool has_bytecode_array() const { return !bytecode_array_.is_null(); } | |
212 Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; } | |
213 | |
214 bool is_tracking_positions() const { return track_positions_; } | |
215 | |
216 bool is_calling() const { | |
217 return GetFlag(kDeferredCalling) || GetFlag(kNonDeferredCalling); | |
218 } | |
219 | |
220 void MarkAsDeferredCalling() { SetFlag(kDeferredCalling); } | |
221 | |
222 bool is_deferred_calling() const { return GetFlag(kDeferredCalling); } | |
223 | |
224 void MarkAsNonDeferredCalling() { SetFlag(kNonDeferredCalling); } | |
225 | |
226 bool is_non_deferred_calling() const { return GetFlag(kNonDeferredCalling); } | |
227 | |
228 void MarkAsSavesCallerDoubles() { SetFlag(kSavesCallerDoubles); } | |
229 | |
230 bool saves_caller_doubles() const { return GetFlag(kSavesCallerDoubles); } | |
231 | |
232 void MarkAsRequiresFrame() { SetFlag(kRequiresFrame); } | |
233 | |
234 bool requires_frame() const { return GetFlag(kRequiresFrame); } | |
235 | |
236 void MarkMustNotHaveEagerFrame() { SetFlag(kMustNotHaveEagerFrame); } | |
237 | |
238 bool GetMustNotHaveEagerFrame() const { | |
239 return GetFlag(kMustNotHaveEagerFrame); | |
240 } | |
241 | |
242 // Compiles marked as debug produce unoptimized code with debug break slots. | |
243 // Inner functions that cannot be compiled w/o context are compiled eagerly. | |
244 // Always include deoptimization support to avoid having to recompile again. | |
245 void MarkAsDebug() { | |
246 SetFlag(kDebug); | |
247 SetFlag(kDeoptimizationSupport); | |
248 } | |
249 | |
250 bool is_debug() const { return GetFlag(kDebug); } | |
251 | |
252 void PrepareForSerializing() { SetFlag(kSerializing); } | |
253 | |
254 bool will_serialize() const { return GetFlag(kSerializing); } | |
255 | |
256 void MarkAsFunctionContextSpecializing() { | |
257 SetFlag(kFunctionContextSpecializing); | |
258 } | |
259 | |
260 bool is_function_context_specializing() const { | |
261 return GetFlag(kFunctionContextSpecializing); | |
262 } | |
263 | |
264 void MarkAsFrameSpecializing() { SetFlag(kFrameSpecializing); } | |
265 | |
266 bool is_frame_specializing() const { return GetFlag(kFrameSpecializing); } | |
267 | |
268 void MarkAsNativeContextSpecializing() { | |
269 SetFlag(kNativeContextSpecializing); | |
270 } | |
271 | |
272 bool is_native_context_specializing() const { | |
273 return GetFlag(kNativeContextSpecializing); | |
274 } | |
275 | |
276 void MarkAsDeoptimizationEnabled() { SetFlag(kDeoptimizationEnabled); } | |
277 | |
278 bool is_deoptimization_enabled() const { | |
279 return GetFlag(kDeoptimizationEnabled); | |
280 } | |
281 | |
282 void MarkAsTypeFeedbackEnabled() { SetFlag(kTypeFeedbackEnabled); } | |
283 | |
284 bool is_type_feedback_enabled() const { | |
285 return GetFlag(kTypeFeedbackEnabled); | |
286 } | |
287 | |
288 void MarkAsAccessorInliningEnabled() { SetFlag(kAccessorInliningEnabled); } | |
289 | |
290 bool is_accessor_inlining_enabled() const { | |
291 return GetFlag(kAccessorInliningEnabled); | |
292 } | |
293 | |
294 void MarkAsSourcePositionsEnabled() { SetFlag(kSourcePositionsEnabled); } | |
295 | |
296 bool is_source_positions_enabled() const { | |
297 return GetFlag(kSourcePositionsEnabled); | |
298 } | |
299 | |
300 void MarkAsInliningEnabled() { SetFlag(kInliningEnabled); } | |
301 | |
302 bool is_inlining_enabled() const { return GetFlag(kInliningEnabled); } | |
303 | |
304 void MarkAsSplittingEnabled() { SetFlag(kSplittingEnabled); } | |
305 | |
306 bool is_splitting_enabled() const { return GetFlag(kSplittingEnabled); } | |
307 | |
308 void MarkAsBailoutOnUninitialized() { SetFlag(kBailoutOnUninitialized); } | |
309 | |
310 bool is_bailout_on_uninitialized() const { | |
311 return GetFlag(kBailoutOnUninitialized); | |
312 } | |
313 | |
314 void MarkAsOptimizeFromBytecode() { SetFlag(kOptimizeFromBytecode); } | |
315 | |
316 bool is_optimizing_from_bytecode() const { | |
317 return GetFlag(kOptimizeFromBytecode); | |
318 } | |
319 | |
320 bool GeneratePreagedPrologue() const { | |
321 // Generate a pre-aged prologue if we are optimizing for size, which | |
322 // will make code flushing more aggressive. Only apply to Code::FUNCTION, | |
323 // since StaticMarkingVisitor::IsFlushable only flushes proper functions. | |
324 return FLAG_optimize_for_size && FLAG_age_code && !is_debug() && | |
325 output_code_kind() == Code::FUNCTION; | |
326 } | |
327 | |
328 void SetCode(Handle<Code> code) { code_ = code; } | |
329 | |
330 void SetBytecodeArray(Handle<BytecodeArray> bytecode_array) { | |
331 bytecode_array_ = bytecode_array; | |
332 } | |
333 | |
334 bool ShouldTrapOnDeopt() const { | |
335 return (FLAG_trap_on_deopt && IsOptimizing()) || | |
336 (FLAG_trap_on_stub_deopt && IsStub()); | |
337 } | |
338 | |
339 bool has_native_context() const; | |
340 Context* native_context() const; | |
341 | |
342 bool has_global_object() const; | |
343 JSGlobalObject* global_object() const; | |
344 | |
345 // Accessors for the different compilation modes. | |
346 bool IsOptimizing() const { return mode_ == OPTIMIZE; } | |
347 bool IsStub() const { return mode_ == STUB; } | |
348 void SetOptimizing() { | |
349 DCHECK(has_shared_info()); | |
350 SetMode(OPTIMIZE); | |
351 optimization_id_ = isolate()->NextOptimizationId(); | |
352 code_flags_ = | |
353 Code::KindField::update(code_flags_, Code::OPTIMIZED_FUNCTION); | |
354 } | |
355 void SetOptimizingForOsr(BailoutId osr_ast_id, JavaScriptFrame* osr_frame) { | |
356 SetOptimizing(); | |
357 osr_ast_id_ = osr_ast_id; | |
358 osr_frame_ = osr_frame; | |
359 } | |
360 | |
361 // Deoptimization support. | |
362 bool HasDeoptimizationSupport() const { | |
363 return GetFlag(kDeoptimizationSupport); | |
364 } | |
365 void EnableDeoptimizationSupport() { | |
366 DCHECK_EQ(BASE, mode_); | |
367 SetFlag(kDeoptimizationSupport); | |
368 } | |
369 bool ShouldEnsureSpaceForLazyDeopt() { return !IsStub(); } | |
370 | |
371 bool ExpectsJSReceiverAsReceiver(); | |
372 | |
373 // Determines whether or not to insert a self-optimization header. | |
374 bool ShouldSelfOptimize(); | |
375 | |
376 void set_deferred_handles(DeferredHandles* deferred_handles) { | |
377 DCHECK(deferred_handles_ == NULL); | |
378 deferred_handles_ = deferred_handles; | |
379 } | |
380 | |
381 void ReopenHandlesInNewHandleScope(); | |
382 | |
383 void AbortOptimization(BailoutReason reason) { | |
384 DCHECK(reason != kNoReason); | |
385 if (bailout_reason_ == kNoReason) bailout_reason_ = reason; | |
386 SetFlag(kDisableFutureOptimization); | |
387 } | |
388 | |
389 void RetryOptimization(BailoutReason reason) { | |
390 DCHECK(reason != kNoReason); | |
391 if (GetFlag(kDisableFutureOptimization)) return; | |
392 bailout_reason_ = reason; | |
393 } | |
394 | |
395 BailoutReason bailout_reason() const { return bailout_reason_; } | |
396 | |
397 int prologue_offset() const { | |
398 DCHECK_NE(Code::kPrologueOffsetNotSet, prologue_offset_); | |
399 return prologue_offset_; | |
400 } | |
401 | |
402 void set_prologue_offset(int prologue_offset) { | |
403 DCHECK_EQ(Code::kPrologueOffsetNotSet, prologue_offset_); | |
404 prologue_offset_ = prologue_offset; | |
405 } | |
406 | |
407 CompilationDependencies* dependencies() { return &dependencies_; } | |
408 | |
409 int optimization_id() const { return optimization_id_; } | |
410 | |
411 int osr_expr_stack_height() { return osr_expr_stack_height_; } | |
412 void set_osr_expr_stack_height(int height) { | |
413 DCHECK(height >= 0); | |
414 osr_expr_stack_height_ = height; | |
415 } | |
416 | |
417 bool has_simple_parameters(); | |
418 | |
419 struct InlinedFunctionHolder { | |
420 Handle<SharedFunctionInfo> shared_info; | |
421 | |
422 // Root that holds the unoptimized code of the inlined function alive | |
423 // (and out of reach of code flushing) until we finish compilation. | |
424 // Do not remove. | |
425 Handle<Code> inlined_code_object_root; | |
426 | |
427 InlinedFunctionHolder(Handle<SharedFunctionInfo> inlined_shared_info, | |
428 Handle<Code> inlined_code_object_root) | |
429 : shared_info(inlined_shared_info), | |
430 inlined_code_object_root(inlined_code_object_root) {} | |
431 }; | |
432 | |
433 typedef std::vector<InlinedFunctionHolder> InlinedFunctionList; | |
434 InlinedFunctionList const& inlined_functions() const { | |
435 return inlined_functions_; | |
436 } | |
437 | |
438 void AddInlinedFunction(Handle<SharedFunctionInfo> inlined_function); | |
439 | |
440 std::unique_ptr<char[]> GetDebugName() const; | |
441 | |
442 Code::Kind output_code_kind() const; | |
443 | |
444 StackFrame::Type GetOutputStackFrameType() const; | |
445 | |
446 int GetDeclareGlobalsFlags() const; | |
447 | |
448 SourcePositionTableBuilder::RecordingMode SourcePositionRecordingMode() const; | |
449 | |
450 private: | |
451 // Compilation mode. | |
452 // BASE is generated by the full codegen, optionally prepared for bailouts. | |
453 // OPTIMIZE is optimized code generated by the Hydrogen-based backend. | |
454 enum Mode { | |
455 BASE, | |
456 OPTIMIZE, | |
457 STUB | |
458 }; | |
459 | |
460 CompilationInfo(ParseInfo* parse_info, Vector<const char> debug_name, | |
461 Code::Flags code_flags, Mode mode, Isolate* isolate, | |
462 Zone* zone); | |
463 | |
464 ParseInfo* parse_info_; | |
465 Isolate* isolate_; | |
466 | |
467 void SetMode(Mode mode) { | |
468 mode_ = mode; | |
469 } | |
470 | |
471 void SetFlag(Flag flag) { flags_ |= flag; } | |
472 | |
473 void SetFlag(Flag flag, bool value) { | |
474 flags_ = value ? flags_ | flag : flags_ & ~flag; | |
475 } | |
476 | |
477 bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; } | |
478 | |
479 unsigned flags_; | |
480 | |
481 Code::Flags code_flags_; | |
482 | |
483 Handle<JSFunction> closure_; | |
484 | |
485 // The compiled code. | |
486 Handle<Code> code_; | |
487 | |
488 // Compilation mode flag and whether deoptimization is allowed. | |
489 Mode mode_; | |
490 BailoutId osr_ast_id_; | |
491 | |
492 // Holds the bytecode array generated by the interpreter. | |
493 // TODO(rmcilroy/mstarzinger): Temporary work-around until compiler.cc is | |
494 // refactored to avoid us needing to carry the BytcodeArray around. | |
495 Handle<BytecodeArray> bytecode_array_; | |
496 | |
497 // The zone from which the compilation pipeline working on this | |
498 // CompilationInfo allocates. | |
499 Zone* zone_; | |
500 | |
501 DeferredHandles* deferred_handles_; | |
502 | |
503 // Dependencies for this compilation, e.g. stable maps. | |
504 CompilationDependencies dependencies_; | |
505 | |
506 BailoutReason bailout_reason_; | |
507 | |
508 int prologue_offset_; | |
509 | |
510 bool track_positions_; | |
511 | |
512 InlinedFunctionList inlined_functions_; | |
513 | |
514 // Number of parameters used for compilation of stubs that require arguments. | |
515 int parameter_count_; | |
516 | |
517 int optimization_id_; | |
518 | |
519 int osr_expr_stack_height_; | |
520 | |
521 // The current OSR frame for specialization or {nullptr}. | |
522 JavaScriptFrame* osr_frame_ = nullptr; | |
523 | |
524 Vector<const char> debug_name_; | |
525 | |
526 DISALLOW_COPY_AND_ASSIGN(CompilationInfo); | |
527 }; | |
528 | |
529 // A base class for compilation jobs intended to run concurrent to the main | 140 // A base class for compilation jobs intended to run concurrent to the main |
530 // thread. The job is split into three phases which are called in sequence on | 141 // thread. The job is split into three phases which are called in sequence on |
531 // different threads and with different limitations: | 142 // different threads and with different limitations: |
532 // 1) PrepareJob: Runs on main thread. No major limitations. | 143 // 1) PrepareJob: Runs on main thread. No major limitations. |
533 // 2) ExecuteJob: Runs concurrently. No heap allocation or handle derefs. | 144 // 2) ExecuteJob: Runs concurrently. No heap allocation or handle derefs. |
534 // 3) FinalizeJob: Runs on main thread. No dependency changes. | 145 // 3) FinalizeJob: Runs on main thread. No dependency changes. |
535 // | 146 // |
536 // Each of the three phases can either fail or succeed. The current state of | 147 // Each of the three phases can either fail or succeed. The current state of |
537 // the job can be checked using {state()}. | 148 // the job can be checked using {state()}. |
538 class CompilationJob { | 149 class CompilationJob { |
(...skipping 21 matching lines...) Expand all Loading... |
560 | 171 |
561 // Executes the compile job. Can be called on a background thread if | 172 // Executes the compile job. Can be called on a background thread if |
562 // can_execute_on_background_thread() returns true. | 173 // can_execute_on_background_thread() returns true. |
563 MUST_USE_RESULT Status ExecuteJob(); | 174 MUST_USE_RESULT Status ExecuteJob(); |
564 | 175 |
565 // Finalizes the compile job. Must be called on the main thread. | 176 // Finalizes the compile job. Must be called on the main thread. |
566 MUST_USE_RESULT Status FinalizeJob(); | 177 MUST_USE_RESULT Status FinalizeJob(); |
567 | 178 |
568 // Report a transient failure, try again next time. Should only be called on | 179 // Report a transient failure, try again next time. Should only be called on |
569 // optimization compilation jobs. | 180 // optimization compilation jobs. |
570 Status RetryOptimization(BailoutReason reason) { | 181 Status RetryOptimization(BailoutReason reason); |
571 DCHECK(info_->IsOptimizing()); | |
572 info_->RetryOptimization(reason); | |
573 state_ = State::kFailed; | |
574 return FAILED; | |
575 } | |
576 | 182 |
577 // Report a persistent failure, disable future optimization on the function. | 183 // Report a persistent failure, disable future optimization on the function. |
578 // Should only be called on optimization compilation jobs. | 184 // Should only be called on optimization compilation jobs. |
579 Status AbortOptimization(BailoutReason reason) { | 185 Status AbortOptimization(BailoutReason reason); |
580 DCHECK(info_->IsOptimizing()); | |
581 info_->AbortOptimization(reason); | |
582 state_ = State::kFailed; | |
583 return FAILED; | |
584 } | |
585 | 186 |
586 void RecordOptimizedCompilationStats() const; | 187 void RecordOptimizedCompilationStats() const; |
587 void RecordUnoptimizedCompilationStats() const; | 188 void RecordUnoptimizedCompilationStats() const; |
588 | 189 |
589 virtual bool can_execute_on_background_thread() const { return true; } | 190 virtual bool can_execute_on_background_thread() const { return true; } |
590 | 191 |
591 void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } | 192 void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } |
592 uintptr_t stack_limit() const { return stack_limit_; } | 193 uintptr_t stack_limit() const { return stack_limit_; } |
593 | 194 |
594 State state() const { return state_; } | 195 State state() const { return state_; } |
595 CompilationInfo* info() const { return info_; } | 196 CompilationInfo* info() const { return info_; } |
596 Isolate* isolate() const { return info()->isolate(); } | 197 Isolate* isolate() const; |
597 | 198 |
598 protected: | 199 protected: |
599 // Overridden by the actual implementation. | 200 // Overridden by the actual implementation. |
600 virtual Status PrepareJobImpl() = 0; | 201 virtual Status PrepareJobImpl() = 0; |
601 virtual Status ExecuteJobImpl() = 0; | 202 virtual Status ExecuteJobImpl() = 0; |
602 virtual Status FinalizeJobImpl() = 0; | 203 virtual Status FinalizeJobImpl() = 0; |
603 | 204 |
604 // Registers weak object to optimized code dependencies. | 205 // Registers weak object to optimized code dependencies. |
605 // TODO(turbofan): Move this to pipeline.cc once Crankshaft dies. | 206 // TODO(turbofan): Move this to pipeline.cc once Crankshaft dies. |
606 void RegisterWeakObjectsInOptimizedCode(Handle<Code> code); | 207 void RegisterWeakObjectsInOptimizedCode(Handle<Code> code); |
(...skipping 14 matching lines...) Expand all Loading... |
621 state_ = State::kFailed; | 222 state_ = State::kFailed; |
622 } | 223 } |
623 return status; | 224 return status; |
624 } | 225 } |
625 }; | 226 }; |
626 | 227 |
627 } // namespace internal | 228 } // namespace internal |
628 } // namespace v8 | 229 } // namespace v8 |
629 | 230 |
630 #endif // V8_COMPILER_H_ | 231 #endif // V8_COMPILER_H_ |
OLD | NEW |