Allow the deoptimizer translation to track de-materialized objects.
This allows the deoptimizer to materialize objects (e.g. the arguments object) while deopting without having a consective stack area holding the object values. The LEnvironment explicitly tracks locations for these values and preserves them in the translation. R=svenpanne@chromium.org TEST=mjsunit/compiler/inline-arguments Review URL: https://codereview.chromium.org/16779004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15087 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
643350c5d2
commit
93ab1864ea
@ -929,7 +929,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
||||
BailoutId ast_id = hydrogen_env->ast_id();
|
||||
ASSERT(!ast_id.IsNone() ||
|
||||
hydrogen_env->frame_type() != JS_FUNCTION);
|
||||
int value_count = hydrogen_env->length();
|
||||
int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
|
||||
LEnvironment* result = new(zone()) LEnvironment(
|
||||
hydrogen_env->closure(),
|
||||
hydrogen_env->frame_type(),
|
||||
@ -940,13 +940,15 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
||||
outer,
|
||||
hydrogen_env->entry(),
|
||||
zone());
|
||||
bool needs_arguments_object_materialization = false;
|
||||
int argument_index = *argument_index_accumulator;
|
||||
for (int i = 0; i < value_count; ++i) {
|
||||
for (int i = 0; i < hydrogen_env->length(); ++i) {
|
||||
if (hydrogen_env->is_special_index(i)) continue;
|
||||
|
||||
HValue* value = hydrogen_env->values()->at(i);
|
||||
LOperand* op = NULL;
|
||||
if (value->IsArgumentsObject()) {
|
||||
needs_arguments_object_materialization = true;
|
||||
op = NULL;
|
||||
} else if (value->IsPushArgument()) {
|
||||
op = new(zone()) LArgument(argument_index++);
|
||||
@ -958,6 +960,22 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
||||
value->CheckFlag(HInstruction::kUint32));
|
||||
}
|
||||
|
||||
if (needs_arguments_object_materialization) {
|
||||
HArgumentsObject* arguments = hydrogen_env->entry() == NULL
|
||||
? graph()->GetArgumentsObject()
|
||||
: hydrogen_env->entry()->arguments_object();
|
||||
ASSERT(arguments->IsLinked());
|
||||
for (int i = 1; i < arguments->arguments_count(); ++i) {
|
||||
HValue* value = arguments->arguments_values()->at(i);
|
||||
ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument());
|
||||
ASSERT(HInstruction::cast(value)->IsLinked());
|
||||
LOperand* op = UseAny(value);
|
||||
result->AddValue(op,
|
||||
value->representation(),
|
||||
value->CheckFlag(HInstruction::kUint32));
|
||||
}
|
||||
}
|
||||
|
||||
if (hydrogen_env->frame_type() == JS_FUNCTION) {
|
||||
*argument_index_accumulator = argument_index;
|
||||
}
|
||||
|
@ -580,27 +580,15 @@ MemOperand LCodeGen::ToHighMemOperand(LOperand* op) const {
|
||||
|
||||
|
||||
void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
Translation* translation,
|
||||
int* pushed_arguments_index,
|
||||
int* pushed_arguments_count) {
|
||||
Translation* translation) {
|
||||
if (environment == NULL) return;
|
||||
|
||||
// The translation includes one command per value in the environment.
|
||||
int translation_size = environment->values()->length();
|
||||
int translation_size = environment->translation_size();
|
||||
// The output frame height does not include the parameters.
|
||||
int height = translation_size - environment->parameter_count();
|
||||
|
||||
// Function parameters are arguments to the outermost environment. The
|
||||
// arguments index points to the first element of a sequence of tagged
|
||||
// values on the stack that represent the arguments. This needs to be
|
||||
// kept in sync with the LArgumentsElements implementation.
|
||||
*pushed_arguments_index = -environment->parameter_count();
|
||||
*pushed_arguments_count = environment->parameter_count();
|
||||
|
||||
WriteTranslation(environment->outer(),
|
||||
translation,
|
||||
pushed_arguments_index,
|
||||
pushed_arguments_count);
|
||||
WriteTranslation(environment->outer(), translation);
|
||||
bool has_closure_id = !info()->closure().is_null() &&
|
||||
!info()->closure().is_identical_to(environment->closure());
|
||||
int closure_id = has_closure_id
|
||||
@ -632,23 +620,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
break;
|
||||
}
|
||||
|
||||
// Inlined frames which push their arguments cause the index to be
|
||||
// bumped and another stack area to be used for materialization,
|
||||
// otherwise actual argument values are unknown for inlined frames.
|
||||
bool arguments_known = true;
|
||||
int arguments_index = *pushed_arguments_index;
|
||||
int arguments_count = *pushed_arguments_count;
|
||||
if (environment->entry() != NULL) {
|
||||
arguments_known = environment->entry()->arguments_pushed();
|
||||
arguments_index = arguments_index < 0
|
||||
? GetStackSlotCount() : arguments_index + arguments_count;
|
||||
arguments_count = environment->entry()->arguments_count() + 1;
|
||||
if (environment->entry()->arguments_pushed()) {
|
||||
*pushed_arguments_index = arguments_index;
|
||||
*pushed_arguments_count = arguments_count;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < translation_size; ++i) {
|
||||
LOperand* value = environment->values()->at(i);
|
||||
// spilled_registers_ and spilled_double_registers_ are either
|
||||
@ -660,10 +631,7 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
AddToTranslation(translation,
|
||||
environment->spilled_registers()[value->index()],
|
||||
environment->HasTaggedValueAt(i),
|
||||
environment->HasUint32ValueAt(i),
|
||||
arguments_known,
|
||||
arguments_index,
|
||||
arguments_count);
|
||||
environment->HasUint32ValueAt(i));
|
||||
} else if (
|
||||
value->IsDoubleRegister() &&
|
||||
environment->spilled_double_registers()[value->index()] != NULL) {
|
||||
@ -672,20 +640,36 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
translation,
|
||||
environment->spilled_double_registers()[value->index()],
|
||||
false,
|
||||
false,
|
||||
arguments_known,
|
||||
arguments_index,
|
||||
arguments_count);
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mstarzinger): Introduce marker operands to indicate that this value
|
||||
// is not present and must be reconstructed from the deoptimizer. Currently
|
||||
// this is only used for the arguments object.
|
||||
if (value == NULL) {
|
||||
int arguments_count = environment->values()->length() - translation_size;
|
||||
translation->BeginArgumentsObject(arguments_count);
|
||||
for (int i = 0; i < arguments_count; ++i) {
|
||||
LOperand* value = environment->values()->at(translation_size + i);
|
||||
ASSERT(environment->spilled_registers() == NULL ||
|
||||
!value->IsRegister() ||
|
||||
environment->spilled_registers()[value->index()] == NULL);
|
||||
ASSERT(environment->spilled_registers() == NULL ||
|
||||
!value->IsDoubleRegister() ||
|
||||
environment->spilled_double_registers()[value->index()] == NULL);
|
||||
AddToTranslation(translation,
|
||||
value,
|
||||
environment->HasTaggedValueAt(translation_size + i),
|
||||
environment->HasUint32ValueAt(translation_size + i));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
AddToTranslation(translation,
|
||||
value,
|
||||
environment->HasTaggedValueAt(i),
|
||||
environment->HasUint32ValueAt(i),
|
||||
arguments_known,
|
||||
arguments_index,
|
||||
arguments_count);
|
||||
environment->HasUint32ValueAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -693,17 +677,8 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
void LCodeGen::AddToTranslation(Translation* translation,
|
||||
LOperand* op,
|
||||
bool is_tagged,
|
||||
bool is_uint32,
|
||||
bool arguments_known,
|
||||
int arguments_index,
|
||||
int arguments_count) {
|
||||
if (op == NULL) {
|
||||
// TODO(twuerthinger): Introduce marker operands to indicate that this value
|
||||
// is not present and must be reconstructed from the deoptimizer. Currently
|
||||
// this is only used for the arguments object.
|
||||
translation->StoreArgumentsObject(
|
||||
arguments_known, arguments_index, arguments_count);
|
||||
} else if (op->IsStackSlot()) {
|
||||
bool is_uint32) {
|
||||
if (op->IsStackSlot()) {
|
||||
if (is_tagged) {
|
||||
translation->StoreStackSlot(op->index());
|
||||
} else if (is_uint32) {
|
||||
@ -810,8 +785,6 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
|
||||
|
||||
int frame_count = 0;
|
||||
int jsframe_count = 0;
|
||||
int args_index = 0;
|
||||
int args_count = 0;
|
||||
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
|
||||
++frame_count;
|
||||
if (e->frame_type() == JS_FUNCTION) {
|
||||
@ -819,7 +792,7 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
|
||||
}
|
||||
}
|
||||
Translation translation(&translations_, frame_count, jsframe_count, zone());
|
||||
WriteTranslation(environment, &translation, &args_index, &args_count);
|
||||
WriteTranslation(environment, &translation);
|
||||
int deoptimization_index = deoptimizations_.length();
|
||||
int pc_offset = masm()->pc_offset();
|
||||
environment->Register(deoptimization_index,
|
||||
|
@ -171,10 +171,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
int additional_offset);
|
||||
|
||||
// Emit frame translation commands for an environment.
|
||||
void WriteTranslation(LEnvironment* environment,
|
||||
Translation* translation,
|
||||
int* arguments_index,
|
||||
int* arguments_count);
|
||||
void WriteTranslation(LEnvironment* environment, Translation* translation);
|
||||
|
||||
// Declare methods that deal with the individual node types.
|
||||
#define DECLARE_DO(type) void Do##type(L##type* node);
|
||||
@ -293,10 +290,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
void AddToTranslation(Translation* translation,
|
||||
LOperand* op,
|
||||
bool is_tagged,
|
||||
bool is_uint32,
|
||||
bool arguments_known,
|
||||
int arguments_index,
|
||||
int arguments_count);
|
||||
bool is_uint32);
|
||||
void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
|
||||
void PopulateDeoptimizationData(Handle<Code> code);
|
||||
int DefineDeoptimizationLiteral(Handle<Object> literal);
|
||||
|
@ -215,6 +215,8 @@ class GrowableBitVector BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
GrowableBitVector() : bits_(NULL) { }
|
||||
GrowableBitVector(int length, Zone* zone)
|
||||
: bits_(new(zone) BitVector(length, zone)) { }
|
||||
|
||||
bool Contains(int value) const {
|
||||
if (!InBitsRange(value)) return false;
|
||||
|
@ -534,8 +534,9 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
|
||||
output_count_(0),
|
||||
jsframe_count_(0),
|
||||
output_(NULL),
|
||||
deferred_arguments_objects_values_(0),
|
||||
deferred_arguments_objects_(0),
|
||||
deferred_objects_tagged_values_(0),
|
||||
deferred_objects_double_values_(0),
|
||||
deferred_objects_(0),
|
||||
deferred_heap_numbers_(0),
|
||||
trace_(false) {
|
||||
// For COMPILED_STUBs called from builtins, the function pointer is a SMI
|
||||
@ -1566,15 +1567,14 @@ void Deoptimizer::DoComputeCompiledStubFrame(TranslationIterator* iterator,
|
||||
void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
|
||||
ASSERT_NE(DEBUGGER, bailout_type_);
|
||||
|
||||
// Handlify all argument object values before triggering any allocation.
|
||||
List<Handle<Object> > values(deferred_arguments_objects_values_.length());
|
||||
for (int i = 0; i < deferred_arguments_objects_values_.length(); ++i) {
|
||||
values.Add(Handle<Object>(deferred_arguments_objects_values_[i],
|
||||
isolate_));
|
||||
// Handlify all tagged object values before triggering any allocation.
|
||||
List<Handle<Object> > values(deferred_objects_tagged_values_.length());
|
||||
for (int i = 0; i < deferred_objects_tagged_values_.length(); ++i) {
|
||||
values.Add(Handle<Object>(deferred_objects_tagged_values_[i], isolate_));
|
||||
}
|
||||
|
||||
// Play it safe and clear all unhandlified values before we continue.
|
||||
deferred_arguments_objects_values_.Clear();
|
||||
deferred_objects_tagged_values_.Clear();
|
||||
|
||||
// Materialize all heap numbers before looking at arguments because when the
|
||||
// output frames are used to materialize arguments objects later on they need
|
||||
@ -1591,6 +1591,18 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
|
||||
Memory::Object_at(d.slot_address()) = *num;
|
||||
}
|
||||
|
||||
// Materialize all heap numbers required for arguments objects.
|
||||
for (int i = 0; i < values.length(); i++) {
|
||||
if (!values.at(i)->IsTheHole()) continue;
|
||||
double double_value = deferred_objects_double_values_[i];
|
||||
Handle<Object> num = isolate_->factory()->NewNumber(double_value);
|
||||
if (trace_) {
|
||||
PrintF("Materializing a new heap number %p [%e] for arguments object\n",
|
||||
reinterpret_cast<void*>(*num), double_value);
|
||||
}
|
||||
values.Set(i, num);
|
||||
}
|
||||
|
||||
// Materialize arguments objects one frame at a time.
|
||||
for (int frame_index = 0; frame_index < jsframe_count(); ++frame_index) {
|
||||
if (frame_index != 0) it->Advance();
|
||||
@ -1599,9 +1611,9 @@ void Deoptimizer::MaterializeHeapObjects(JavaScriptFrameIterator* it) {
|
||||
Handle<JSObject> arguments;
|
||||
for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
|
||||
if (frame->GetExpression(i) == isolate_->heap()->arguments_marker()) {
|
||||
ArgumentsObjectMaterializationDescriptor descriptor =
|
||||
deferred_arguments_objects_.RemoveLast();
|
||||
const int length = descriptor.arguments_length();
|
||||
ObjectMaterializationDescriptor descriptor =
|
||||
deferred_objects_.RemoveLast();
|
||||
const int length = descriptor.object_length();
|
||||
if (arguments.is_null()) {
|
||||
if (frame->has_adapted_arguments()) {
|
||||
// Use the arguments adapter frame we just built to materialize the
|
||||
@ -1695,7 +1707,7 @@ void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame(
|
||||
#endif
|
||||
|
||||
|
||||
static const char* TraceValueType(bool is_smi, bool is_native) {
|
||||
static const char* TraceValueType(bool is_smi, bool is_native = false) {
|
||||
if (is_native) {
|
||||
return "native";
|
||||
} else if (is_smi) {
|
||||
@ -1706,6 +1718,204 @@ static const char* TraceValueType(bool is_smi, bool is_native) {
|
||||
}
|
||||
|
||||
|
||||
void Deoptimizer::DoTranslateObject(TranslationIterator* iterator,
|
||||
int object_opcode,
|
||||
int field_index) {
|
||||
disasm::NameConverter converter;
|
||||
Address object_slot = deferred_objects_.last().slot_address();
|
||||
|
||||
// Ignore commands marked as duplicate and act on the first non-duplicate.
|
||||
Translation::Opcode opcode =
|
||||
static_cast<Translation::Opcode>(iterator->Next());
|
||||
while (opcode == Translation::DUPLICATE) {
|
||||
opcode = static_cast<Translation::Opcode>(iterator->Next());
|
||||
iterator->Skip(Translation::NumberOfOperandsFor(opcode));
|
||||
opcode = static_cast<Translation::Opcode>(iterator->Next());
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
case Translation::BEGIN:
|
||||
case Translation::JS_FRAME:
|
||||
case Translation::ARGUMENTS_ADAPTOR_FRAME:
|
||||
case Translation::CONSTRUCT_STUB_FRAME:
|
||||
case Translation::GETTER_STUB_FRAME:
|
||||
case Translation::SETTER_STUB_FRAME:
|
||||
case Translation::COMPILED_STUB_FRAME:
|
||||
case Translation::ARGUMENTS_OBJECT:
|
||||
case Translation::DUPLICATE:
|
||||
UNREACHABLE();
|
||||
return;
|
||||
|
||||
case Translation::REGISTER: {
|
||||
int input_reg = iterator->Next();
|
||||
intptr_t input_value = input_->GetRegister(input_reg);
|
||||
if (trace_) {
|
||||
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
||||
reinterpret_cast<intptr_t>(object_slot),
|
||||
field_index);
|
||||
PrintF("0x%08" V8PRIxPTR " ; %s ", input_value,
|
||||
converter.NameOfCPURegister(input_reg));
|
||||
reinterpret_cast<Object*>(input_value)->ShortPrint();
|
||||
PrintF("\n");
|
||||
}
|
||||
AddObjectTaggedValue(input_value);
|
||||
return;
|
||||
}
|
||||
|
||||
case Translation::INT32_REGISTER: {
|
||||
int input_reg = iterator->Next();
|
||||
intptr_t value = input_->GetRegister(input_reg);
|
||||
bool is_smi = Smi::IsValid(value);
|
||||
if (trace_) {
|
||||
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
||||
reinterpret_cast<intptr_t>(object_slot),
|
||||
field_index);
|
||||
PrintF("%" V8PRIdPTR " ; %s (%s)\n", value,
|
||||
converter.NameOfCPURegister(input_reg),
|
||||
TraceValueType(is_smi));
|
||||
}
|
||||
if (is_smi) {
|
||||
intptr_t tagged_value =
|
||||
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
|
||||
AddObjectTaggedValue(tagged_value);
|
||||
} else {
|
||||
double double_value = static_cast<double>(static_cast<int32_t>(value));
|
||||
AddObjectDoubleValue(double_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case Translation::UINT32_REGISTER: {
|
||||
int input_reg = iterator->Next();
|
||||
uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
|
||||
bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
|
||||
if (trace_) {
|
||||
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
||||
reinterpret_cast<intptr_t>(object_slot),
|
||||
field_index);
|
||||
PrintF("%" V8PRIdPTR " ; uint %s (%s)\n", value,
|
||||
converter.NameOfCPURegister(input_reg),
|
||||
TraceValueType(is_smi));
|
||||
}
|
||||
if (is_smi) {
|
||||
intptr_t tagged_value =
|
||||
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
|
||||
AddObjectTaggedValue(tagged_value);
|
||||
} else {
|
||||
double double_value = static_cast<double>(static_cast<uint32_t>(value));
|
||||
AddObjectDoubleValue(double_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case Translation::DOUBLE_REGISTER: {
|
||||
int input_reg = iterator->Next();
|
||||
double value = input_->GetDoubleRegister(input_reg);
|
||||
if (trace_) {
|
||||
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
||||
reinterpret_cast<intptr_t>(object_slot),
|
||||
field_index);
|
||||
PrintF("%e ; %s\n", value,
|
||||
DoubleRegister::AllocationIndexToString(input_reg));
|
||||
}
|
||||
AddObjectDoubleValue(value);
|
||||
return;
|
||||
}
|
||||
|
||||
case Translation::STACK_SLOT: {
|
||||
int input_slot_index = iterator->Next();
|
||||
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
intptr_t input_value = input_->GetFrameSlot(input_offset);
|
||||
if (trace_) {
|
||||
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
||||
reinterpret_cast<intptr_t>(object_slot),
|
||||
field_index);
|
||||
PrintF("0x%08" V8PRIxPTR " ; [sp + %d] ", input_value, input_offset);
|
||||
reinterpret_cast<Object*>(input_value)->ShortPrint();
|
||||
PrintF("\n");
|
||||
}
|
||||
AddObjectTaggedValue(input_value);
|
||||
return;
|
||||
}
|
||||
|
||||
case Translation::INT32_STACK_SLOT: {
|
||||
int input_slot_index = iterator->Next();
|
||||
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
intptr_t value = input_->GetFrameSlot(input_offset);
|
||||
bool is_smi = Smi::IsValid(value);
|
||||
if (trace_) {
|
||||
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
||||
reinterpret_cast<intptr_t>(object_slot),
|
||||
field_index);
|
||||
PrintF("%" V8PRIdPTR " ; [sp + %d] (%s)\n",
|
||||
value, input_offset, TraceValueType(is_smi));
|
||||
}
|
||||
if (is_smi) {
|
||||
intptr_t tagged_value =
|
||||
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
|
||||
AddObjectTaggedValue(tagged_value);
|
||||
} else {
|
||||
double double_value = static_cast<double>(static_cast<int32_t>(value));
|
||||
AddObjectDoubleValue(double_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case Translation::UINT32_STACK_SLOT: {
|
||||
int input_slot_index = iterator->Next();
|
||||
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
uintptr_t value =
|
||||
static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
|
||||
bool is_smi = (value <= static_cast<uintptr_t>(Smi::kMaxValue));
|
||||
if (trace_) {
|
||||
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
||||
reinterpret_cast<intptr_t>(object_slot),
|
||||
field_index);
|
||||
PrintF("%" V8PRIdPTR " ; [sp + %d] (uint %s)\n",
|
||||
value, input_offset, TraceValueType(is_smi));
|
||||
}
|
||||
if (is_smi) {
|
||||
intptr_t tagged_value =
|
||||
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
|
||||
AddObjectTaggedValue(tagged_value);
|
||||
} else {
|
||||
double double_value = static_cast<double>(static_cast<uint32_t>(value));
|
||||
AddObjectDoubleValue(double_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
case Translation::DOUBLE_STACK_SLOT: {
|
||||
int input_slot_index = iterator->Next();
|
||||
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
double value = input_->GetDoubleFrameSlot(input_offset);
|
||||
if (trace_) {
|
||||
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
||||
reinterpret_cast<intptr_t>(object_slot),
|
||||
field_index);
|
||||
PrintF("%e ; [sp + %d]\n", value, input_offset);
|
||||
}
|
||||
AddObjectDoubleValue(value);
|
||||
return;
|
||||
}
|
||||
|
||||
case Translation::LITERAL: {
|
||||
Object* literal = ComputeLiteral(iterator->Next());
|
||||
if (trace_) {
|
||||
PrintF(" object @0x%08" V8PRIxPTR ": [field #%d] <- ",
|
||||
reinterpret_cast<intptr_t>(object_slot),
|
||||
field_index);
|
||||
literal->ShortPrint();
|
||||
PrintF(" ; literal\n");
|
||||
}
|
||||
intptr_t value = reinterpret_cast<intptr_t>(literal);
|
||||
AddObjectTaggedValue(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
||||
int frame_index,
|
||||
unsigned output_offset,
|
||||
@ -1758,7 +1968,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
||||
intptr_t value = input_->GetRegister(input_reg);
|
||||
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
|
||||
Smi::IsValid(value);
|
||||
|
||||
if (trace_) {
|
||||
PrintF(
|
||||
" 0x%08" V8PRIxPTR ": [top + %d] <- %" V8PRIdPTR " ; %s (%s)\n",
|
||||
@ -1836,8 +2045,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
||||
|
||||
case Translation::STACK_SLOT: {
|
||||
int input_slot_index = iterator->Next();
|
||||
unsigned input_offset =
|
||||
input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
intptr_t input_value = input_->GetFrameSlot(input_offset);
|
||||
if (trace_) {
|
||||
PrintF(" 0x%08" V8PRIxPTR ": ",
|
||||
@ -1855,8 +2063,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
||||
|
||||
case Translation::INT32_STACK_SLOT: {
|
||||
int input_slot_index = iterator->Next();
|
||||
unsigned input_offset =
|
||||
input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
intptr_t value = input_->GetFrameSlot(input_offset);
|
||||
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
|
||||
Smi::IsValid(value);
|
||||
@ -1888,8 +2095,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
||||
|
||||
case Translation::UINT32_STACK_SLOT: {
|
||||
int input_slot_index = iterator->Next();
|
||||
unsigned input_offset =
|
||||
input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
uintptr_t value =
|
||||
static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
|
||||
bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
|
||||
@ -1922,8 +2128,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
||||
|
||||
case Translation::DOUBLE_STACK_SLOT: {
|
||||
int input_slot_index = iterator->Next();
|
||||
unsigned input_offset =
|
||||
input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
|
||||
double value = input_->GetDoubleFrameSlot(input_offset);
|
||||
if (trace_) {
|
||||
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [sp + %d]\n",
|
||||
@ -1954,31 +2159,24 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
||||
}
|
||||
|
||||
case Translation::ARGUMENTS_OBJECT: {
|
||||
bool args_known = iterator->Next();
|
||||
int args_index = iterator->Next() + 1; // Skip receiver.
|
||||
int args_length = iterator->Next() - 1; // Skip receiver.
|
||||
int length = iterator->Next();
|
||||
if (trace_) {
|
||||
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
|
||||
output_[frame_index]->GetTop() + output_offset,
|
||||
output_offset);
|
||||
isolate_->heap()->arguments_marker()->ShortPrint();
|
||||
PrintF(" ; %sarguments object\n", args_known ? "" : "dummy ");
|
||||
PrintF(" ; arguments object (length = %d)\n", length);
|
||||
}
|
||||
// Use the arguments marker value as a sentinel and fill in the arguments
|
||||
// object after the deoptimized frame is built.
|
||||
intptr_t value = reinterpret_cast<intptr_t>(
|
||||
isolate_->heap()->arguments_marker());
|
||||
AddArgumentsObject(
|
||||
output_[frame_index]->GetTop() + output_offset, args_length);
|
||||
AddObjectStart(output_[frame_index]->GetTop() + output_offset, length);
|
||||
output_[frame_index]->SetFrameSlot(output_offset, value);
|
||||
// We save the tagged argument values on the side and materialize the
|
||||
// actual arguments object after the deoptimized frame is built.
|
||||
for (int i = 0; i < args_length; i++) {
|
||||
unsigned input_offset = input_->GetOffsetFromSlotIndex(args_index + i);
|
||||
intptr_t input_value = args_known
|
||||
? input_->GetFrameSlot(input_offset)
|
||||
: reinterpret_cast<intptr_t>(isolate_->heap()->the_hole_value());
|
||||
AddArgumentsObjectValue(input_value);
|
||||
// We save the argument values on the side and materialize the actual
|
||||
// arguments object after the deoptimized frame is built.
|
||||
for (int i = 0; i < length; i++) {
|
||||
DoTranslateObject(iterator, Translation::ARGUMENTS_OBJECT, i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -2324,15 +2522,22 @@ Object* Deoptimizer::ComputeLiteral(int index) const {
|
||||
}
|
||||
|
||||
|
||||
void Deoptimizer::AddArgumentsObject(intptr_t slot_address, int argc) {
|
||||
ArgumentsObjectMaterializationDescriptor object_desc(
|
||||
reinterpret_cast<Address>(slot_address), argc);
|
||||
deferred_arguments_objects_.Add(object_desc);
|
||||
void Deoptimizer::AddObjectStart(intptr_t slot_address, int length) {
|
||||
ObjectMaterializationDescriptor object_desc(
|
||||
reinterpret_cast<Address>(slot_address), length);
|
||||
deferred_objects_.Add(object_desc);
|
||||
}
|
||||
|
||||
|
||||
void Deoptimizer::AddArgumentsObjectValue(intptr_t value) {
|
||||
deferred_arguments_objects_values_.Add(reinterpret_cast<Object*>(value));
|
||||
void Deoptimizer::AddObjectTaggedValue(intptr_t value) {
|
||||
deferred_objects_tagged_values_.Add(reinterpret_cast<Object*>(value));
|
||||
deferred_objects_double_values_.Add(isolate()->heap()->nan_value()->value());
|
||||
}
|
||||
|
||||
|
||||
void Deoptimizer::AddObjectDoubleValue(double value) {
|
||||
deferred_objects_tagged_values_.Add(isolate()->heap()->the_hole_value());
|
||||
deferred_objects_double_values_.Add(value);
|
||||
}
|
||||
|
||||
|
||||
@ -2556,6 +2761,12 @@ void Translation::BeginCompiledStubFrame() {
|
||||
}
|
||||
|
||||
|
||||
void Translation::BeginArgumentsObject(int args_length) {
|
||||
buffer_->Add(ARGUMENTS_OBJECT, zone());
|
||||
buffer_->Add(args_length, zone());
|
||||
}
|
||||
|
||||
|
||||
void Translation::StoreRegister(Register reg) {
|
||||
buffer_->Add(REGISTER, zone());
|
||||
buffer_->Add(reg.code(), zone());
|
||||
@ -2610,16 +2821,6 @@ void Translation::StoreLiteral(int literal_id) {
|
||||
}
|
||||
|
||||
|
||||
void Translation::StoreArgumentsObject(bool args_known,
|
||||
int args_index,
|
||||
int args_length) {
|
||||
buffer_->Add(ARGUMENTS_OBJECT, zone());
|
||||
buffer_->Add(args_known, zone());
|
||||
buffer_->Add(args_index, zone());
|
||||
buffer_->Add(args_length, zone());
|
||||
}
|
||||
|
||||
|
||||
void Translation::MarkDuplicate() {
|
||||
buffer_->Add(DUPLICATE, zone());
|
||||
}
|
||||
@ -2631,6 +2832,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
|
||||
return 0;
|
||||
case GETTER_STUB_FRAME:
|
||||
case SETTER_STUB_FRAME:
|
||||
case ARGUMENTS_OBJECT:
|
||||
case REGISTER:
|
||||
case INT32_REGISTER:
|
||||
case UINT32_REGISTER:
|
||||
@ -2647,7 +2849,6 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
|
||||
case CONSTRUCT_STUB_FRAME:
|
||||
return 2;
|
||||
case JS_FRAME:
|
||||
case ARGUMENTS_OBJECT:
|
||||
return 3;
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
@ -75,17 +75,17 @@ class HeapNumberMaterializationDescriptor BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
|
||||
class ArgumentsObjectMaterializationDescriptor BASE_EMBEDDED {
|
||||
class ObjectMaterializationDescriptor BASE_EMBEDDED {
|
||||
public:
|
||||
ArgumentsObjectMaterializationDescriptor(Address slot_address, int argc)
|
||||
: slot_address_(slot_address), arguments_length_(argc) { }
|
||||
ObjectMaterializationDescriptor(Address slot_address, int length)
|
||||
: slot_address_(slot_address), object_length_(length) { }
|
||||
|
||||
Address slot_address() const { return slot_address_; }
|
||||
int arguments_length() const { return arguments_length_; }
|
||||
int object_length() const { return object_length_; }
|
||||
|
||||
private:
|
||||
Address slot_address_;
|
||||
int arguments_length_;
|
||||
int object_length_;
|
||||
};
|
||||
|
||||
|
||||
@ -369,6 +369,10 @@ class Deoptimizer : public Malloced {
|
||||
void DoComputeCompiledStubFrame(TranslationIterator* iterator,
|
||||
int frame_index);
|
||||
|
||||
void DoTranslateObject(TranslationIterator* iterator,
|
||||
int object_opcode,
|
||||
int field_index);
|
||||
|
||||
enum DeoptimizerTranslatedValueType {
|
||||
TRANSLATED_VALUE_IS_NATIVE,
|
||||
TRANSLATED_VALUE_IS_TAGGED
|
||||
@ -394,8 +398,9 @@ class Deoptimizer : public Malloced {
|
||||
|
||||
Object* ComputeLiteral(int index) const;
|
||||
|
||||
void AddArgumentsObject(intptr_t slot_address, int argc);
|
||||
void AddArgumentsObjectValue(intptr_t value);
|
||||
void AddObjectStart(intptr_t slot_address, int argc);
|
||||
void AddObjectTaggedValue(intptr_t value);
|
||||
void AddObjectDoubleValue(double value);
|
||||
void AddDoubleValue(intptr_t slot_address, double value);
|
||||
|
||||
static void GenerateDeoptimizationEntries(
|
||||
@ -446,8 +451,9 @@ class Deoptimizer : public Malloced {
|
||||
// Array of output frame descriptions.
|
||||
FrameDescription** output_;
|
||||
|
||||
List<Object*> deferred_arguments_objects_values_;
|
||||
List<ArgumentsObjectMaterializationDescriptor> deferred_arguments_objects_;
|
||||
List<Object*> deferred_objects_tagged_values_;
|
||||
List<double> deferred_objects_double_values_;
|
||||
List<ObjectMaterializationDescriptor> deferred_objects_;
|
||||
List<HeapNumberMaterializationDescriptor> deferred_heap_numbers_;
|
||||
#ifdef DEBUG
|
||||
DisallowHeapAllocation* disallow_heap_allocation_;
|
||||
@ -698,6 +704,7 @@ class Translation BASE_EMBEDDED {
|
||||
SETTER_STUB_FRAME,
|
||||
ARGUMENTS_ADAPTOR_FRAME,
|
||||
COMPILED_STUB_FRAME,
|
||||
ARGUMENTS_OBJECT,
|
||||
REGISTER,
|
||||
INT32_REGISTER,
|
||||
UINT32_REGISTER,
|
||||
@ -707,7 +714,6 @@ class Translation BASE_EMBEDDED {
|
||||
UINT32_STACK_SLOT,
|
||||
DOUBLE_STACK_SLOT,
|
||||
LITERAL,
|
||||
ARGUMENTS_OBJECT,
|
||||
|
||||
// A prefix indicating that the next command is a duplicate of the one
|
||||
// that follows it.
|
||||
@ -733,6 +739,7 @@ class Translation BASE_EMBEDDED {
|
||||
void BeginConstructStubFrame(int literal_id, unsigned height);
|
||||
void BeginGetterStubFrame(int literal_id);
|
||||
void BeginSetterStubFrame(int literal_id);
|
||||
void BeginArgumentsObject(int args_length);
|
||||
void StoreRegister(Register reg);
|
||||
void StoreInt32Register(Register reg);
|
||||
void StoreUint32Register(Register reg);
|
||||
@ -742,7 +749,6 @@ class Translation BASE_EMBEDDED {
|
||||
void StoreUint32StackSlot(int index);
|
||||
void StoreDoubleStackSlot(int index);
|
||||
void StoreLiteral(int literal_id);
|
||||
void StoreArgumentsObject(bool args_known, int args_index, int args_length);
|
||||
void MarkDuplicate();
|
||||
|
||||
Zone* zone() const { return zone_; }
|
||||
|
@ -2016,6 +2016,9 @@ enum InliningKind {
|
||||
};
|
||||
|
||||
|
||||
class HArgumentsObject;
|
||||
|
||||
|
||||
class HEnterInlined: public HTemplateInstruction<0> {
|
||||
public:
|
||||
HEnterInlined(Handle<JSFunction> closure,
|
||||
@ -2023,7 +2026,7 @@ class HEnterInlined: public HTemplateInstruction<0> {
|
||||
FunctionLiteral* function,
|
||||
InliningKind inlining_kind,
|
||||
Variable* arguments_var,
|
||||
ZoneList<HValue*>* arguments_values,
|
||||
HArgumentsObject* arguments_object,
|
||||
bool undefined_receiver,
|
||||
Zone* zone)
|
||||
: closure_(closure),
|
||||
@ -2032,7 +2035,7 @@ class HEnterInlined: public HTemplateInstruction<0> {
|
||||
function_(function),
|
||||
inlining_kind_(inlining_kind),
|
||||
arguments_var_(arguments_var),
|
||||
arguments_values_(arguments_values),
|
||||
arguments_object_(arguments_object),
|
||||
undefined_receiver_(undefined_receiver),
|
||||
return_targets_(2, zone) {
|
||||
}
|
||||
@ -2055,7 +2058,7 @@ class HEnterInlined: public HTemplateInstruction<0> {
|
||||
}
|
||||
|
||||
Variable* arguments_var() { return arguments_var_; }
|
||||
ZoneList<HValue*>* arguments_values() { return arguments_values_; }
|
||||
HArgumentsObject* arguments_object() { return arguments_object_; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
|
||||
|
||||
@ -2066,7 +2069,7 @@ class HEnterInlined: public HTemplateInstruction<0> {
|
||||
FunctionLiteral* function_;
|
||||
InliningKind inlining_kind_;
|
||||
Variable* arguments_var_;
|
||||
ZoneList<HValue*>* arguments_values_;
|
||||
HArgumentsObject* arguments_object_;
|
||||
bool undefined_receiver_;
|
||||
ZoneList<HBasicBlock*> return_targets_;
|
||||
};
|
||||
@ -3202,19 +3205,37 @@ class HInductionVariableAnnotation : public HUnaryOperation {
|
||||
|
||||
class HArgumentsObject: public HTemplateInstruction<0> {
|
||||
public:
|
||||
HArgumentsObject() {
|
||||
HArgumentsObject(int count, Zone* zone) : values_(count, zone) {
|
||||
set_representation(Representation::Tagged());
|
||||
SetFlag(kIsArguments);
|
||||
}
|
||||
|
||||
const ZoneList<HValue*>* arguments_values() const { return &values_; }
|
||||
int arguments_count() const { return values_.length(); }
|
||||
|
||||
void AddArgument(HValue* argument, Zone* zone) {
|
||||
values_.Add(NULL, zone); // Resize list.
|
||||
SetOperandAt(values_.length() - 1, argument);
|
||||
}
|
||||
|
||||
virtual int OperandCount() { return values_.length(); }
|
||||
virtual HValue* OperandAt(int index) const { return values_[index]; }
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
return Representation::None();
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(ArgumentsObject)
|
||||
|
||||
protected:
|
||||
virtual void InternalSetOperandAt(int index, HValue* value) {
|
||||
values_[index] = value;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual bool IsDeletable() const { return true; }
|
||||
|
||||
ZoneList<HValue*> values_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -3550,6 +3550,7 @@ FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
|
||||
function_return_(NULL),
|
||||
test_context_(NULL),
|
||||
entry_(NULL),
|
||||
arguments_object_(NULL),
|
||||
arguments_elements_(NULL),
|
||||
outer_(owner->function_state()) {
|
||||
if (outer_ != NULL) {
|
||||
@ -4701,18 +4702,18 @@ void HOptimizedGraphBuilder::SetUpScope(Scope* scope) {
|
||||
AddInstruction(undefined_constant);
|
||||
graph()->set_undefined_constant(undefined_constant);
|
||||
|
||||
HArgumentsObject* object = new(zone()) HArgumentsObject;
|
||||
AddInstruction(object);
|
||||
graph()->SetArgumentsObject(object);
|
||||
|
||||
// Set the initial values of parameters including "this". "This" has
|
||||
// parameter index 0.
|
||||
// Create an arguments object containing the initial parameters. Set the
|
||||
// initial values of parameters including "this" having parameter index 0.
|
||||
ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
|
||||
|
||||
HArgumentsObject* arguments_object =
|
||||
new(zone()) HArgumentsObject(environment()->parameter_count(), zone());
|
||||
for (int i = 0; i < environment()->parameter_count(); ++i) {
|
||||
HInstruction* parameter = AddInstruction(new(zone()) HParameter(i));
|
||||
arguments_object->AddArgument(parameter, zone());
|
||||
environment()->Bind(i, parameter);
|
||||
}
|
||||
AddInstruction(arguments_object);
|
||||
graph()->SetArgumentsObject(arguments_object);
|
||||
|
||||
// First special is HContext.
|
||||
HInstruction* context = AddInstruction(new(zone()) HContext);
|
||||
@ -7432,7 +7433,8 @@ void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() {
|
||||
HEnterInlined* entry = function_state()->entry();
|
||||
entry->set_arguments_pushed();
|
||||
|
||||
ZoneList<HValue*>* arguments_values = entry->arguments_values();
|
||||
HArgumentsObject* arguments = entry->arguments_object();
|
||||
const ZoneList<HValue*>* arguments_values = arguments->arguments_values();
|
||||
|
||||
HInstruction* insert_after = entry;
|
||||
for (int i = 0; i < arguments_values->length(); i++) {
|
||||
@ -8033,17 +8035,20 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
||||
|
||||
AddSimulate(return_id);
|
||||
current_block()->UpdateEnvironment(inner_env);
|
||||
ZoneList<HValue*>* arguments_values = NULL;
|
||||
HArgumentsObject* arguments_object = NULL;
|
||||
|
||||
// If the function uses arguments copy current arguments values
|
||||
// to use them for materialization.
|
||||
// If the function uses arguments object create and bind one, also copy
|
||||
// current arguments values to use them for materialization.
|
||||
if (function->scope()->arguments() != NULL) {
|
||||
ASSERT(function->scope()->arguments()->IsStackAllocated());
|
||||
HEnvironment* arguments_env = inner_env->arguments_environment();
|
||||
int arguments_count = arguments_env->parameter_count();
|
||||
arguments_values = new(zone()) ZoneList<HValue*>(arguments_count, zone());
|
||||
arguments_object = new(zone()) HArgumentsObject(arguments_count, zone());
|
||||
inner_env->Bind(function->scope()->arguments(), arguments_object);
|
||||
for (int i = 0; i < arguments_count; i++) {
|
||||
arguments_values->Add(arguments_env->Lookup(i), zone());
|
||||
arguments_object->AddArgument(arguments_env->Lookup(i), zone());
|
||||
}
|
||||
AddInstruction(arguments_object);
|
||||
}
|
||||
|
||||
HEnterInlined* enter_inlined =
|
||||
@ -8052,20 +8057,12 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
|
||||
function,
|
||||
function_state()->inlining_kind(),
|
||||
function->scope()->arguments(),
|
||||
arguments_values,
|
||||
arguments_object,
|
||||
undefined_receiver,
|
||||
zone());
|
||||
function_state()->set_entry(enter_inlined);
|
||||
AddInstruction(enter_inlined);
|
||||
|
||||
// If the function uses arguments object create and bind one.
|
||||
if (function->scope()->arguments() != NULL) {
|
||||
ASSERT(function->scope()->arguments()->IsStackAllocated());
|
||||
inner_env->Bind(function->scope()->arguments(),
|
||||
graph()->GetArgumentsObject());
|
||||
}
|
||||
|
||||
|
||||
VisitDeclarations(target_info.scope()->declarations());
|
||||
VisitStatements(function->body());
|
||||
if (HasStackOverflow()) {
|
||||
@ -8497,13 +8494,10 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
|
||||
} else {
|
||||
// We are inside inlined function and we know exactly what is inside
|
||||
// arguments object. But we need to be able to materialize at deopt.
|
||||
// TODO(mstarzinger): For now we just ensure arguments are pushed
|
||||
// right after HEnterInlined, but we could be smarter about this.
|
||||
EnsureArgumentsArePushedForAccess();
|
||||
ASSERT_EQ(environment()->arguments_environment()->parameter_count(),
|
||||
function_state()->entry()->arguments_values()->length());
|
||||
HEnterInlined* entry = function_state()->entry();
|
||||
ZoneList<HValue*>* arguments_values = entry->arguments_values();
|
||||
function_state()->entry()->arguments_object()->arguments_count());
|
||||
HArgumentsObject* args = function_state()->entry()->arguments_object();
|
||||
const ZoneList<HValue*>* arguments_values = args->arguments_values();
|
||||
int arguments_count = arguments_values->length();
|
||||
PushAndAdd(new(zone()) HWrapReceiver(receiver, function));
|
||||
for (int i = 1; i < arguments_count; i++) {
|
||||
@ -11008,6 +11002,7 @@ HEnvironment::HEnvironment(HEnvironment* outer,
|
||||
values_(arguments, zone),
|
||||
frame_type_(frame_type),
|
||||
parameter_count_(arguments),
|
||||
specials_count_(0),
|
||||
local_count_(0),
|
||||
outer_(outer),
|
||||
entry_(NULL),
|
||||
|
@ -260,6 +260,7 @@ class HLoopInformation: public ZoneObject {
|
||||
HStackCheck* stack_check_;
|
||||
};
|
||||
|
||||
|
||||
class BoundsCheckTable;
|
||||
class HGraph: public ZoneObject {
|
||||
public:
|
||||
@ -411,6 +412,10 @@ class HGraph: public ZoneObject {
|
||||
depends_on_empty_array_proto_elements_ = true;
|
||||
}
|
||||
|
||||
bool depends_on_empty_array_proto_elements() {
|
||||
return depends_on_empty_array_proto_elements_;
|
||||
}
|
||||
|
||||
void RecordUint32Instruction(HInstruction* instr) {
|
||||
if (uint32_instructions_ == NULL) {
|
||||
uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone());
|
||||
@ -876,6 +881,11 @@ class FunctionState {
|
||||
HEnterInlined* entry() { return entry_; }
|
||||
void set_entry(HEnterInlined* entry) { entry_ = entry; }
|
||||
|
||||
HArgumentsObject* arguments_object() { return arguments_object_; }
|
||||
void set_arguments_object(HArgumentsObject* arguments_object) {
|
||||
arguments_object_ = arguments_object;
|
||||
}
|
||||
|
||||
HArgumentsElements* arguments_elements() { return arguments_elements_; }
|
||||
void set_arguments_elements(HArgumentsElements* arguments_elements) {
|
||||
arguments_elements_ = arguments_elements;
|
||||
@ -909,6 +919,7 @@ class FunctionState {
|
||||
// entry.
|
||||
HEnterInlined* entry_;
|
||||
|
||||
HArgumentsObject* arguments_object_;
|
||||
HArgumentsElements* arguments_elements_;
|
||||
|
||||
FunctionState* outer_;
|
||||
|
@ -614,27 +614,15 @@ Operand LCodeGen::HighOperand(LOperand* op) {
|
||||
|
||||
|
||||
void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
Translation* translation,
|
||||
int* pushed_arguments_index,
|
||||
int* pushed_arguments_count) {
|
||||
Translation* translation) {
|
||||
if (environment == NULL) return;
|
||||
|
||||
// The translation includes one command per value in the environment.
|
||||
int translation_size = environment->values()->length();
|
||||
int translation_size = environment->translation_size();
|
||||
// The output frame height does not include the parameters.
|
||||
int height = translation_size - environment->parameter_count();
|
||||
|
||||
// Function parameters are arguments to the outermost environment. The
|
||||
// arguments index points to the first element of a sequence of tagged
|
||||
// values on the stack that represent the arguments. This needs to be
|
||||
// kept in sync with the LArgumentsElements implementation.
|
||||
*pushed_arguments_index = -environment->parameter_count();
|
||||
*pushed_arguments_count = environment->parameter_count();
|
||||
|
||||
WriteTranslation(environment->outer(),
|
||||
translation,
|
||||
pushed_arguments_index,
|
||||
pushed_arguments_count);
|
||||
WriteTranslation(environment->outer(), translation);
|
||||
bool has_closure_id = !info()->closure().is_null() &&
|
||||
!info()->closure().is_identical_to(environment->closure());
|
||||
int closure_id = has_closure_id
|
||||
@ -667,23 +655,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// Inlined frames which push their arguments cause the index to be
|
||||
// bumped and another stack area to be used for materialization,
|
||||
// otherwise actual argument values are unknown for inlined frames.
|
||||
bool arguments_known = true;
|
||||
int arguments_index = *pushed_arguments_index;
|
||||
int arguments_count = *pushed_arguments_count;
|
||||
if (environment->entry() != NULL) {
|
||||
arguments_known = environment->entry()->arguments_pushed();
|
||||
arguments_index = arguments_index < 0
|
||||
? GetStackSlotCount() : arguments_index + arguments_count;
|
||||
arguments_count = environment->entry()->arguments_count() + 1;
|
||||
if (environment->entry()->arguments_pushed()) {
|
||||
*pushed_arguments_index = arguments_index;
|
||||
*pushed_arguments_count = arguments_count;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < translation_size; ++i) {
|
||||
LOperand* value = environment->values()->at(i);
|
||||
// spilled_registers_ and spilled_double_registers_ are either
|
||||
@ -695,10 +666,7 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
AddToTranslation(translation,
|
||||
environment->spilled_registers()[value->index()],
|
||||
environment->HasTaggedValueAt(i),
|
||||
environment->HasUint32ValueAt(i),
|
||||
arguments_known,
|
||||
arguments_index,
|
||||
arguments_count);
|
||||
environment->HasUint32ValueAt(i));
|
||||
} else if (
|
||||
value->IsDoubleRegister() &&
|
||||
environment->spilled_double_registers()[value->index()] != NULL) {
|
||||
@ -707,20 +675,36 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
translation,
|
||||
environment->spilled_double_registers()[value->index()],
|
||||
false,
|
||||
false,
|
||||
arguments_known,
|
||||
arguments_index,
|
||||
arguments_count);
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mstarzinger): Introduce marker operands to indicate that this value
|
||||
// is not present and must be reconstructed from the deoptimizer. Currently
|
||||
// this is only used for the arguments object.
|
||||
if (value == NULL) {
|
||||
int arguments_count = environment->values()->length() - translation_size;
|
||||
translation->BeginArgumentsObject(arguments_count);
|
||||
for (int i = 0; i < arguments_count; ++i) {
|
||||
LOperand* value = environment->values()->at(translation_size + i);
|
||||
ASSERT(environment->spilled_registers() == NULL ||
|
||||
!value->IsRegister() ||
|
||||
environment->spilled_registers()[value->index()] == NULL);
|
||||
ASSERT(environment->spilled_registers() == NULL ||
|
||||
!value->IsDoubleRegister() ||
|
||||
environment->spilled_double_registers()[value->index()] == NULL);
|
||||
AddToTranslation(translation,
|
||||
value,
|
||||
environment->HasTaggedValueAt(translation_size + i),
|
||||
environment->HasUint32ValueAt(translation_size + i));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
AddToTranslation(translation,
|
||||
value,
|
||||
environment->HasTaggedValueAt(i),
|
||||
environment->HasUint32ValueAt(i),
|
||||
arguments_known,
|
||||
arguments_index,
|
||||
arguments_count);
|
||||
environment->HasUint32ValueAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -728,17 +712,8 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
void LCodeGen::AddToTranslation(Translation* translation,
|
||||
LOperand* op,
|
||||
bool is_tagged,
|
||||
bool is_uint32,
|
||||
bool arguments_known,
|
||||
int arguments_index,
|
||||
int arguments_count) {
|
||||
if (op == NULL) {
|
||||
// TODO(twuerthinger): Introduce marker operands to indicate that this value
|
||||
// is not present and must be reconstructed from the deoptimizer. Currently
|
||||
// this is only used for the arguments object.
|
||||
translation->StoreArgumentsObject(
|
||||
arguments_known, arguments_index, arguments_count);
|
||||
} else if (op->IsStackSlot()) {
|
||||
bool is_uint32) {
|
||||
if (op->IsStackSlot()) {
|
||||
if (is_tagged) {
|
||||
translation->StoreStackSlot(op->index());
|
||||
} else if (is_uint32) {
|
||||
@ -864,8 +839,6 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(
|
||||
|
||||
int frame_count = 0;
|
||||
int jsframe_count = 0;
|
||||
int args_index = 0;
|
||||
int args_count = 0;
|
||||
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
|
||||
++frame_count;
|
||||
if (e->frame_type() == JS_FUNCTION) {
|
||||
@ -873,7 +846,7 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(
|
||||
}
|
||||
}
|
||||
Translation translation(&translations_, frame_count, jsframe_count, zone());
|
||||
WriteTranslation(environment, &translation, &args_index, &args_count);
|
||||
WriteTranslation(environment, &translation);
|
||||
int deoptimization_index = deoptimizations_.length();
|
||||
int pc_offset = masm()->pc_offset();
|
||||
environment->Register(deoptimization_index,
|
||||
|
@ -168,10 +168,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
void DoGap(LGap* instr);
|
||||
|
||||
// Emit frame translation commands for an environment.
|
||||
void WriteTranslation(LEnvironment* environment,
|
||||
Translation* translation,
|
||||
int* arguments_index,
|
||||
int* arguments_count);
|
||||
void WriteTranslation(LEnvironment* environment, Translation* translation);
|
||||
|
||||
void EnsureRelocSpaceForDeoptimization();
|
||||
|
||||
@ -285,10 +282,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
void AddToTranslation(Translation* translation,
|
||||
LOperand* op,
|
||||
bool is_tagged,
|
||||
bool is_uint32,
|
||||
bool arguments_known,
|
||||
int arguments_index,
|
||||
int arguments_count);
|
||||
bool is_uint32);
|
||||
void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
|
||||
void PopulateDeoptimizationData(Handle<Code> code);
|
||||
int DefineDeoptimizationLiteral(Handle<Object> literal);
|
||||
|
@ -990,7 +990,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
||||
BailoutId ast_id = hydrogen_env->ast_id();
|
||||
ASSERT(!ast_id.IsNone() ||
|
||||
hydrogen_env->frame_type() != JS_FUNCTION);
|
||||
int value_count = hydrogen_env->length();
|
||||
int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
|
||||
LEnvironment* result =
|
||||
new(zone()) LEnvironment(hydrogen_env->closure(),
|
||||
hydrogen_env->frame_type(),
|
||||
@ -1001,13 +1001,15 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
||||
outer,
|
||||
hydrogen_env->entry(),
|
||||
zone());
|
||||
bool needs_arguments_object_materialization = false;
|
||||
int argument_index = *argument_index_accumulator;
|
||||
for (int i = 0; i < value_count; ++i) {
|
||||
for (int i = 0; i < hydrogen_env->length(); ++i) {
|
||||
if (hydrogen_env->is_special_index(i)) continue;
|
||||
|
||||
HValue* value = hydrogen_env->values()->at(i);
|
||||
LOperand* op = NULL;
|
||||
if (value->IsArgumentsObject()) {
|
||||
needs_arguments_object_materialization = true;
|
||||
op = NULL;
|
||||
} else if (value->IsPushArgument()) {
|
||||
op = new(zone()) LArgument(argument_index++);
|
||||
@ -1019,6 +1021,22 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
||||
value->CheckFlag(HInstruction::kUint32));
|
||||
}
|
||||
|
||||
if (needs_arguments_object_materialization) {
|
||||
HArgumentsObject* arguments = hydrogen_env->entry() == NULL
|
||||
? graph()->GetArgumentsObject()
|
||||
: hydrogen_env->entry()->arguments_object();
|
||||
ASSERT(arguments->IsLinked());
|
||||
for (int i = 1; i < arguments->arguments_count(); ++i) {
|
||||
HValue* value = arguments->arguments_values()->at(i);
|
||||
ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument());
|
||||
ASSERT(HInstruction::cast(value)->IsLinked());
|
||||
LOperand* op = UseAny(value);
|
||||
result->AddValue(op,
|
||||
value->representation(),
|
||||
value->CheckFlag(HInstruction::kUint32));
|
||||
}
|
||||
}
|
||||
|
||||
if (hydrogen_env->frame_type() == JS_FUNCTION) {
|
||||
*argument_index_accumulator = argument_index;
|
||||
}
|
||||
|
@ -527,6 +527,7 @@ class LEnvironment: public ZoneObject {
|
||||
deoptimization_index_(Safepoint::kNoDeoptimizationIndex),
|
||||
translation_index_(-1),
|
||||
ast_id_(ast_id),
|
||||
translation_size_(value_count),
|
||||
parameter_count_(parameter_count),
|
||||
pc_offset_(-1),
|
||||
values_(value_count, zone),
|
||||
@ -544,6 +545,7 @@ class LEnvironment: public ZoneObject {
|
||||
int deoptimization_index() const { return deoptimization_index_; }
|
||||
int translation_index() const { return translation_index_; }
|
||||
BailoutId ast_id() const { return ast_id_; }
|
||||
int translation_size() const { return translation_size_; }
|
||||
int parameter_count() const { return parameter_count_; }
|
||||
int pc_offset() const { return pc_offset_; }
|
||||
LOperand** spilled_registers() const { return spilled_registers_; }
|
||||
@ -553,6 +555,7 @@ class LEnvironment: public ZoneObject {
|
||||
const ZoneList<LOperand*>* values() const { return &values_; }
|
||||
LEnvironment* outer() const { return outer_; }
|
||||
HEnterInlined* entry() { return entry_; }
|
||||
Zone* zone() const { return zone_; }
|
||||
|
||||
void AddValue(LOperand* operand,
|
||||
Representation representation,
|
||||
@ -560,11 +563,11 @@ class LEnvironment: public ZoneObject {
|
||||
values_.Add(operand, zone());
|
||||
if (representation.IsSmiOrTagged()) {
|
||||
ASSERT(!is_uint32);
|
||||
is_tagged_.Add(values_.length() - 1);
|
||||
is_tagged_.Add(values_.length() - 1, zone());
|
||||
}
|
||||
|
||||
if (is_uint32) {
|
||||
is_uint32_.Add(values_.length() - 1);
|
||||
is_uint32_.Add(values_.length() - 1, zone());
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,8 +599,6 @@ class LEnvironment: public ZoneObject {
|
||||
|
||||
void PrintTo(StringStream* stream);
|
||||
|
||||
Zone* zone() const { return zone_; }
|
||||
|
||||
private:
|
||||
Handle<JSFunction> closure_;
|
||||
FrameType frame_type_;
|
||||
@ -605,11 +606,15 @@ class LEnvironment: public ZoneObject {
|
||||
int deoptimization_index_;
|
||||
int translation_index_;
|
||||
BailoutId ast_id_;
|
||||
int translation_size_;
|
||||
int parameter_count_;
|
||||
int pc_offset_;
|
||||
|
||||
// Value array: [parameters] [locals] [expression stack] [de-materialized].
|
||||
// |>--------- translation_size ---------<|
|
||||
ZoneList<LOperand*> values_;
|
||||
BitVector is_tagged_;
|
||||
BitVector is_uint32_;
|
||||
GrowableBitVector is_tagged_;
|
||||
GrowableBitVector is_uint32_;
|
||||
|
||||
// Allocation index indexed arrays of spill slot operands for registers
|
||||
// that are also in spill slots at an OSR entry. NULL for environments
|
||||
@ -619,7 +624,6 @@ class LEnvironment: public ZoneObject {
|
||||
|
||||
LEnvironment* outer_;
|
||||
HEnterInlined* entry_;
|
||||
|
||||
Zone* zone_;
|
||||
};
|
||||
|
||||
|
@ -1385,7 +1385,7 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
|
||||
global_object ? "Global Object: " : "",
|
||||
vowel ? "n" : "");
|
||||
accumulator->Put(str);
|
||||
accumulator->Add(" with %smap 0x%p",
|
||||
accumulator->Add(" with %smap %p",
|
||||
map_of_this->is_deprecated() ? "deprecated " : "",
|
||||
map_of_this);
|
||||
printed = true;
|
||||
@ -10550,11 +10550,8 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
|
||||
}
|
||||
|
||||
case Translation::ARGUMENTS_OBJECT: {
|
||||
bool args_known = iterator.Next();
|
||||
int args_index = iterator.Next();
|
||||
int args_length = iterator.Next();
|
||||
PrintF(out, "{index=%d, length=%d, known=%d}",
|
||||
args_index, args_length, args_known);
|
||||
PrintF(out, "{length=%d}", args_length);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -469,27 +469,15 @@ Operand LCodeGen::ToOperand(LOperand* op) const {
|
||||
|
||||
|
||||
void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
Translation* translation,
|
||||
int* pushed_arguments_index,
|
||||
int* pushed_arguments_count) {
|
||||
Translation* translation) {
|
||||
if (environment == NULL) return;
|
||||
|
||||
// The translation includes one command per value in the environment.
|
||||
int translation_size = environment->values()->length();
|
||||
int translation_size = environment->translation_size();
|
||||
// The output frame height does not include the parameters.
|
||||
int height = translation_size - environment->parameter_count();
|
||||
|
||||
// Function parameters are arguments to the outermost environment. The
|
||||
// arguments index points to the first element of a sequence of tagged
|
||||
// values on the stack that represent the arguments. This needs to be
|
||||
// kept in sync with the LArgumentsElements implementation.
|
||||
*pushed_arguments_index = -environment->parameter_count();
|
||||
*pushed_arguments_count = environment->parameter_count();
|
||||
|
||||
WriteTranslation(environment->outer(),
|
||||
translation,
|
||||
pushed_arguments_index,
|
||||
pushed_arguments_count);
|
||||
WriteTranslation(environment->outer(), translation);
|
||||
bool has_closure_id = !info()->closure().is_null() &&
|
||||
!info()->closure().is_identical_to(environment->closure());
|
||||
int closure_id = has_closure_id
|
||||
@ -521,23 +509,6 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
break;
|
||||
}
|
||||
|
||||
// Inlined frames which push their arguments cause the index to be
|
||||
// bumped and another stack area to be used for materialization,
|
||||
// otherwise actual argument values are unknown for inlined frames.
|
||||
bool arguments_known = true;
|
||||
int arguments_index = *pushed_arguments_index;
|
||||
int arguments_count = *pushed_arguments_count;
|
||||
if (environment->entry() != NULL) {
|
||||
arguments_known = environment->entry()->arguments_pushed();
|
||||
arguments_index = arguments_index < 0
|
||||
? GetStackSlotCount() : arguments_index + arguments_count;
|
||||
arguments_count = environment->entry()->arguments_count() + 1;
|
||||
if (environment->entry()->arguments_pushed()) {
|
||||
*pushed_arguments_index = arguments_index;
|
||||
*pushed_arguments_count = arguments_count;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < translation_size; ++i) {
|
||||
LOperand* value = environment->values()->at(i);
|
||||
// spilled_registers_ and spilled_double_registers_ are either
|
||||
@ -549,10 +520,7 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
AddToTranslation(translation,
|
||||
environment->spilled_registers()[value->index()],
|
||||
environment->HasTaggedValueAt(i),
|
||||
environment->HasUint32ValueAt(i),
|
||||
arguments_known,
|
||||
arguments_index,
|
||||
arguments_count);
|
||||
environment->HasUint32ValueAt(i));
|
||||
} else if (
|
||||
value->IsDoubleRegister() &&
|
||||
environment->spilled_double_registers()[value->index()] != NULL) {
|
||||
@ -561,20 +529,36 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
translation,
|
||||
environment->spilled_double_registers()[value->index()],
|
||||
false,
|
||||
false,
|
||||
arguments_known,
|
||||
arguments_index,
|
||||
arguments_count);
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(mstarzinger): Introduce marker operands to indicate that this value
|
||||
// is not present and must be reconstructed from the deoptimizer. Currently
|
||||
// this is only used for the arguments object.
|
||||
if (value == NULL) {
|
||||
int arguments_count = environment->values()->length() - translation_size;
|
||||
translation->BeginArgumentsObject(arguments_count);
|
||||
for (int i = 0; i < arguments_count; ++i) {
|
||||
LOperand* value = environment->values()->at(translation_size + i);
|
||||
ASSERT(environment->spilled_registers() == NULL ||
|
||||
!value->IsRegister() ||
|
||||
environment->spilled_registers()[value->index()] == NULL);
|
||||
ASSERT(environment->spilled_registers() == NULL ||
|
||||
!value->IsDoubleRegister() ||
|
||||
environment->spilled_double_registers()[value->index()] == NULL);
|
||||
AddToTranslation(translation,
|
||||
value,
|
||||
environment->HasTaggedValueAt(translation_size + i),
|
||||
environment->HasUint32ValueAt(translation_size + i));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
AddToTranslation(translation,
|
||||
value,
|
||||
environment->HasTaggedValueAt(i),
|
||||
environment->HasUint32ValueAt(i),
|
||||
arguments_known,
|
||||
arguments_index,
|
||||
arguments_count);
|
||||
environment->HasUint32ValueAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
@ -582,17 +566,8 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
||||
void LCodeGen::AddToTranslation(Translation* translation,
|
||||
LOperand* op,
|
||||
bool is_tagged,
|
||||
bool is_uint32,
|
||||
bool arguments_known,
|
||||
int arguments_index,
|
||||
int arguments_count) {
|
||||
if (op == NULL) {
|
||||
// TODO(twuerthinger): Introduce marker operands to indicate that this value
|
||||
// is not present and must be reconstructed from the deoptimizer. Currently
|
||||
// this is only used for the arguments object.
|
||||
translation->StoreArgumentsObject(
|
||||
arguments_known, arguments_index, arguments_count);
|
||||
} else if (op->IsStackSlot()) {
|
||||
bool is_uint32) {
|
||||
if (op->IsStackSlot()) {
|
||||
if (is_tagged) {
|
||||
translation->StoreStackSlot(op->index());
|
||||
} else if (is_uint32) {
|
||||
@ -697,8 +672,6 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
|
||||
|
||||
int frame_count = 0;
|
||||
int jsframe_count = 0;
|
||||
int args_index = 0;
|
||||
int args_count = 0;
|
||||
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
|
||||
++frame_count;
|
||||
if (e->frame_type() == JS_FUNCTION) {
|
||||
@ -706,7 +679,7 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
|
||||
}
|
||||
}
|
||||
Translation translation(&translations_, frame_count, jsframe_count, zone());
|
||||
WriteTranslation(environment, &translation, &args_index, &args_count);
|
||||
WriteTranslation(environment, &translation);
|
||||
int deoptimization_index = deoptimizations_.length();
|
||||
int pc_offset = masm()->pc_offset();
|
||||
environment->Register(deoptimization_index,
|
||||
|
@ -139,10 +139,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
void DoGap(LGap* instr);
|
||||
|
||||
// Emit frame translation commands for an environment.
|
||||
void WriteTranslation(LEnvironment* environment,
|
||||
Translation* translation,
|
||||
int* arguments_index,
|
||||
int* arguments_count);
|
||||
void WriteTranslation(LEnvironment* environment, Translation* translation);
|
||||
|
||||
// Declare methods that deal with the individual node types.
|
||||
#define DECLARE_DO(type) void Do##type(L##type* node);
|
||||
@ -253,10 +250,7 @@ class LCodeGen BASE_EMBEDDED {
|
||||
void AddToTranslation(Translation* translation,
|
||||
LOperand* op,
|
||||
bool is_tagged,
|
||||
bool is_uint32,
|
||||
bool arguments_known,
|
||||
int arguments_index,
|
||||
int arguments_count);
|
||||
bool is_uint32);
|
||||
void RegisterDependentCodeForEmbeddedMaps(Handle<Code> code);
|
||||
void PopulateDeoptimizationData(Handle<Code> code);
|
||||
int DefineDeoptimizationLiteral(Handle<Object> literal);
|
||||
|
@ -937,7 +937,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
||||
BailoutId ast_id = hydrogen_env->ast_id();
|
||||
ASSERT(!ast_id.IsNone() ||
|
||||
hydrogen_env->frame_type() != JS_FUNCTION);
|
||||
int value_count = hydrogen_env->length();
|
||||
int value_count = hydrogen_env->length() - hydrogen_env->specials_count();
|
||||
LEnvironment* result = new(zone()) LEnvironment(
|
||||
hydrogen_env->closure(),
|
||||
hydrogen_env->frame_type(),
|
||||
@ -948,13 +948,15 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
||||
outer,
|
||||
hydrogen_env->entry(),
|
||||
zone());
|
||||
bool needs_arguments_object_materialization = false;
|
||||
int argument_index = *argument_index_accumulator;
|
||||
for (int i = 0; i < value_count; ++i) {
|
||||
for (int i = 0; i < hydrogen_env->length(); ++i) {
|
||||
if (hydrogen_env->is_special_index(i)) continue;
|
||||
|
||||
HValue* value = hydrogen_env->values()->at(i);
|
||||
LOperand* op = NULL;
|
||||
if (value->IsArgumentsObject()) {
|
||||
needs_arguments_object_materialization = true;
|
||||
op = NULL;
|
||||
} else if (value->IsPushArgument()) {
|
||||
op = new(zone()) LArgument(argument_index++);
|
||||
@ -966,6 +968,22 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
||||
value->CheckFlag(HInstruction::kUint32));
|
||||
}
|
||||
|
||||
if (needs_arguments_object_materialization) {
|
||||
HArgumentsObject* arguments = hydrogen_env->entry() == NULL
|
||||
? graph()->GetArgumentsObject()
|
||||
: hydrogen_env->entry()->arguments_object();
|
||||
ASSERT(arguments->IsLinked());
|
||||
for (int i = 1; i < arguments->arguments_count(); ++i) {
|
||||
HValue* value = arguments->arguments_values()->at(i);
|
||||
ASSERT(!value->IsArgumentsObject() && !value->IsPushArgument());
|
||||
ASSERT(HInstruction::cast(value)->IsLinked());
|
||||
LOperand* op = UseAny(value);
|
||||
result->AddValue(op,
|
||||
value->representation(),
|
||||
value->CheckFlag(HInstruction::kUint32));
|
||||
}
|
||||
}
|
||||
|
||||
if (hydrogen_env->frame_type() == JS_FUNCTION) {
|
||||
*argument_index_accumulator = argument_index;
|
||||
}
|
||||
|
@ -266,3 +266,46 @@ test_toarr(toarr2);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
// Test materialization of arguments object with values in registers.
|
||||
(function () {
|
||||
"use strict";
|
||||
var forceDeopt = { deopt:false };
|
||||
function inner(a,b,c,d,e,f,g,h,i,j) {
|
||||
var args = arguments;
|
||||
forceDeopt.deopt;
|
||||
assertSame(10, args.length);
|
||||
assertSame(a, args[0]);
|
||||
assertSame(b, args[1]);
|
||||
assertSame(c, args[2]);
|
||||
assertSame(d, args[3]);
|
||||
assertSame(e, args[4]);
|
||||
assertSame(f, args[5]);
|
||||
assertSame(g, args[6]);
|
||||
assertSame(h, args[7]);
|
||||
assertSame(i, args[8]);
|
||||
assertSame(j, args[9]);
|
||||
}
|
||||
|
||||
var a = 0.5;
|
||||
var b = 1.7;
|
||||
var c = 123;
|
||||
function outer() {
|
||||
inner(
|
||||
a - 0.3, // double in double register
|
||||
b + 2.3, // integer in double register
|
||||
c + 321, // integer in general register
|
||||
c - 456, // integer in stack slot
|
||||
a + 0.1, a + 0.2, a + 0.3, a + 0.4, a + 0.5,
|
||||
a + 0.6 // double in stack slot
|
||||
);
|
||||
}
|
||||
|
||||
outer();
|
||||
outer();
|
||||
%OptimizeFunctionOnNextCall(outer);
|
||||
outer();
|
||||
delete forceDeopt.deopt;
|
||||
outer();
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user