Index: src/deoptimizer.h |
diff --git a/src/deoptimizer.h b/src/deoptimizer.h |
index d16e0558d95878b64b0530306ceb4c2c923eb529..e1fdb1690ebf12828529ddc2d0e42e3e67141920 100644 |
--- a/src/deoptimizer.h |
+++ b/src/deoptimizer.h |
@@ -14,17 +14,270 @@ |
namespace v8 { |
namespace internal { |
- |
-static inline double read_double_value(Address p) { |
- double d; |
- memcpy(&d, p, sizeof(d)); |
- return d; |
-} |
- |
- |
class FrameDescription; |
class TranslationIterator; |
class DeoptimizedFrameInfo; |
+class TranslatedState; |
+class RegisterValues; |
+ |
+class TranslatedValue BASE_EMBEDDED { |
+ public: |
+ // Allocation-less getter of the value. |
+ // Returns heap()->arguments_marker() if allocation would be |
+ // necessary to get the value. |
+ Object* GetRawValue() const; |
+ Handle<Object> GetValue(); |
+ |
+ bool IsMaterializedObject() const; |
+ |
+ private: |
+ friend class TranslatedState; |
+ friend class TranslatedFrame; |
+ |
+ enum Kind { |
+ kInvalid, |
+ kTagged, |
+ kInt32, |
+ kUInt32, |
+ kBoolBit, |
+ kDouble, |
+ kCapturedObject, // Object captured by the escape analysis. |
+ // The number of nested objects can be obtained |
+ // with the DeferredObjectLength() method |
+ // (the values of the nested objects follow |
+ // this value in the depth-first order.) |
+ kDuplicatedObject, // Duplicated object of a deferred object. |
+ kArgumentsObject // Arguments object - only used to keep indexing |
+ // in sync, it should not be materialized. |
+ }; |
+ |
+ TranslatedValue(TranslatedState* container, Kind kind) |
+ : kind_(kind), container_(container) {} |
+ Kind kind() const { return kind_; } |
+ void Handlify(); |
+ int GetChildrenCount() const; |
+ |
+ static TranslatedValue NewArgumentsObject(TranslatedState* container, |
+ int length, int object_index); |
+ static TranslatedValue NewDeferredObject(TranslatedState* container, |
+ int length, int object_index); |
+ static TranslatedValue NewDuplicateObject(TranslatedState* container, int id); |
+ static TranslatedValue NewDouble(TranslatedState* container, double value); |
+ static TranslatedValue NewInt32(TranslatedState* container, int32_t value); |
+ static TranslatedValue NewUInt32(TranslatedState* container, uint32_t value); |
+ static TranslatedValue NewBool(TranslatedState* container, uint32_t value); |
+ static TranslatedValue NewTagged(TranslatedState* container, Object* literal); |
+ static TranslatedValue NewInvalid(); |
+ |
+ Isolate* isolate() const; |
+ void MaterializeSimple(); |
+ |
+ Kind kind_; |
+ TranslatedState* container_; // This is only needed for materialization of |
+ // objects and constructing handles (to get |
+ // to the isolate). |
+ |
+ MaybeHandle<Object> value_; // Before handlification, this is always null, |
+ // after materialization it is never null, |
+ // in between it is only null if the value needs |
+ // to be materialized. |
+ |
+ struct MaterializedObjectInfo { |
+ int id_; |
+ int length_; // Applies only to kArgumentsObject or kCapturedObject kinds. |
+ }; |
+ |
+ union { |
+ // kind kTagged. After handlification it is always nullptr. |
+ Object* raw_literal_; |
+ // kind is kUInt32 or kBoolBit. |
+ uint32_t uint32_value_; |
+ // kind is kInt32. |
+ int32_t int32_value_; |
+ // kind is kDouble |
+ double double_value_; |
+ // kind is kDuplicatedObject or kArgumentsObject or kCapturedObject. |
+ MaterializedObjectInfo materialization_info_; |
+ }; |
+ |
+ // Checked accessors for the union members. |
+ Object* raw_literal() const; |
+ int32_t int32_value() const; |
+ uint32_t uint32_value() const; |
+ double double_value() const; |
+ int object_length() const; |
+ int object_index() const; |
+}; |
+ |
+ |
+class TranslatedFrame { |
+ public: |
+ enum Kind { |
+ kFunction, |
+ kGetter, |
+ kSetter, |
+ kArgumentsAdaptor, |
+ kConstructStub, |
+ kCompiledStub, |
+ kInvalid |
+ }; |
+ |
+ int GetValueCount(); |
+ |
+ Kind kind() const { return kind_; } |
+ BailoutId node_id() { return node_id_; } |
+ JSFunction* raw_function() { return raw_function_; } |
+ Handle<JSFunction> function() { return function_; } |
+ int height() { return height_; } |
+ |
+ class iterator { |
+ public: |
+ iterator& operator++() { |
+ AdvanceIterator(&position_); |
+ return *this; |
+ } |
+ |
+ iterator operator++(int) { |
+ iterator original(position_); |
+ AdvanceIterator(&position_); |
+ return original; |
+ } |
+ |
+ bool operator==(const iterator& other) const { |
+ return position_ == other.position_; |
+ } |
+ bool operator!=(const iterator& other) const { return !(*this == other); } |
+ |
+ TranslatedValue& operator*() { return (*position_); } |
+ TranslatedValue* operator->() { return &(*position_); } |
+ |
+ private: |
+ friend TranslatedFrame; |
+ |
+ explicit iterator(std::deque<TranslatedValue>::iterator position) |
+ : position_(position) {} |
+ |
+ std::deque<TranslatedValue>::iterator position_; |
+ }; |
+ |
+ iterator begin() { return iterator(values_.begin()); } |
+ iterator end() { return iterator(values_.end()); } |
+ |
+ private: |
+ friend class TranslatedState; |
+ |
+ // Constructor static methods. |
+ static TranslatedFrame JSFrame(BailoutId node_id, JSFunction* function, |
+ int height); |
+ static TranslatedFrame AccessorFrame(Kind kind, JSFunction* function); |
+ static TranslatedFrame ArgumentsAdaptorFrame(JSFunction* function, |
+ int height); |
+ static TranslatedFrame ConstructStubFrame(JSFunction* function, int height); |
+ static TranslatedFrame CompiledStubFrame(int height, Isolate* isolate) { |
+ return TranslatedFrame(kCompiledStub, isolate, nullptr, height); |
+ } |
+ static TranslatedFrame InvalidFrame() { |
+ return TranslatedFrame(kInvalid, nullptr); |
+ } |
+ |
+ static void AdvanceIterator(std::deque<TranslatedValue>::iterator* iter); |
+ |
+ TranslatedFrame(Kind kind, Isolate* isolate, JSFunction* function = nullptr, |
+ int height = 0) |
+ : kind_(kind), |
+ node_id_(BailoutId::None()), |
+ raw_function_(function), |
+ height_(height), |
+ isolate_(isolate) {} |
+ |
+ |
+ void Add(const TranslatedValue& value) { values_.push_back(value); } |
+ void Handlify(Isolate* isolate); |
+ |
+ Kind kind_; |
+ BailoutId node_id_; |
+ JSFunction* raw_function_; |
+ Handle<JSFunction> function_; |
+ int height_; |
+ Isolate* isolate_; |
+ |
+ typedef std::deque<TranslatedValue> ValuesContainer; |
+ |
+ ValuesContainer values_; |
+}; |
+ |
+ |
+// Auxiliary class for translating deoptimization values. |
+// Typical usage sequence: |
+// |
+// 1. Construct the instance. This will involve reading out the translations |
+// and resolving them to values using the supplied frame pointer and |
+// machine state (registers). This phase is guaranteed not to allocate |
+// and not to use any HandleScope. Any object pointers will be stored raw. |
+// |
+// 2. Handlify pointers. This will convert all the raw pointers to handles. |
+// |
+// 3. Reading out the frame values. |
+// |
+// Note: After the instance is constructed, it is possible to iterate over |
+// the values eagerly. |
+ |
+class TranslatedState { |
+ public: |
+ TranslatedState(); |
+ explicit TranslatedState(JavaScriptFrame* frame); |
+ |
+ void Prepare(bool has_adapted_arguments, Address stack_frame_pointer); |
+ |
+ // Store newly materialized values into the isolate. |
+ void StoreMaterializedValuesAndDeopt(); |
+ |
+ std::vector<TranslatedFrame>& frames() { return frames_; } |
+ |
+ TranslatedFrame* GetArgumentsInfoFromJSFrameIndex(int jsframe_index, |
+ int* arguments_count); |
+ |
+ Isolate* isolate() { return isolate_; } |
+ |
+ void Init(Address input_frame_pointer, JSFunction* input_frame_function, |
+ TranslationIterator* iterator, FixedArray* literal_array, |
+ RegisterValues* registers, FILE* trace_file); |
+ |
+ private: |
+ friend TranslatedValue; |
+ |
+ TranslatedFrame CreateNextTranslatedFrame(TranslationIterator* iterator, |
+ FixedArray* literal_array, |
+ Address fp, |
+ JSFunction* frame_function, |
+ FILE* trace_file); |
+ TranslatedValue CreateNextTranslatedValue(int frame_index, int value_index, |
+ TranslationIterator* iterator, |
+ FixedArray* literal_array, |
+ Address fp, |
+ RegisterValues* registers, |
+ FILE* trace_file); |
+ |
+ void UpdateFromPreviouslyMaterializedObjects(); |
+ Handle<Object> MaterializeAt(int frame_index, int* value_index); |
+ Handle<Object> MaterializeObjectAt(int object_index); |
+ bool GetAdaptedArguments(Handle<JSObject>* result, int frame_index); |
+ |
+ static int SlotOffsetFp(int slot_index); |
+ static Address SlotAddress(Address fp, int slot_index); |
+ static uint32_t GetUInt32Slot(Address fp, int slot_index); |
+ |
+ std::vector<TranslatedFrame> frames_; |
+ Isolate* isolate_; |
+ Address stack_frame_pointer_; |
+ bool has_adapted_arguments_; |
+ |
+ struct ObjectPosition { |
+ int frame_index_; |
+ int value_index_; |
+ }; |
+ std::deque<ObjectPosition> object_positions_; |
+}; |
template<typename T> |
class HeapNumberMaterializationDescriptor BASE_EMBEDDED { |
@@ -280,10 +533,7 @@ class Deoptimizer : public Malloced { |
void MaterializeHeapObjects(JavaScriptFrameIterator* it); |
void MaterializeHeapNumbersForDebuggerInspectableFrame( |
- Address parameters_top, |
- uint32_t parameters_size, |
- Address expressions_top, |
- uint32_t expressions_size, |
+ int frame_index, int parameter_count, int expression_count, |
DeoptimizedFrameInfo* info); |
static void ComputeOutputFrames(Deoptimizer* deoptimizer); |
@@ -382,20 +632,9 @@ class Deoptimizer : public Malloced { |
void DoComputeCompiledStubFrame(TranslationIterator* iterator, |
int frame_index); |
- // Translate object, store the result into an auxiliary array |
- // (deferred_objects_tagged_values_). |
- void DoTranslateObject(TranslationIterator* iterator, |
- int object_index, |
- int field_index); |
- |
- // Translate value, store the result into the given frame slot. |
- void DoTranslateCommand(TranslationIterator* iterator, |
- int frame_index, |
- unsigned output_offset); |
- |
- // Translate object, do not store the result anywhere (but do update |
- // the deferred materialization array). |
- void DoTranslateObjectAndSkip(TranslationIterator* iterator); |
+ void WriteValueToOutput(TranslatedFrame::iterator* iterator, int* input_index, |
+ int frame_index, unsigned output_offset, |
+ Address output_address_for_materialization = nullptr); |
unsigned ComputeInputFrameSize() const; |
unsigned ComputeFixedSize(JSFunction* function) const; |
@@ -405,28 +644,6 @@ class Deoptimizer : public Malloced { |
Object* ComputeLiteral(int index) const; |
- void AddObjectStart(intptr_t slot_address, int argc, bool is_arguments); |
- void AddObjectDuplication(intptr_t slot, int object_index); |
- void AddObjectTaggedValue(intptr_t value); |
- void AddObjectDoubleValue(double value); |
- void AddDoubleValue(intptr_t slot_address, double value); |
- |
- bool ArgumentsObjectIsAdapted(int object_index) { |
- ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index); |
- int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1; |
- return jsframe_has_adapted_arguments_[reverse_jsframe_index]; |
- } |
- |
- Handle<JSFunction> ArgumentsObjectFunction(int object_index) { |
- ObjectMaterializationDescriptor desc = deferred_objects_.at(object_index); |
- int reverse_jsframe_index = jsframe_count_ - desc.jsframe_index() - 1; |
- return jsframe_functions_[reverse_jsframe_index]; |
- } |
- |
- // Helper function for heap object materialization. |
- Handle<Object> MaterializeNextHeapObject(); |
- Handle<Object> MaterializeNextValue(); |
- |
static void GenerateDeoptimizationEntries( |
MacroAssembler* masm, int count, BailoutType type); |
@@ -484,27 +701,15 @@ class Deoptimizer : public Malloced { |
// Array of output frame descriptions. |
FrameDescription** output_; |
- // Deferred values to be materialized. |
- List<Object*> deferred_objects_tagged_values_; |
- List<HeapNumberMaterializationDescriptor<int> > |
- deferred_objects_double_values_; |
- List<ObjectMaterializationDescriptor> deferred_objects_; |
- List<HeapNumberMaterializationDescriptor<Address> > deferred_heap_numbers_; |
- |
// Key for lookup of previously materialized objects |
Address stack_fp_; |
- Handle<FixedArray> previously_materialized_objects_; |
- int prev_materialized_count_; |
- // Output frame information. Only used during heap object materialization. |
- List<Handle<JSFunction> > jsframe_functions_; |
- List<bool> jsframe_has_adapted_arguments_; |
- |
- // Materialized objects. Only used during heap object materialization. |
- List<Handle<Object> >* materialized_values_; |
- List<Handle<Object> >* materialized_objects_; |
- int materialization_value_index_; |
- int materialization_object_index_; |
+ TranslatedState translated_state_; |
+ struct ValueToMaterialize { |
+ Address output_slot_address_; |
+ TranslatedFrame::iterator value_; |
+ }; |
+ std::vector<ValueToMaterialize> values_to_materialize_; |
#ifdef DEBUG |
DisallowHeapAllocation* disallow_heap_allocation_; |
@@ -519,6 +724,41 @@ class Deoptimizer : public Malloced { |
}; |
+class RegisterValues { |
+ public: |
+ intptr_t GetRegister(unsigned n) const { |
+#if DEBUG |
+ // This convoluted DCHECK is needed to work around a gcc problem that |
+ // improperly detects an array bounds overflow in optimized debug builds |
+ // when using a plain DCHECK. |
+ if (n >= arraysize(registers_)) { |
+ DCHECK(false); |
+ return 0; |
+ } |
+#endif |
+ return registers_[n]; |
+ } |
+ |
+ double GetDoubleRegister(unsigned n) const { |
+ DCHECK(n < arraysize(double_registers_)); |
+ return double_registers_[n]; |
+ } |
+ |
+ void SetRegister(unsigned n, intptr_t value) { |
+ DCHECK(n < arraysize(registers_)); |
+ registers_[n] = value; |
+ } |
+ |
+ void SetDoubleRegister(unsigned n, double value) { |
+ DCHECK(n < arraysize(double_registers_)); |
+ double_registers_[n] = value; |
+ } |
+ |
+ intptr_t registers_[Register::kNumRegisters]; |
+ double double_registers_[DoubleRegister::kMaxNumRegisters]; |
+}; |
+ |
+ |
class FrameDescription { |
public: |
FrameDescription(uint32_t frame_size, |
@@ -554,11 +794,15 @@ class FrameDescription { |
return *GetFrameSlotPointer(offset); |
} |
- double GetDoubleFrameSlot(unsigned offset) { |
- intptr_t* ptr = GetFrameSlotPointer(offset); |
- return read_double_value(reinterpret_cast<Address>(ptr)); |
+ Address GetFramePointerAddress() { |
+ int fp_offset = GetFrameSize() - |
+ (ComputeParametersCount() + 1) * kPointerSize - |
+ StandardFrameConstants::kCallerSPOffset; |
+ return reinterpret_cast<Address>(GetFrameSlotPointer(fp_offset)); |
} |
+ RegisterValues* GetRegisterValues() { return ®ister_values_; } |
+ |
void SetFrameSlot(unsigned offset, intptr_t value) { |
*GetFrameSlotPointer(offset) = value; |
} |
@@ -570,31 +814,19 @@ class FrameDescription { |
void SetCallerConstantPool(unsigned offset, intptr_t value); |
intptr_t GetRegister(unsigned n) const { |
-#if DEBUG |
- // This convoluted DCHECK is needed to work around a gcc problem that |
- // improperly detects an array bounds overflow in optimized debug builds |
- // when using a plain DCHECK. |
- if (n >= arraysize(registers_)) { |
- DCHECK(false); |
- return 0; |
- } |
-#endif |
- return registers_[n]; |
+ return register_values_.GetRegister(n); |
} |
double GetDoubleRegister(unsigned n) const { |
- DCHECK(n < arraysize(double_registers_)); |
- return double_registers_[n]; |
+ return register_values_.GetDoubleRegister(n); |
} |
void SetRegister(unsigned n, intptr_t value) { |
- DCHECK(n < arraysize(registers_)); |
- registers_[n] = value; |
+ register_values_.SetRegister(n, value); |
} |
void SetDoubleRegister(unsigned n, double value) { |
- DCHECK(n < arraysize(double_registers_)); |
- double_registers_[n] = value; |
+ register_values_.SetDoubleRegister(n, value); |
} |
intptr_t GetTop() const { return top_; } |
@@ -635,11 +867,11 @@ class FrameDescription { |
Object* GetExpression(int index); |
static int registers_offset() { |
- return OFFSET_OF(FrameDescription, registers_); |
+ return OFFSET_OF(FrameDescription, register_values_.registers_); |
} |
static int double_registers_offset() { |
- return OFFSET_OF(FrameDescription, double_registers_); |
+ return OFFSET_OF(FrameDescription, register_values_.double_registers_); |
} |
static int frame_size_offset() { |
@@ -670,8 +902,7 @@ class FrameDescription { |
// the end of the structure aligned. |
uintptr_t frame_size_; // Number of bytes. |
JSFunction* function_; |
- intptr_t registers_[Register::kNumRegisters]; |
- double double_registers_[DoubleRegister::kMaxNumRegisters]; |
+ RegisterValues register_values_; |
intptr_t top_; |
intptr_t pc_; |
intptr_t fp_; |
@@ -802,7 +1033,7 @@ class Translation BASE_EMBEDDED { |
// Commands. |
void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height); |
- void BeginCompiledStubFrame(); |
+ void BeginCompiledStubFrame(int height); |
void BeginArgumentsAdaptorFrame(int literal_id, unsigned height); |
void BeginConstructStubFrame(int literal_id, unsigned height); |
void BeginGetterStubFrame(int literal_id); |
@@ -841,124 +1072,6 @@ class Translation BASE_EMBEDDED { |
}; |
-class SlotRef BASE_EMBEDDED { |
- public: |
- enum SlotRepresentation { |
- UNKNOWN, |
- TAGGED, |
- INT32, |
- UINT32, |
- BOOLBIT, |
- DOUBLE, |
- LITERAL, |
- DEFERRED_OBJECT, // Object captured by the escape analysis. |
- // The number of nested objects can be obtained |
- // with the DeferredObjectLength() method |
- // (the SlotRefs of the nested objects follow |
- // this SlotRef in the depth-first order.) |
- DUPLICATE_OBJECT, // Duplicated object of a deferred object. |
- ARGUMENTS_OBJECT // Arguments object - only used to keep indexing |
- // in sync, it should not be materialized. |
- }; |
- |
- SlotRef() |
- : addr_(NULL), representation_(UNKNOWN) { } |
- |
- SlotRef(Address addr, SlotRepresentation representation) |
- : addr_(addr), representation_(representation) { } |
- |
- SlotRef(Isolate* isolate, Object* literal) |
- : literal_(literal, isolate), representation_(LITERAL) { } |
- |
- static SlotRef NewArgumentsObject(int length) { |
- SlotRef slot; |
- slot.representation_ = ARGUMENTS_OBJECT; |
- slot.deferred_object_length_ = length; |
- return slot; |
- } |
- |
- static SlotRef NewDeferredObject(int length) { |
- SlotRef slot; |
- slot.representation_ = DEFERRED_OBJECT; |
- slot.deferred_object_length_ = length; |
- return slot; |
- } |
- |
- SlotRepresentation Representation() { return representation_; } |
- |
- static SlotRef NewDuplicateObject(int id) { |
- SlotRef slot; |
- slot.representation_ = DUPLICATE_OBJECT; |
- slot.duplicate_object_id_ = id; |
- return slot; |
- } |
- |
- int GetChildrenCount() { |
- if (representation_ == DEFERRED_OBJECT || |
- representation_ == ARGUMENTS_OBJECT) { |
- return deferred_object_length_; |
- } else { |
- return 0; |
- } |
- } |
- |
- int DuplicateObjectId() { return duplicate_object_id_; } |
- |
- Handle<Object> GetValue(Isolate* isolate); |
- |
- private: |
- Address addr_; |
- Handle<Object> literal_; |
- SlotRepresentation representation_; |
- int deferred_object_length_; |
- int duplicate_object_id_; |
-}; |
- |
-class SlotRefValueBuilder BASE_EMBEDDED { |
- public: |
- SlotRefValueBuilder( |
- JavaScriptFrame* frame, |
- int inlined_frame_index, |
- int formal_parameter_count); |
- |
- void Prepare(Isolate* isolate); |
- Handle<Object> GetNext(Isolate* isolate, int level); |
- void Finish(Isolate* isolate); |
- |
- int args_length() { return args_length_; } |
- |
- private: |
- List<Handle<Object> > materialized_objects_; |
- Handle<FixedArray> previously_materialized_objects_; |
- int prev_materialized_count_; |
- Address stack_frame_id_; |
- List<SlotRef> slot_refs_; |
- int current_slot_; |
- int args_length_; |
- int first_slot_index_; |
- bool should_deoptimize_; |
- |
- static SlotRef ComputeSlotForNextArgument( |
- Translation::Opcode opcode, |
- TranslationIterator* iterator, |
- DeoptimizationInputData* data, |
- JavaScriptFrame* frame); |
- |
- Handle<Object> GetPreviouslyMaterialized(Isolate* isolate, int length); |
- |
- static Address SlotAddress(JavaScriptFrame* frame, int slot_index) { |
- if (slot_index >= 0) { |
- const int offset = JavaScriptFrameConstants::kLocal0Offset; |
- return frame->fp() + offset - (slot_index * kPointerSize); |
- } else { |
- const int offset = JavaScriptFrameConstants::kLastParameterOffset; |
- return frame->fp() + offset - ((slot_index + 1) * kPointerSize); |
- } |
- } |
- |
- Handle<Object> GetDeferredObject(Isolate* isolate); |
-}; |
- |
class MaterializedObjectStore { |
public: |
explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) { |
@@ -1058,6 +1171,7 @@ class DeoptimizedFrameInfo : public Malloced { |
friend class Deoptimizer; |
}; |
-} } // namespace v8::internal |
+} // namespace internal |
+} // namespace v8 |
#endif // V8_DEOPTIMIZER_H_ |