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.
5 #ifndef V8_DEOPTIMIZER_H_
6 #define V8_DEOPTIMIZER_H_
10 #include "src/allocation.h"
11 #include "src/macro-assembler.h"
17 class FrameDescription;
18 class TranslationIterator;
19 class DeoptimizedFrameInfo;
20 class TranslatedState;
23 class TranslatedValue {
25 // Allocation-less getter of the value.
26 // Returns heap()->arguments_marker() if allocation would be
27 // necessary to get the value.
28 Object* GetRawValue() const;
29 Handle<Object> GetValue();
31 bool IsMaterializedObject() const;
34 friend class TranslatedState;
35 friend class TranslatedFrame;
44 kCapturedObject, // Object captured by the escape analysis.
45 // The number of nested objects can be obtained
46 // with the DeferredObjectLength() method
47 // (the values of the nested objects follow
48 // this value in the depth-first order.)
49 kDuplicatedObject, // Duplicated object of a deferred object.
50 kArgumentsObject // Arguments object - only used to keep indexing
51 // in sync, it should not be materialized.
54 TranslatedValue(TranslatedState* container, Kind kind)
55 : kind_(kind), container_(container) {}
56 Kind kind() const { return kind_; }
58 int GetChildrenCount() const;
60 static TranslatedValue NewArgumentsObject(TranslatedState* container,
61 int length, int object_index);
62 static TranslatedValue NewDeferredObject(TranslatedState* container,
63 int length, int object_index);
64 static TranslatedValue NewDuplicateObject(TranslatedState* container, int id);
65 static TranslatedValue NewDouble(TranslatedState* container, double value);
66 static TranslatedValue NewInt32(TranslatedState* container, int32_t value);
67 static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value);
68 static TranslatedValue NewBool(TranslatedState* container, uint32_t value);
69 static TranslatedValue NewTagged(TranslatedState* container, Object* literal);
70 static TranslatedValue NewInvalid(TranslatedState* container);
72 Isolate* isolate() const;
73 void MaterializeSimple();
76 TranslatedState* container_; // This is only needed for materialization of
77 // objects and constructing handles (to get
80 MaybeHandle<Object> value_; // Before handlification, this is always null,
81 // after materialization it is never null,
82 // in between it is only null if the value needs
83 // to be materialized.
85 struct MaterializedObjectInfo {
87 int length_; // Applies only to kArgumentsObject or kCapturedObject kinds.
91 // kind kTagged. After handlification it is always nullptr.
93 // kind is kUInt32 or kBoolBit.
94 uint32_t uint32_value_;
99 // kind is kDuplicatedObject or kArgumentsObject or kCapturedObject.
100 MaterializedObjectInfo materialization_info_;
103 // Checked accessors for the union members.
104 Object* raw_literal() const;
105 int32_t int32_value() const;
106 uint32_t uint32_value() const;
107 double double_value() const;
108 int object_length() const;
109 int object_index() const;
113 class TranslatedFrame {
127 Kind kind() const { return kind_; }
128 BailoutId node_id() const { return node_id_; }
129 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
130 int height() const { return height_; }
134 iterator& operator++() {
135 AdvanceIterator(&position_);
139 iterator operator++(int) {
140 iterator original(position_);
141 AdvanceIterator(&position_);
145 bool operator==(const iterator& other) const {
146 return position_ == other.position_;
148 bool operator!=(const iterator& other) const { return !(*this == other); }
150 TranslatedValue& operator*() { return (*position_); }
151 TranslatedValue* operator->() { return &(*position_); }
154 friend TranslatedFrame;
156 explicit iterator(std::deque<TranslatedValue>::iterator position)
157 : position_(position) {}
159 std::deque<TranslatedValue>::iterator position_;
162 typedef TranslatedValue& reference;
163 typedef TranslatedValue const& const_reference;
165 iterator begin() { return iterator(values_.begin()); }
166 iterator end() { return iterator(values_.end()); }
168 reference front() { return values_.front(); }
169 const_reference front() const { return values_.front(); }
172 friend class TranslatedState;
174 // Constructor static methods.
175 static TranslatedFrame JSFrame(BailoutId node_id,
176 SharedFunctionInfo* shared_info, int height);
177 static TranslatedFrame AccessorFrame(Kind kind,
178 SharedFunctionInfo* shared_info);
179 static TranslatedFrame ArgumentsAdaptorFrame(SharedFunctionInfo* shared_info,
181 static TranslatedFrame ConstructStubFrame(SharedFunctionInfo* shared_info,
183 static TranslatedFrame CompiledStubFrame(int height, Isolate* isolate) {
184 return TranslatedFrame(kCompiledStub, isolate, nullptr, height);
186 static TranslatedFrame InvalidFrame() {
187 return TranslatedFrame(kInvalid, nullptr);
190 static void AdvanceIterator(std::deque<TranslatedValue>::iterator* iter);
192 TranslatedFrame(Kind kind, Isolate* isolate,
193 SharedFunctionInfo* shared_info = nullptr, int height = 0)
195 node_id_(BailoutId::None()),
196 raw_shared_info_(shared_info),
201 void Add(const TranslatedValue& value) { values_.push_back(value); }
206 SharedFunctionInfo* raw_shared_info_;
207 Handle<SharedFunctionInfo> shared_info_;
211 typedef std::deque<TranslatedValue> ValuesContainer;
213 ValuesContainer values_;
217 // Auxiliary class for translating deoptimization values.
218 // Typical usage sequence:
220 // 1. Construct the instance. This will involve reading out the translations
221 // and resolving them to values using the supplied frame pointer and
222 // machine state (registers). This phase is guaranteed not to allocate
223 // and not to use any HandleScope. Any object pointers will be stored raw.
225 // 2. Handlify pointers. This will convert all the raw pointers to handles.
227 // 3. Reading out the frame values.
229 // Note: After the instance is constructed, it is possible to iterate over
230 // the values eagerly.
232 class TranslatedState {
235 explicit TranslatedState(JavaScriptFrame* frame);
237 void Prepare(bool has_adapted_arguments, Address stack_frame_pointer);
239 // Store newly materialized values into the isolate.
240 void StoreMaterializedValuesAndDeopt();
242 typedef std::vector<TranslatedFrame>::iterator iterator;
243 iterator begin() { return frames_.begin(); }
244 iterator end() { return frames_.end(); }
246 typedef std::vector<TranslatedFrame>::const_iterator const_iterator;
247 const_iterator begin() const { return frames_.begin(); }
248 const_iterator end() const { return frames_.end(); }
250 std::vector<TranslatedFrame>& frames() { return frames_; }
252 TranslatedFrame* GetArgumentsInfoFromJSFrameIndex(int jsframe_index,
253 int* arguments_count);
255 Isolate* isolate() { return isolate_; }
257 void Init(Address input_frame_pointer, JSFunction* input_frame_function,
258 TranslationIterator* iterator, FixedArray* literal_array,
259 RegisterValues* registers, FILE* trace_file);
262 friend TranslatedValue;
264 TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator,
265 FixedArray* literal_array,
267 JSFunction* frame_function,
269 TranslatedValue CreateNextTranslatedValue(int frame_index, int value_index,
270 TranslationIterator* iterator,
271 FixedArray* literal_array,
273 RegisterValues* registers,
276 void UpdateFromPreviouslyMaterializedObjects();
277 Handle<Object> MaterializeAt(int frame_index, int* value_index);
278 Handle<Object> MaterializeObjectAt(int object_index);
279 bool GetAdaptedArguments(Handle<JSObject>* result, int frame_index);
281 static int SlotOffsetFp(int slot_index);
282 static Address SlotAddress(Address fp, int slot_index);
283 static uint32_t GetUInt32Slot(Address fp, int slot_index);
285 std::vector<TranslatedFrame> frames_;
287 Address stack_frame_pointer_;
288 bool has_adapted_arguments_;
290 struct ObjectPosition {
294 std::deque<ObjectPosition> object_positions_;
298 class OptimizedFunctionVisitor BASE_EMBEDDED {
300 virtual ~OptimizedFunctionVisitor() {}
302 // Function which is called before iteration of any optimized functions
303 // from given native context.
304 virtual void EnterContext(Context* context) = 0;
306 virtual void VisitFunction(JSFunction* function) = 0;
308 // Function which is called after iteration of all optimized functions
309 // from given native context.
310 virtual void LeaveContext(Context* context) = 0;
314 #define DEOPT_MESSAGES_LIST(V) \
315 V(kNoReason, "no reason") \
316 V(kConstantGlobalVariableAssignment, "Constant global variable assignment") \
317 V(kConversionOverflow, "conversion overflow") \
318 V(kDivisionByZero, "division by zero") \
319 V(kElementsKindUnhandledInKeyedLoadGenericStub, \
320 "ElementsKind unhandled in KeyedLoadGenericStub") \
321 V(kExpectedHeapNumber, "Expected heap number") \
322 V(kExpectedSmi, "Expected smi") \
323 V(kForcedDeoptToRuntime, "Forced deopt to runtime") \
325 V(kHoleyArrayDespitePackedElements_kindFeedback, \
326 "Holey array despite packed elements_kind feedback") \
327 V(kInstanceMigrationFailed, "instance migration failed") \
328 V(kInsufficientTypeFeedbackForCallWithArguments, \
329 "Insufficient type feedback for call with arguments") \
330 V(kInsufficientTypeFeedbackForCombinedTypeOfBinaryOperation, \
331 "Insufficient type feedback for combined type of binary operation") \
332 V(kInsufficientTypeFeedbackForGenericNamedAccess, \
333 "Insufficient type feedback for generic named access") \
334 V(kInsufficientTypeFeedbackForKeyedLoad, \
335 "Insufficient type feedback for keyed load") \
336 V(kInsufficientTypeFeedbackForKeyedStore, \
337 "Insufficient type feedback for keyed store") \
338 V(kInsufficientTypeFeedbackForLHSOfBinaryOperation, \
339 "Insufficient type feedback for LHS of binary operation") \
340 V(kInsufficientTypeFeedbackForRHSOfBinaryOperation, \
341 "Insufficient type feedback for RHS of binary operation") \
342 V(kKeyIsNegative, "key is negative") \
343 V(kLostPrecision, "lost precision") \
344 V(kLostPrecisionOrNaN, "lost precision or NaN") \
345 V(kMementoFound, "memento found") \
346 V(kMinusZero, "minus zero") \
348 V(kNegativeKeyEncountered, "Negative key encountered") \
349 V(kNegativeValue, "negative value") \
350 V(kNoCache, "no cache") \
351 V(kNonStrictElementsInKeyedLoadGenericStub, \
352 "non-strict elements in KeyedLoadGenericStub") \
353 V(kNotADateObject, "not a date object") \
354 V(kNotAHeapNumber, "not a heap number") \
355 V(kNotAHeapNumberUndefinedBoolean, "not a heap number/undefined/true/false") \
356 V(kNotAHeapNumberUndefined, "not a heap number/undefined") \
357 V(kNotAJavaScriptObject, "not a JavaScript object") \
358 V(kNotASmi, "not a Smi") \
360 V(kOutOfBounds, "out of bounds") \
361 V(kOutsideOfRange, "Outside of range") \
362 V(kOverflow, "overflow") \
363 V(kReceiverWasAGlobalObject, "receiver was a global object") \
365 V(kTooManyArguments, "too many arguments") \
366 V(kTooManyUndetectableTypes, "Too many undetectable types") \
367 V(kTracingElementsTransitions, "Tracing elements transitions") \
368 V(kTypeMismatchBetweenFeedbackAndConstant, \
369 "Type mismatch between feedback and constant") \
370 V(kUndefined, "undefined") \
371 V(kUnexpectedCellContentsInConstantGlobalStore, \
372 "Unexpected cell contents in constant global store") \
373 V(kUnexpectedCellContentsInGlobalStore, \
374 "Unexpected cell contents in global store") \
375 V(kUnexpectedObject, "unexpected object") \
376 V(kUnexpectedRHSOfBinaryOperation, "Unexpected RHS of binary operation") \
377 V(kUninitializedBoilerplateInFastClone, \
378 "Uninitialized boilerplate in fast clone") \
379 V(kUninitializedBoilerplateLiterals, "Uninitialized boilerplate literals") \
380 V(kUnknownMapInPolymorphicAccess, "Unknown map in polymorphic access") \
381 V(kUnknownMapInPolymorphicCall, "Unknown map in polymorphic call") \
382 V(kUnknownMapInPolymorphicElementAccess, \
383 "Unknown map in polymorphic element access") \
384 V(kUnknownMap, "Unknown map") \
385 V(kValueMismatch, "value mismatch") \
386 V(kWrongInstanceType, "wrong instance type") \
387 V(kWrongMap, "wrong map") \
388 V(kUndefinedOrNullInForIn, "null or undefined in for-in") \
389 V(kUndefinedOrNullInToObject, "null or undefined in ToObject")
392 class Deoptimizer : public Malloced {
398 // This last bailout type is not really a bailout, but used by the
399 // debugger to deoptimize stack frames to allow inspection.
401 kBailoutTypesWithCodeEntry = SOFT + 1
404 #define DEOPT_MESSAGES_CONSTANTS(C, T) C,
406 DEOPT_MESSAGES_LIST(DEOPT_MESSAGES_CONSTANTS) kLastDeoptReason
408 #undef DEOPT_MESSAGES_CONSTANTS
409 static const char* GetDeoptReason(DeoptReason deopt_reason);
412 DeoptInfo(SourcePosition position, const char* m, DeoptReason d)
413 : position(position), mnemonic(m), deopt_reason(d), inlining_id(0) {}
415 SourcePosition position;
416 const char* mnemonic;
417 DeoptReason deopt_reason;
421 static DeoptInfo GetDeoptInfo(Code* code, byte* from);
423 struct JumpTableEntry : public ZoneObject {
424 inline JumpTableEntry(Address entry, const DeoptInfo& deopt_info,
425 Deoptimizer::BailoutType type, bool frame)
428 deopt_info(deopt_info),
430 needs_frame(frame) {}
432 bool IsEquivalentTo(const JumpTableEntry& other) const {
433 return address == other.address && bailout_type == other.bailout_type &&
434 needs_frame == other.needs_frame;
439 DeoptInfo deopt_info;
440 Deoptimizer::BailoutType bailout_type;
444 static bool TraceEnabledFor(BailoutType deopt_type,
445 StackFrame::Type frame_type);
446 static const char* MessageFor(BailoutType type);
448 int output_count() const { return output_count_; }
450 Handle<JSFunction> function() const { return Handle<JSFunction>(function_); }
451 Handle<Code> compiled_code() const { return Handle<Code>(compiled_code_); }
452 BailoutType bailout_type() const { return bailout_type_; }
454 // Number of created JS frames. Not all created frames are necessarily JS.
455 int jsframe_count() const { return jsframe_count_; }
457 static Deoptimizer* New(JSFunction* function,
463 static Deoptimizer* Grab(Isolate* isolate);
465 // The returned object with information on the optimized frame needs to be
466 // freed before another one can be generated.
467 static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
470 static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
473 // Makes sure that there is enough room in the relocation
474 // information of a code object to perform lazy deoptimization
475 // patching. If there is not enough room a new relocation
476 // information object is allocated and comments are added until it
478 static void EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code);
480 // Deoptimize the function now. Its current optimized code will never be run
481 // again and any activations of the optimized code will get deoptimized when
482 // execution returns.
483 static void DeoptimizeFunction(JSFunction* function);
485 // Deoptimize all code in the given isolate.
486 static void DeoptimizeAll(Isolate* isolate);
488 // Deoptimizes all optimized code that has been previously marked
489 // (via code->set_marked_for_deoptimization) and unlinks all functions that
490 // refer to that code.
491 static void DeoptimizeMarkedCode(Isolate* isolate);
493 // Visit all the known optimized functions in a given isolate.
494 static void VisitAllOptimizedFunctions(
495 Isolate* isolate, OptimizedFunctionVisitor* visitor);
497 // The size in bytes of the code required at a lazy deopt patch site.
498 static int patch_size();
502 void MaterializeHeapObjects(JavaScriptFrameIterator* it);
504 void MaterializeHeapNumbersForDebuggerInspectableFrame(
505 int frame_index, int parameter_count, int expression_count,
506 DeoptimizedFrameInfo* info);
508 static void ComputeOutputFrames(Deoptimizer* deoptimizer);
512 CALCULATE_ENTRY_ADDRESS,
517 static Address GetDeoptimizationEntry(
521 GetEntryMode mode = ENSURE_ENTRY_CODE);
522 static int GetDeoptimizationId(Isolate* isolate,
525 static int GetOutputInfo(DeoptimizationOutputData* data,
527 SharedFunctionInfo* shared);
529 // Code generation support.
530 static int input_offset() { return OFFSET_OF(Deoptimizer, input_); }
531 static int output_count_offset() {
532 return OFFSET_OF(Deoptimizer, output_count_);
534 static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
536 static int has_alignment_padding_offset() {
537 return OFFSET_OF(Deoptimizer, has_alignment_padding_);
540 static int GetDeoptimizedCodeCount(Isolate* isolate);
542 static const int kNotDeoptimizationEntry = -1;
544 // Generators for the deoptimization entry code.
545 class TableEntryGenerator BASE_EMBEDDED {
547 TableEntryGenerator(MacroAssembler* masm, BailoutType type, int count)
548 : masm_(masm), type_(type), count_(count) {}
553 MacroAssembler* masm() const { return masm_; }
554 BailoutType type() const { return type_; }
555 Isolate* isolate() const { return masm_->isolate(); }
557 void GeneratePrologue();
560 int count() const { return count_; }
562 MacroAssembler* masm_;
563 Deoptimizer::BailoutType type_;
567 int ConvertJSFrameIndexToFrameIndex(int jsframe_index);
569 static size_t GetMaxDeoptTableSize();
571 static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
575 Isolate* isolate() const { return isolate_; }
578 static const int kMinNumberOfEntries = 64;
579 static const int kMaxNumberOfEntries = 16384;
581 Deoptimizer(Isolate* isolate,
582 JSFunction* function,
587 Code* optimized_code);
588 Code* FindOptimizedCode(JSFunction* function, Code* optimized_code);
589 void PrintFunctionName();
590 void DeleteFrameDescriptions();
592 void DoComputeOutputFrames();
593 void DoComputeJSFrame(TranslationIterator* iterator, int frame_index);
594 void DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
596 void DoComputeConstructStubFrame(TranslationIterator* iterator,
598 void DoComputeAccessorStubFrame(TranslationIterator* iterator,
600 bool is_setter_stub_frame);
601 void DoComputeCompiledStubFrame(TranslationIterator* iterator,
604 void WriteTranslatedValueToOutput(
605 TranslatedFrame::iterator* iterator, int* input_index, int frame_index,
606 unsigned output_offset, const char* debug_hint_string = nullptr,
607 Address output_address_for_materialization = nullptr);
608 void WriteValueToOutput(Object* value, int input_index, int frame_index,
609 unsigned output_offset,
610 const char* debug_hint_string);
611 void DebugPrintOutputSlot(intptr_t value, int frame_index,
612 unsigned output_offset,
613 const char* debug_hint_string);
615 unsigned ComputeInputFrameSize() const;
616 unsigned ComputeFixedSize(JSFunction* function) const;
618 unsigned ComputeIncomingArgumentSize(JSFunction* function) const;
619 unsigned ComputeOutgoingArgumentSize() const;
621 Object* ComputeLiteral(int index) const;
623 static void GenerateDeoptimizationEntries(
624 MacroAssembler* masm, int count, BailoutType type);
626 // Marks all the code in the given context for deoptimization.
627 static void MarkAllCodeForContext(Context* native_context);
629 // Visit all the known optimized functions in a given context.
630 static void VisitAllOptimizedFunctionsForContext(
631 Context* context, OptimizedFunctionVisitor* visitor);
633 // Deoptimizes all code marked in the given context.
634 static void DeoptimizeMarkedCodeForContext(Context* native_context);
636 // Patch the given code so that it will deoptimize itself.
637 static void PatchCodeForDeoptimization(Isolate* isolate, Code* code);
639 // Searches the list of known deoptimizing code for a Code object
640 // containing the given address (which is supposedly faster than
641 // searching all code objects).
642 Code* FindDeoptimizingCode(Address addr);
644 // Fill the input from from a JavaScript frame. This is used when
645 // the debugger needs to inspect an optimized frame. For normal
646 // deoptimizations the input frame is filled in generated code.
647 void FillInputFrame(Address tos, JavaScriptFrame* frame);
649 // Fill the given output frame's registers to contain the failure handler
650 // address and the number of parameters for a stub failure trampoline.
651 void SetPlatformCompiledStubRegisters(FrameDescription* output_frame,
652 CodeStubDescriptor* desc);
654 // Fill the given output frame's double registers with the original values
655 // from the input frame's double registers.
656 void CopyDoubleRegisters(FrameDescription* output_frame);
658 // Determines whether the input frame contains alignment padding by looking
659 // at the dynamic alignment state slot inside the frame.
660 bool HasAlignmentPadding(JSFunction* function);
663 JSFunction* function_;
664 Code* compiled_code_;
665 unsigned bailout_id_;
666 BailoutType bailout_type_;
669 int has_alignment_padding_;
671 // Input frame description.
672 FrameDescription* input_;
673 // Number of output frames.
675 // Number of output js frames.
677 // Array of output frame descriptions.
678 FrameDescription** output_;
680 // Key for lookup of previously materialized objects
683 TranslatedState translated_state_;
684 struct ValueToMaterialize {
685 Address output_slot_address_;
686 TranslatedFrame::iterator value_;
688 std::vector<ValueToMaterialize> values_to_materialize_;
691 DisallowHeapAllocation* disallow_heap_allocation_;
694 CodeTracer::Scope* trace_scope_;
696 static const int table_entry_size_;
698 friend class FrameDescription;
699 friend class DeoptimizedFrameInfo;
703 class RegisterValues {
705 intptr_t GetRegister(unsigned n) const {
707 // This convoluted DCHECK is needed to work around a gcc problem that
708 // improperly detects an array bounds overflow in optimized debug builds
709 // when using a plain DCHECK.
710 if (n >= arraysize(registers_)) {
715 return registers_[n];
718 double GetDoubleRegister(unsigned n) const {
719 DCHECK(n < arraysize(double_registers_));
720 return double_registers_[n];
723 void SetRegister(unsigned n, intptr_t value) {
724 DCHECK(n < arraysize(registers_));
725 registers_[n] = value;
728 void SetDoubleRegister(unsigned n, double value) {
729 DCHECK(n < arraysize(double_registers_));
730 double_registers_[n] = value;
733 intptr_t registers_[Register::kNumRegisters];
734 double double_registers_[DoubleRegister::kMaxNumRegisters];
738 class FrameDescription {
740 FrameDescription(uint32_t frame_size,
741 JSFunction* function);
743 void* operator new(size_t size, uint32_t frame_size) {
744 // Subtracts kPointerSize, as the member frame_content_ already supplies
745 // the first element of the area to store the frame.
746 return malloc(size + frame_size - kPointerSize);
749 // Bug in VS2015 RC, reported fixed in RTM. Microsoft bug: 1153909.
750 #if !defined(_MSC_FULL_VER) || _MSC_FULL_VER != 190022816
751 void operator delete(void* pointer, uint32_t frame_size) {
754 #endif // _MSC_FULL_VER
756 void operator delete(void* description) {
760 uint32_t GetFrameSize() const {
761 DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
762 return static_cast<uint32_t>(frame_size_);
765 JSFunction* GetFunction() const { return function_; }
767 unsigned GetOffsetFromSlotIndex(int slot_index);
769 intptr_t GetFrameSlot(unsigned offset) {
770 return *GetFrameSlotPointer(offset);
773 Address GetFramePointerAddress() {
774 int fp_offset = GetFrameSize() -
775 (ComputeParametersCount() + 1) * kPointerSize -
776 StandardFrameConstants::kCallerSPOffset;
777 return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset));
780 RegisterValues* GetRegisterValues() { return ®ister_values_; }
782 void SetFrameSlot(unsigned offset, intptr_t value) {
783 *GetFrameSlotPointer(offset) = value;
786 void SetCallerPc(unsigned offset, intptr_t value);
788 void SetCallerFp(unsigned offset, intptr_t value);
790 void SetCallerConstantPool(unsigned offset, intptr_t value);
792 intptr_t GetRegister(unsigned n) const {
793 return register_values_.GetRegister(n);
796 double GetDoubleRegister(unsigned n) const {
797 return register_values_.GetDoubleRegister(n);
800 void SetRegister(unsigned n, intptr_t value) {
801 register_values_.SetRegister(n, value);
804 void SetDoubleRegister(unsigned n, double value) {
805 register_values_.SetDoubleRegister(n, value);
808 intptr_t GetTop() const { return top_; }
809 void SetTop(intptr_t top) { top_ = top; }
811 intptr_t GetPc() const { return pc_; }
812 void SetPc(intptr_t pc) { pc_ = pc; }
814 intptr_t GetFp() const { return fp_; }
815 void SetFp(intptr_t fp) { fp_ = fp; }
817 intptr_t GetContext() const { return context_; }
818 void SetContext(intptr_t context) { context_ = context; }
820 intptr_t GetConstantPool() const { return constant_pool_; }
821 void SetConstantPool(intptr_t constant_pool) {
822 constant_pool_ = constant_pool;
825 Smi* GetState() const { return state_; }
826 void SetState(Smi* state) { state_ = state; }
828 void SetContinuation(intptr_t pc) { continuation_ = pc; }
830 StackFrame::Type GetFrameType() const { return type_; }
831 void SetFrameType(StackFrame::Type type) { type_ = type; }
833 // Get the incoming arguments count.
834 int ComputeParametersCount();
836 // Get a parameter value for an unoptimized frame.
837 Object* GetParameter(int index);
839 // Get the expression stack height for a unoptimized frame.
840 unsigned GetExpressionCount();
842 // Get the expression stack value for an unoptimized frame.
843 Object* GetExpression(int index);
845 static int registers_offset() {
846 return OFFSET_OF(FrameDescription, register_values_.registers_);
849 static int double_registers_offset() {
850 return OFFSET_OF(FrameDescription, register_values_.double_registers_);
853 static int frame_size_offset() {
854 return offsetof(FrameDescription, frame_size_);
857 static int pc_offset() { return offsetof(FrameDescription, pc_); }
859 static int state_offset() { return offsetof(FrameDescription, state_); }
861 static int continuation_offset() {
862 return offsetof(FrameDescription, continuation_);
865 static int frame_content_offset() {
866 return offsetof(FrameDescription, frame_content_);
870 static const uint32_t kZapUint32 = 0xbeeddead;
872 // Frame_size_ must hold a uint32_t value. It is only a uintptr_t to
873 // keep the variable-size array frame_content_ of type intptr_t at
874 // the end of the structure aligned.
875 uintptr_t frame_size_; // Number of bytes.
876 JSFunction* function_;
877 RegisterValues register_values_;
882 intptr_t constant_pool_;
883 StackFrame::Type type_;
886 // Continuation is the PC where the execution continues after
888 intptr_t continuation_;
890 // This must be at the end of the object as the object is allocated larger
891 // than it's definition indicate to extend this array.
892 intptr_t frame_content_[1];
894 intptr_t* GetFrameSlotPointer(unsigned offset) {
895 DCHECK(offset < frame_size_);
896 return reinterpret_cast<intptr_t*>(
897 reinterpret_cast<Address>(this) + frame_content_offset() + offset);
900 int ComputeFixedSize();
904 class DeoptimizerData {
906 explicit DeoptimizerData(MemoryAllocator* allocator);
909 void Iterate(ObjectVisitor* v);
912 MemoryAllocator* allocator_;
913 int deopt_entry_code_entries_[Deoptimizer::kBailoutTypesWithCodeEntry];
914 MemoryChunk* deopt_entry_code_[Deoptimizer::kBailoutTypesWithCodeEntry];
916 DeoptimizedFrameInfo* deoptimized_frame_info_;
918 Deoptimizer* current_;
920 friend class Deoptimizer;
922 DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
926 class TranslationBuffer BASE_EMBEDDED {
928 explicit TranslationBuffer(Zone* zone) : contents_(256, zone) { }
930 int CurrentIndex() const { return contents_.length(); }
931 void Add(int32_t value, Zone* zone);
933 Handle<ByteArray> CreateByteArray(Factory* factory);
936 ZoneList<uint8_t> contents_;
940 class TranslationIterator BASE_EMBEDDED {
942 TranslationIterator(ByteArray* buffer, int index)
943 : buffer_(buffer), index_(index) {
944 DCHECK(index >= 0 && index < buffer->length());
949 bool HasNext() const { return index_ < buffer_->length(); }
952 for (int i = 0; i < n; i++) Next();
961 #define TRANSLATION_OPCODE_LIST(V) \
964 V(CONSTRUCT_STUB_FRAME) \
965 V(GETTER_STUB_FRAME) \
966 V(SETTER_STUB_FRAME) \
967 V(ARGUMENTS_ADAPTOR_FRAME) \
968 V(COMPILED_STUB_FRAME) \
969 V(DUPLICATED_OBJECT) \
970 V(ARGUMENTS_OBJECT) \
978 V(INT32_STACK_SLOT) \
979 V(UINT32_STACK_SLOT) \
981 V(DOUBLE_STACK_SLOT) \
986 class Translation BASE_EMBEDDED {
988 #define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
990 TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
993 #undef DECLARE_TRANSLATION_OPCODE_ENUM
995 Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
998 index_(buffer->CurrentIndex()),
1000 buffer_->Add(BEGIN, zone);
1001 buffer_->Add(frame_count, zone);
1002 buffer_->Add(jsframe_count, zone);
1005 int index() const { return index_; }
1008 void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height);
1009 void BeginCompiledStubFrame(int height);
1010 void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
1011 void BeginConstructStubFrame(int literal_id, unsigned height);
1012 void BeginGetterStubFrame(int literal_id);
1013 void BeginSetterStubFrame(int literal_id);
1014 void BeginArgumentsObject(int args_length);
1015 void BeginCapturedObject(int length);
1016 void DuplicateObject(int object_index);
1017 void StoreRegister(Register reg);
1018 void StoreInt32Register(Register reg);
1019 void StoreUint32Register(Register reg);
1020 void StoreBoolRegister(Register reg);
1021 void StoreDoubleRegister(DoubleRegister reg);
1022 void StoreStackSlot(int index);
1023 void StoreInt32StackSlot(int index);
1024 void StoreUint32StackSlot(int index);
1025 void StoreBoolStackSlot(int index);
1026 void StoreDoubleStackSlot(int index);
1027 void StoreLiteral(int literal_id);
1028 void StoreArgumentsObject(bool args_known, int args_index, int args_length);
1029 void StoreJSFrameFunction();
1031 Zone* zone() const { return zone_; }
1033 static int NumberOfOperandsFor(Opcode opcode);
1035 #if defined(OBJECT_PRINT) || defined(ENABLE_DISASSEMBLER)
1036 static const char* StringFor(Opcode opcode);
1040 TranslationBuffer* buffer_;
1046 class MaterializedObjectStore {
1048 explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
1051 Handle<FixedArray> Get(Address fp);
1052 void Set(Address fp, Handle<FixedArray> materialized_objects);
1053 bool Remove(Address fp);
1056 Isolate* isolate() { return isolate_; }
1057 Handle<FixedArray> GetStackEntries();
1058 Handle<FixedArray> EnsureStackEntries(int size);
1060 int StackIdToIndex(Address fp);
1063 List<Address> frame_fps_;
1067 // Class used to represent an unoptimized frame when the debugger
1068 // needs to inspect a frame that is part of an optimized frame. The
1069 // internally used FrameDescription objects are not GC safe so for use
1070 // by the debugger frame information is copied to an object of this type.
1071 // Represents parameters in unadapted form so their number might mismatch
1072 // formal parameter count.
1073 class DeoptimizedFrameInfo : public Malloced {
1075 DeoptimizedFrameInfo(Deoptimizer* deoptimizer,
1077 bool has_arguments_adaptor,
1078 bool has_construct_stub);
1079 virtual ~DeoptimizedFrameInfo();
1082 void Iterate(ObjectVisitor* v);
1084 // Return the number of incoming arguments.
1085 int parameters_count() { return parameters_count_; }
1087 // Return the height of the expression stack.
1088 int expression_count() { return expression_count_; }
1090 // Get the frame function.
1091 JSFunction* GetFunction() {
1095 // Get the frame context.
1096 Object* GetContext() { return context_; }
1098 // Check if this frame is preceded by construct stub frame. The bottom-most
1099 // inlined frame might still be called by an uninlined construct stub.
1100 bool HasConstructStub() {
1101 return has_construct_stub_;
1104 // Get an incoming argument.
1105 Object* GetParameter(int index) {
1106 DCHECK(0 <= index && index < parameters_count());
1107 return parameters_[index];
1110 // Get an expression from the expression stack.
1111 Object* GetExpression(int index) {
1112 DCHECK(0 <= index && index < expression_count());
1113 return expression_stack_[index];
1116 int GetSourcePosition() {
1117 return source_position_;
1121 // Set an incoming argument.
1122 void SetParameter(int index, Object* obj) {
1123 DCHECK(0 <= index && index < parameters_count());
1124 parameters_[index] = obj;
1127 // Set an expression on the expression stack.
1128 void SetExpression(int index, Object* obj) {
1129 DCHECK(0 <= index && index < expression_count());
1130 expression_stack_[index] = obj;
1133 JSFunction* function_;
1135 bool has_construct_stub_;
1136 int parameters_count_;
1137 int expression_count_;
1138 Object** parameters_;
1139 Object** expression_stack_;
1140 int source_position_;
1142 friend class Deoptimizer;
1145 } // namespace internal
1148 #endif // V8_DEOPTIMIZER_H_