Upgrade to 3.29
Update V8 to 3.29.88.17 and update makefiles to support building on
all the relevant platforms.
Bug: 17370214
Change-Id: Ia3407c157fd8d72a93e23d8318ccaf6ecf77fa4e
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 6bc4a51..612d5f6 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -1,59 +1,74 @@
// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
#ifndef V8_DEOPTIMIZER_H_
#define V8_DEOPTIMIZER_H_
-#include "v8.h"
+#include "src/v8.h"
-#include "allocation.h"
-#include "macro-assembler.h"
-#include "zone-inl.h"
+#include "src/allocation.h"
+#include "src/macro-assembler.h"
+#include "src/zone-inl.h"
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 DeoptimizingCodeListNode;
class DeoptimizedFrameInfo;
+template<typename T>
class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
public:
- HeapNumberMaterializationDescriptor(Address slot_address, double val)
- : slot_address_(slot_address), val_(val) { }
+ HeapNumberMaterializationDescriptor(T destination, double value)
+ : destination_(destination), value_(value) { }
+
+ T destination() const { return destination_; }
+ double value() const { return value_; }
+
+ private:
+ T destination_;
+ double value_;
+};
+
+
+class ObjectMaterializationDescriptor BASE_EMBEDDED {
+ public:
+ ObjectMaterializationDescriptor(
+ Address slot_address, int frame, int length, int duplicate, bool is_args)
+ : slot_address_(slot_address),
+ jsframe_index_(frame),
+ object_length_(length),
+ duplicate_object_(duplicate),
+ is_arguments_(is_args) { }
Address slot_address() const { return slot_address_; }
- double value() const { return val_; }
+ int jsframe_index() const { return jsframe_index_; }
+ int object_length() const { return object_length_; }
+ int duplicate_object() const { return duplicate_object_; }
+ bool is_arguments() const { return is_arguments_; }
+
+ // Only used for allocated receivers in DoComputeConstructStubFrame.
+ void patch_slot_address(intptr_t slot) {
+ slot_address_ = reinterpret_cast<Address>(slot);
+ }
private:
Address slot_address_;
- double val_;
+ int jsframe_index_;
+ int object_length_;
+ int duplicate_object_;
+ bool is_arguments_;
};
@@ -62,63 +77,79 @@
virtual ~OptimizedFunctionVisitor() {}
// Function which is called before iteration of any optimized functions
- // from given global context.
+ // from given native context.
virtual void EnterContext(Context* context) = 0;
virtual void VisitFunction(JSFunction* function) = 0;
// Function which is called after iteration of all optimized functions
- // from given global context.
+ // from given native context.
virtual void LeaveContext(Context* context) = 0;
};
-class Deoptimizer;
-
-
-class DeoptimizerData {
- public:
- DeoptimizerData();
- ~DeoptimizerData();
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
- void Iterate(ObjectVisitor* v);
-#endif
-
- private:
- MemoryChunk* eager_deoptimization_entry_code_;
- MemoryChunk* lazy_deoptimization_entry_code_;
- Deoptimizer* current_;
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
- DeoptimizedFrameInfo* deoptimized_frame_info_;
-#endif
-
- // List of deoptimized code which still have references from active stack
- // frames. These code objects are needed by the deoptimizer when deoptimizing
- // a frame for which the code object for the function function has been
- // changed from the code present when deoptimizing was done.
- DeoptimizingCodeListNode* deoptimizing_code_list_;
-
- friend class Deoptimizer;
-
- DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
-};
-
-
class Deoptimizer : public Malloced {
public:
enum BailoutType {
EAGER,
LAZY,
- OSR,
+ SOFT,
// This last bailout type is not really a bailout, but used by the
// debugger to deoptimize stack frames to allow inspection.
DEBUGGER
};
+ static const int kBailoutTypesWithCodeEntry = SOFT + 1;
+
+ struct Reason {
+ Reason(int r, const char* m, const char* d)
+ : raw_position(r), mnemonic(m), detail(d) {}
+
+ bool operator==(const Reason& other) const {
+ return raw_position == other.raw_position &&
+ CStringEquals(mnemonic, other.mnemonic) &&
+ CStringEquals(detail, other.detail);
+ }
+
+ bool operator!=(const Reason& other) const { return !(*this == other); }
+
+ int raw_position;
+ const char* mnemonic;
+ const char* detail;
+ };
+
+ struct JumpTableEntry : public ZoneObject {
+ inline JumpTableEntry(Address entry, const Reason& the_reason,
+ Deoptimizer::BailoutType type, bool frame)
+ : label(),
+ address(entry),
+ reason(the_reason),
+ bailout_type(type),
+ needs_frame(frame) {}
+
+ bool IsEquivalentTo(const JumpTableEntry& other) const {
+ return address == other.address && bailout_type == other.bailout_type &&
+ needs_frame == other.needs_frame &&
+ (!FLAG_trace_deopt || reason == other.reason);
+ }
+
+ Label label;
+ Address address;
+ Reason reason;
+ Deoptimizer::BailoutType bailout_type;
+ bool needs_frame;
+ };
+
+ static bool TraceEnabledFor(BailoutType deopt_type,
+ StackFrame::Type frame_type);
+ static const char* MessageFor(BailoutType type);
+
int output_count() const { return output_count_; }
+ Handle<JSFunction> function() const { return Handle<JSFunction>(function_); }
+ Handle<Code> compiled_code() const { return Handle<Code>(compiled_code_); }
+ BailoutType bailout_type() const { return bailout_type_; }
+
// Number of created JS frames. Not all created frames are necessarily JS.
int jsframe_count() const { return jsframe_count_; }
@@ -130,7 +161,6 @@
Isolate* isolate);
static Deoptimizer* Grab(Isolate* isolate);
-#ifdef ENABLE_DEBUGGER_SUPPORT
// The returned object with information on the optimized frame needs to be
// freed before another one can be generated.
static DeoptimizedFrameInfo* DebuggerInspectableFrame(JavaScriptFrame* frame,
@@ -138,7 +168,6 @@
Isolate* isolate);
static void DeleteDebuggerInspectableFrame(DeoptimizedFrameInfo* info,
Isolate* isolate);
-#endif
// Makes sure that there is enough room in the relocation
// information of a code object to perform lazy deoptimization
@@ -152,66 +181,54 @@
// execution returns.
static void DeoptimizeFunction(JSFunction* function);
- // Deoptimize all functions in the heap.
- static void DeoptimizeAll();
+ // Deoptimize all code in the given isolate.
+ static void DeoptimizeAll(Isolate* isolate);
+ // Deoptimize code associated with the given global object.
static void DeoptimizeGlobalObject(JSObject* object);
- static void VisitAllOptimizedFunctionsForContext(
- Context* context, OptimizedFunctionVisitor* visitor);
+ // Deoptimizes all optimized code that has been previously marked
+ // (via code->set_marked_for_deoptimization) and unlinks all functions that
+ // refer to that code.
+ static void DeoptimizeMarkedCode(Isolate* isolate);
- static void VisitAllOptimizedFunctionsForGlobalObject(
- JSObject* object, OptimizedFunctionVisitor* visitor);
-
- static void VisitAllOptimizedFunctions(OptimizedFunctionVisitor* visitor);
+ // Visit all the known optimized functions in a given isolate.
+ static void VisitAllOptimizedFunctions(
+ Isolate* isolate, OptimizedFunctionVisitor* visitor);
// The size in bytes of the code required at a lazy deopt patch site.
static int patch_size();
- // Patch all stack guard checks in the unoptimized code to
- // unconditionally call replacement_code.
- static void PatchStackCheckCode(Code* unoptimized_code,
- Code* check_code,
- Code* replacement_code);
-
- // Patch stack guard check at instruction before pc_after in
- // the unoptimized code to unconditionally call replacement_code.
- static void PatchStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code);
-
- // Change all patched stack guard checks in the unoptimized code
- // back to a normal stack guard check.
- static void RevertStackCheckCode(Code* unoptimized_code,
- Code* check_code,
- Code* replacement_code);
-
- // Change all patched stack guard checks in the unoptimized code
- // back to a normal stack guard check.
- static void RevertStackCheckCodeAt(Code* unoptimized_code,
- Address pc_after,
- Code* check_code,
- Code* replacement_code);
-
~Deoptimizer();
- void MaterializeHeapNumbers();
-#ifdef ENABLE_DEBUGGER_SUPPORT
+ void MaterializeHeapObjects(JavaScriptFrameIterator* it);
+
void MaterializeHeapNumbersForDebuggerInspectableFrame(
Address parameters_top,
uint32_t parameters_size,
Address expressions_top,
uint32_t expressions_size,
DeoptimizedFrameInfo* info);
-#endif
static void ComputeOutputFrames(Deoptimizer* deoptimizer);
- static Address GetDeoptimizationEntry(int id, BailoutType type);
- static int GetDeoptimizationId(Address addr, BailoutType type);
+
+ enum GetEntryMode {
+ CALCULATE_ENTRY_ADDRESS,
+ ENSURE_ENTRY_CODE
+ };
+
+
+ static Address GetDeoptimizationEntry(
+ Isolate* isolate,
+ int id,
+ BailoutType type,
+ GetEntryMode mode = ENSURE_ENTRY_CODE);
+ static int GetDeoptimizationId(Isolate* isolate,
+ Address addr,
+ BailoutType type);
static int GetOutputInfo(DeoptimizationOutputData* data,
- unsigned node_id,
+ BailoutId node_id,
SharedFunctionInfo* shared);
// Code generation support.
@@ -221,6 +238,10 @@
}
static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
+ static int has_alignment_padding_offset() {
+ return OFFSET_OF(Deoptimizer, has_alignment_padding_);
+ }
+
static int GetDeoptimizedCodeCount(Isolate* isolate);
static const int kNotDeoptimizationEntry = -1;
@@ -237,6 +258,7 @@
protected:
MacroAssembler* masm() const { return masm_; }
BailoutType type() const { return type_; }
+ Isolate* isolate() const { return masm_->isolate(); }
virtual void GeneratePrologue() { }
@@ -261,8 +283,17 @@
int ConvertJSFrameIndexToFrameIndex(int jsframe_index);
+ static size_t GetMaxDeoptTableSize();
+
+ static void EnsureCodeForDeoptimizationEntry(Isolate* isolate,
+ BailoutType type,
+ int max_entry_id);
+
+ Isolate* isolate() const { return isolate_; }
+
private:
- static const int kNumberOfEntries = 16384;
+ static const int kMinNumberOfEntries = 64;
+ static const int kMaxNumberOfEntries = 16384;
Deoptimizer(Isolate* isolate,
JSFunction* function,
@@ -271,24 +302,36 @@
Address from,
int fp_to_sp_delta,
Code* optimized_code);
+ Code* FindOptimizedCode(JSFunction* function, Code* optimized_code);
+ void PrintFunctionName();
void DeleteFrameDescriptions();
void DoComputeOutputFrames();
- void DoComputeOsrOutputFrame();
void DoComputeJSFrame(TranslationIterator* iterator, int frame_index);
void DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
int frame_index);
void DoComputeConstructStubFrame(TranslationIterator* iterator,
int frame_index);
+ void DoComputeAccessorStubFrame(TranslationIterator* iterator,
+ int frame_index,
+ bool is_setter_stub_frame);
+ 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 a command for OSR. Updates the input offset to be used for
- // the next command. Returns false if translation of the command failed
- // (e.g., a number conversion failed) and may or may not have updated the
- // input offset.
- bool DoOsrTranslateCommand(TranslationIterator* iterator,
- int* input_offset);
+
+ // Translate object, do not store the result anywhere (but do update
+ // the deferred materialization array).
+ void DoTranslateObjectAndSkip(TranslationIterator* iterator);
unsigned ComputeInputFrameSize() const;
unsigned ComputeFixedSize(JSFunction* function) const;
@@ -298,30 +341,75 @@
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);
- static MemoryChunk* CreateCode(BailoutType type);
+ 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);
- // Weak handle callback for deoptimizing code objects.
- static void HandleWeakDeoptimizedCode(
- v8::Persistent<v8::Value> obj, void* data);
- static Code* FindDeoptimizingCodeFromAddress(Address addr);
- static void RemoveDeoptimizingCode(Code* code);
+ // Marks all the code in the given context for deoptimization.
+ static void MarkAllCodeForContext(Context* native_context);
+
+ // Visit all the known optimized functions in a given context.
+ static void VisitAllOptimizedFunctionsForContext(
+ Context* context, OptimizedFunctionVisitor* visitor);
+
+ // Deoptimizes all code marked in the given context.
+ static void DeoptimizeMarkedCodeForContext(Context* native_context);
+
+ // Patch the given code so that it will deoptimize itself.
+ static void PatchCodeForDeoptimization(Isolate* isolate, Code* code);
+
+ // Searches the list of known deoptimizing code for a Code object
+ // containing the given address (which is supposedly faster than
+ // searching all code objects).
+ Code* FindDeoptimizingCode(Address addr);
// Fill the input from from a JavaScript frame. This is used when
// the debugger needs to inspect an optimized frame. For normal
// deoptimizations the input frame is filled in generated code.
void FillInputFrame(Address tos, JavaScriptFrame* frame);
+ // Fill the given output frame's registers to contain the failure handler
+ // address and the number of parameters for a stub failure trampoline.
+ void SetPlatformCompiledStubRegisters(FrameDescription* output_frame,
+ CodeStubDescriptor* desc);
+
+ // Fill the given output frame's double registers with the original values
+ // from the input frame's double registers.
+ void CopyDoubleRegisters(FrameDescription* output_frame);
+
+ // Determines whether the input frame contains alignment padding by looking
+ // at the dynamic alignment state slot inside the frame.
+ bool HasAlignmentPadding(JSFunction* function);
+
Isolate* isolate_;
JSFunction* function_;
- Code* optimized_code_;
+ Code* compiled_code_;
unsigned bailout_id_;
BailoutType bailout_type_;
Address from_;
int fp_to_sp_delta_;
+ int has_alignment_padding_;
// Input frame description.
FrameDescription* input_;
@@ -332,12 +420,37 @@
// Array of output frame descriptions.
FrameDescription** output_;
- List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
+ // 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_;
+
+#ifdef DEBUG
+ DisallowHeapAllocation* disallow_heap_allocation_;
+#endif // DEBUG
+
+ CodeTracer::Scope* trace_scope_;
static const int table_entry_size_;
friend class FrameDescription;
- friend class DeoptimizingCodeListNode;
friend class DeoptimizedFrameInfo;
};
@@ -362,7 +475,7 @@
}
uint32_t GetFrameSize() const {
- ASSERT(static_cast<uint32_t>(frame_size_) == frame_size_);
+ DCHECK(static_cast<uint32_t>(frame_size_) == frame_size_);
return static_cast<uint32_t>(frame_size_);
}
@@ -376,42 +489,44 @@
double GetDoubleFrameSlot(unsigned offset) {
intptr_t* ptr = GetFrameSlotPointer(offset);
-#if V8_TARGET_ARCH_MIPS
- // Prevent gcc from using load-double (mips ldc1) on (possibly)
- // non-64-bit aligned double. Uses two lwc1 instructions.
- union conversion {
- double d;
- uint32_t u[2];
- } c;
- c.u[0] = *reinterpret_cast<uint32_t*>(ptr);
- c.u[1] = *(reinterpret_cast<uint32_t*>(ptr) + 1);
- return c.d;
-#else
- return *reinterpret_cast<double*>(ptr);
-#endif
+ return read_double_value(reinterpret_cast<Address>(ptr));
}
void SetFrameSlot(unsigned offset, intptr_t value) {
*GetFrameSlotPointer(offset) = value;
}
+ void SetCallerPc(unsigned offset, intptr_t value);
+
+ void SetCallerFp(unsigned offset, intptr_t value);
+
+ void SetCallerConstantPool(unsigned offset, intptr_t value);
+
intptr_t GetRegister(unsigned n) const {
- ASSERT(n < ARRAY_SIZE(registers_));
+#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 {
- ASSERT(n < ARRAY_SIZE(double_registers_));
+ DCHECK(n < arraysize(double_registers_));
return double_registers_[n];
}
void SetRegister(unsigned n, intptr_t value) {
- ASSERT(n < ARRAY_SIZE(registers_));
+ DCHECK(n < arraysize(registers_));
registers_[n] = value;
}
void SetDoubleRegister(unsigned n, double value) {
- ASSERT(n < ARRAY_SIZE(double_registers_));
+ DCHECK(n < arraysize(double_registers_));
double_registers_[n] = value;
}
@@ -427,6 +542,11 @@
intptr_t GetContext() const { return context_; }
void SetContext(intptr_t context) { context_ = context; }
+ intptr_t GetConstantPool() const { return constant_pool_; }
+ void SetConstantPool(intptr_t constant_pool) {
+ constant_pool_ = constant_pool;
+ }
+
Smi* GetState() const { return state_; }
void SetState(Smi* state) { state_ = state; }
@@ -484,16 +604,14 @@
uintptr_t frame_size_; // Number of bytes.
JSFunction* function_;
intptr_t registers_[Register::kNumRegisters];
- double double_registers_[DoubleRegister::kNumAllocatableRegisters];
+ double double_registers_[DoubleRegister::kMaxNumRegisters];
intptr_t top_;
intptr_t pc_;
intptr_t fp_;
intptr_t context_;
+ intptr_t constant_pool_;
StackFrame::Type type_;
Smi* state_;
-#ifdef DEBUG
- Code::Kind kind_;
-#endif
// Continuation is the PC where the execution continues after
// deoptimizing.
@@ -504,7 +622,7 @@
intptr_t frame_content_[1];
intptr_t* GetFrameSlotPointer(unsigned offset) {
- ASSERT(offset < frame_size_);
+ DCHECK(offset < frame_size_);
return reinterpret_cast<intptr_t*>(
reinterpret_cast<Address>(this) + frame_content_offset() + offset);
}
@@ -513,14 +631,36 @@
};
+class DeoptimizerData {
+ public:
+ explicit DeoptimizerData(MemoryAllocator* allocator);
+ ~DeoptimizerData();
+
+ void Iterate(ObjectVisitor* v);
+
+ private:
+ MemoryAllocator* allocator_;
+ int deopt_entry_code_entries_[Deoptimizer::kBailoutTypesWithCodeEntry];
+ MemoryChunk* deopt_entry_code_[Deoptimizer::kBailoutTypesWithCodeEntry];
+
+ DeoptimizedFrameInfo* deoptimized_frame_info_;
+
+ Deoptimizer* current_;
+
+ friend class Deoptimizer;
+
+ DISALLOW_COPY_AND_ASSIGN(DeoptimizerData);
+};
+
+
class TranslationBuffer BASE_EMBEDDED {
public:
- TranslationBuffer() : contents_(256) { }
+ explicit TranslationBuffer(Zone* zone) : contents_(256, zone) { }
int CurrentIndex() const { return contents_.length(); }
- void Add(int32_t value);
+ void Add(int32_t value, Zone* zone);
- Handle<ByteArray> CreateByteArray();
+ Handle<ByteArray> CreateByteArray(Factory* factory);
private:
ZoneList<uint8_t> contents_;
@@ -531,7 +671,7 @@
public:
TranslationIterator(ByteArray* buffer, int index)
: buffer_(buffer), index_(index) {
- ASSERT(index >= 0 && index < buffer->length());
+ DCHECK(index >= 0 && index < buffer->length());
}
int32_t Next();
@@ -548,50 +688,71 @@
};
+#define TRANSLATION_OPCODE_LIST(V) \
+ V(BEGIN) \
+ V(JS_FRAME) \
+ V(CONSTRUCT_STUB_FRAME) \
+ V(GETTER_STUB_FRAME) \
+ V(SETTER_STUB_FRAME) \
+ V(ARGUMENTS_ADAPTOR_FRAME) \
+ V(COMPILED_STUB_FRAME) \
+ V(DUPLICATED_OBJECT) \
+ V(ARGUMENTS_OBJECT) \
+ V(CAPTURED_OBJECT) \
+ V(REGISTER) \
+ V(INT32_REGISTER) \
+ V(UINT32_REGISTER) \
+ V(DOUBLE_REGISTER) \
+ V(STACK_SLOT) \
+ V(INT32_STACK_SLOT) \
+ V(UINT32_STACK_SLOT) \
+ V(DOUBLE_STACK_SLOT) \
+ V(LITERAL)
+
+
class Translation BASE_EMBEDDED {
public:
+#define DECLARE_TRANSLATION_OPCODE_ENUM(item) item,
enum Opcode {
- BEGIN,
- JS_FRAME,
- CONSTRUCT_STUB_FRAME,
- ARGUMENTS_ADAPTOR_FRAME,
- REGISTER,
- INT32_REGISTER,
- DOUBLE_REGISTER,
- STACK_SLOT,
- INT32_STACK_SLOT,
- DOUBLE_STACK_SLOT,
- LITERAL,
- ARGUMENTS_OBJECT,
-
- // A prefix indicating that the next command is a duplicate of the one
- // that follows it.
- DUPLICATE
+ TRANSLATION_OPCODE_LIST(DECLARE_TRANSLATION_OPCODE_ENUM)
+ LAST = LITERAL
};
+#undef DECLARE_TRANSLATION_OPCODE_ENUM
- Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count)
+ Translation(TranslationBuffer* buffer, int frame_count, int jsframe_count,
+ Zone* zone)
: buffer_(buffer),
- index_(buffer->CurrentIndex()) {
- buffer_->Add(BEGIN);
- buffer_->Add(frame_count);
- buffer_->Add(jsframe_count);
+ index_(buffer->CurrentIndex()),
+ zone_(zone) {
+ buffer_->Add(BEGIN, zone);
+ buffer_->Add(frame_count, zone);
+ buffer_->Add(jsframe_count, zone);
}
int index() const { return index_; }
// Commands.
- void BeginJSFrame(int node_id, int literal_id, unsigned height);
+ void BeginJSFrame(BailoutId node_id, int literal_id, unsigned height);
+ void BeginCompiledStubFrame();
void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
void BeginConstructStubFrame(int literal_id, unsigned height);
+ void BeginGetterStubFrame(int literal_id);
+ void BeginSetterStubFrame(int literal_id);
+ void BeginArgumentsObject(int args_length);
+ void BeginCapturedObject(int length);
+ void DuplicateObject(int object_index);
void StoreRegister(Register reg);
void StoreInt32Register(Register reg);
+ void StoreUint32Register(Register reg);
void StoreDoubleRegister(DoubleRegister reg);
void StoreStackSlot(int index);
void StoreInt32StackSlot(int index);
+ void StoreUint32StackSlot(int index);
void StoreDoubleStackSlot(int index);
void StoreLiteral(int literal_id);
- void StoreArgumentsObject();
- void MarkDuplicate();
+ void StoreArgumentsObject(bool args_known, int args_index, int args_length);
+
+ Zone* zone() const { return zone_; }
static int NumberOfOperandsFor(Opcode opcode);
@@ -599,29 +760,13 @@
static const char* StringFor(Opcode opcode);
#endif
+ // A literal id which refers to the JSFunction itself.
+ static const int kSelfLiteralId = -239;
+
private:
TranslationBuffer* buffer_;
int index_;
-};
-
-
-// Linked list holding deoptimizing code objects. The deoptimizing code objects
-// are kept as weak handles until they are no longer activated on the stack.
-class DeoptimizingCodeListNode : public Malloced {
- public:
- explicit DeoptimizingCodeListNode(Code* code);
- ~DeoptimizingCodeListNode();
-
- DeoptimizingCodeListNode* next() const { return next_; }
- void set_next(DeoptimizingCodeListNode* next) { next_ = next; }
- Handle<Code> code() const { return code_; }
-
- private:
- // Global (weak) handle to the deoptimizing code object.
- Handle<Code> code_;
-
- // Next pointer for linked list.
- DeoptimizingCodeListNode* next_;
+ Zone* zone_;
};
@@ -631,8 +776,17 @@
UNKNOWN,
TAGGED,
INT32,
+ UINT32,
DOUBLE,
- LITERAL
+ 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()
@@ -641,46 +795,83 @@
SlotRef(Address addr, SlotRepresentation representation)
: addr_(addr), representation_(representation) { }
- explicit SlotRef(Object* literal)
- : literal_(literal), representation_(LITERAL) { }
+ SlotRef(Isolate* isolate, Object* literal)
+ : literal_(literal, isolate), representation_(LITERAL) { }
- Handle<Object> GetValue() {
- switch (representation_) {
- case TAGGED:
- return Handle<Object>(Memory::Object_at(addr_));
+ static SlotRef NewArgumentsObject(int length) {
+ SlotRef slot;
+ slot.representation_ = ARGUMENTS_OBJECT;
+ slot.deferred_object_length_ = length;
+ return slot;
+ }
- case INT32: {
- int value = Memory::int32_at(addr_);
- if (Smi::IsValid(value)) {
- return Handle<Object>(Smi::FromInt(value));
- } else {
- return Isolate::Current()->factory()->NewNumberFromInt(value);
- }
- }
+ static SlotRef NewDeferredObject(int length) {
+ SlotRef slot;
+ slot.representation_ = DEFERRED_OBJECT;
+ slot.deferred_object_length_ = length;
+ return slot;
+ }
- case DOUBLE: {
- double value = Memory::double_at(addr_);
- return Isolate::Current()->factory()->NewNumber(value);
- }
+ SlotRepresentation Representation() { return representation_; }
- case LITERAL:
- return literal_;
+ static SlotRef NewDuplicateObject(int id) {
+ SlotRef slot;
+ slot.representation_ = DUPLICATE_OBJECT;
+ slot.duplicate_object_id_ = id;
+ return slot;
+ }
- default:
- UNREACHABLE();
- return Handle<Object>::null();
+ int GetChildrenCount() {
+ if (representation_ == DEFERRED_OBJECT ||
+ representation_ == ARGUMENTS_OBJECT) {
+ return deferred_object_length_;
+ } else {
+ return 0;
}
}
- static Vector<SlotRef> ComputeSlotMappingForArguments(
- JavaScriptFrame* frame,
- int inlined_frame_index,
- int formal_parameter_count);
+ 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_;
+
+ 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) {
@@ -692,19 +883,30 @@
}
}
- static SlotRef ComputeSlotForNextArgument(TranslationIterator* iterator,
- DeoptimizationInputData* data,
- JavaScriptFrame* frame);
+ Handle<Object> GetDeferredObject(Isolate* isolate);
+};
- static void ComputeSlotsForArguments(
- Vector<SlotRef>* args_slots,
- TranslationIterator* iterator,
- DeoptimizationInputData* data,
- JavaScriptFrame* frame);
+class MaterializedObjectStore {
+ public:
+ explicit MaterializedObjectStore(Isolate* isolate) : isolate_(isolate) {
+ }
+
+ Handle<FixedArray> Get(Address fp);
+ void Set(Address fp, Handle<FixedArray> materialized_objects);
+ void Remove(Address fp);
+
+ private:
+ Isolate* isolate() { return isolate_; }
+ Handle<FixedArray> GetStackEntries();
+ Handle<FixedArray> EnsureStackEntries(int size);
+
+ int StackIdToIndex(Address fp);
+
+ Isolate* isolate_;
+ List<Address> frame_fps_;
};
-#ifdef ENABLE_DEBUGGER_SUPPORT
// Class used to represent an unoptimized frame when the debugger
// needs to inspect a frame that is part of an optimized frame. The
// internally used FrameDescription objects are not GC safe so for use
@@ -733,6 +935,9 @@
return function_;
}
+ // Get the frame context.
+ Object* GetContext() { return context_; }
+
// Check if this frame is preceded by construct stub frame. The bottom-most
// inlined frame might still be called by an uninlined construct stub.
bool HasConstructStub() {
@@ -741,13 +946,13 @@
// Get an incoming argument.
Object* GetParameter(int index) {
- ASSERT(0 <= index && index < parameters_count());
+ DCHECK(0 <= index && index < parameters_count());
return parameters_[index];
}
// Get an expression from the expression stack.
Object* GetExpression(int index) {
- ASSERT(0 <= index && index < expression_count());
+ DCHECK(0 <= index && index < expression_count());
return expression_stack_[index];
}
@@ -758,17 +963,18 @@
private:
// Set an incoming argument.
void SetParameter(int index, Object* obj) {
- ASSERT(0 <= index && index < parameters_count());
+ DCHECK(0 <= index && index < parameters_count());
parameters_[index] = obj;
}
// Set an expression on the expression stack.
void SetExpression(int index, Object* obj) {
- ASSERT(0 <= index && index < expression_count());
+ DCHECK(0 <= index && index < expression_count());
expression_stack_[index] = obj;
}
JSFunction* function_;
+ Object* context_;
bool has_construct_stub_;
int parameters_count_;
int expression_count_;
@@ -778,7 +984,6 @@
friend class Deoptimizer;
};
-#endif
} } // namespace v8::internal