|
|
@ -1,4 +1,4 @@ |
|
|
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
|
|
|
// 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:
|
|
|
@ -104,10 +104,27 @@ Deoptimizer* Deoptimizer::Grab(Isolate* isolate) { |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int Deoptimizer::ConvertJSFrameIndexToFrameIndex(int jsframe_index) { |
|
|
|
if (jsframe_index == 0) return 0; |
|
|
|
|
|
|
|
int frame_index = 0; |
|
|
|
while (jsframe_index >= 0) { |
|
|
|
FrameDescription* frame = output_[frame_index]; |
|
|
|
if (frame->GetFrameType() == StackFrame::JAVA_SCRIPT) { |
|
|
|
jsframe_index--; |
|
|
|
} |
|
|
|
frame_index++; |
|
|
|
} |
|
|
|
|
|
|
|
return frame_index - 1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#ifdef ENABLE_DEBUGGER_SUPPORT |
|
|
|
DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame( |
|
|
|
JavaScriptFrame* frame, |
|
|
|
int frame_index, |
|
|
|
int jsframe_index, |
|
|
|
Isolate* isolate) { |
|
|
|
ASSERT(isolate == Isolate::Current()); |
|
|
|
ASSERT(frame->is_optimized()); |
|
|
@ -143,22 +160,40 @@ DeoptimizedFrameInfo* Deoptimizer::DebuggerInspectableFrame( |
|
|
|
|
|
|
|
// Create the GC safe output frame information and register it for GC
|
|
|
|
// handling.
|
|
|
|
ASSERT_LT(frame_index, deoptimizer->output_count()); |
|
|
|
ASSERT_LT(jsframe_index, deoptimizer->jsframe_count()); |
|
|
|
|
|
|
|
// Convert JS frame index into frame index.
|
|
|
|
int frame_index = deoptimizer->ConvertJSFrameIndexToFrameIndex(jsframe_index); |
|
|
|
|
|
|
|
bool has_arguments_adaptor = |
|
|
|
frame_index > 0 && |
|
|
|
deoptimizer->output_[frame_index - 1]->GetFrameType() == |
|
|
|
StackFrame::ARGUMENTS_ADAPTOR; |
|
|
|
|
|
|
|
DeoptimizedFrameInfo* info = |
|
|
|
new DeoptimizedFrameInfo(deoptimizer, frame_index); |
|
|
|
new DeoptimizedFrameInfo(deoptimizer, frame_index, has_arguments_adaptor); |
|
|
|
isolate->deoptimizer_data()->deoptimized_frame_info_ = info; |
|
|
|
|
|
|
|
// Get the "simulated" top and size for the requested frame.
|
|
|
|
Address top = |
|
|
|
reinterpret_cast<Address>(deoptimizer->output_[frame_index]->GetTop()); |
|
|
|
uint32_t size = deoptimizer->output_[frame_index]->GetFrameSize(); |
|
|
|
FrameDescription* parameters_frame = |
|
|
|
deoptimizer->output_[ |
|
|
|
has_arguments_adaptor ? (frame_index - 1) : frame_index]; |
|
|
|
|
|
|
|
uint32_t parameters_size = (info->parameters_count() + 1) * kPointerSize; |
|
|
|
Address parameters_top = reinterpret_cast<Address>( |
|
|
|
parameters_frame->GetTop() + (parameters_frame->GetFrameSize() - |
|
|
|
parameters_size)); |
|
|
|
|
|
|
|
uint32_t expressions_size = info->expression_count() * kPointerSize; |
|
|
|
Address expressions_top = reinterpret_cast<Address>( |
|
|
|
deoptimizer->output_[frame_index]->GetTop()); |
|
|
|
|
|
|
|
// Done with the GC-unsafe frame descriptions. This re-enables allocation.
|
|
|
|
deoptimizer->DeleteFrameDescriptions(); |
|
|
|
|
|
|
|
// Allocate a heap number for the doubles belonging to this frame.
|
|
|
|
deoptimizer->MaterializeHeapNumbersForDebuggerInspectableFrame( |
|
|
|
top, size, info); |
|
|
|
parameters_top, parameters_size, expressions_top, expressions_size, info); |
|
|
|
|
|
|
|
// Finished using the deoptimizer instance.
|
|
|
|
delete deoptimizer; |
|
|
@ -313,6 +348,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate, |
|
|
|
fp_to_sp_delta_(fp_to_sp_delta), |
|
|
|
input_(NULL), |
|
|
|
output_count_(0), |
|
|
|
jsframe_count_(0), |
|
|
|
output_(NULL), |
|
|
|
frame_alignment_marker_(isolate->heap()->frame_alignment_marker()), |
|
|
|
has_alignment_padding_(0), |
|
|
@ -377,9 +413,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate, |
|
|
|
ASSERT(HEAP->allow_allocation(false)); |
|
|
|
unsigned size = ComputeInputFrameSize(); |
|
|
|
input_ = new(size) FrameDescription(size, function); |
|
|
|
#ifdef DEBUG |
|
|
|
input_->SetKind(Code::OPTIMIZED_FUNCTION); |
|
|
|
#endif |
|
|
|
input_->SetFrameType(StackFrame::JAVA_SCRIPT); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -515,6 +549,7 @@ void Deoptimizer::DoComputeOutputFrames() { |
|
|
|
// Read the number of output frames and allocate an array for their
|
|
|
|
// descriptions.
|
|
|
|
int count = iterator.Next(); |
|
|
|
iterator.Next(); // Drop JS frames count.
|
|
|
|
ASSERT(output_ == NULL); |
|
|
|
output_ = new FrameDescription*[count]; |
|
|
|
for (int i = 0; i < count; ++i) { |
|
|
@ -524,7 +559,21 @@ void Deoptimizer::DoComputeOutputFrames() { |
|
|
|
|
|
|
|
// Translate each output frame.
|
|
|
|
for (int i = 0; i < count; ++i) { |
|
|
|
DoComputeFrame(&iterator, i); |
|
|
|
// Read the ast node id, function, and frame height for this output frame.
|
|
|
|
Translation::Opcode opcode = |
|
|
|
static_cast<Translation::Opcode>(iterator.Next()); |
|
|
|
switch (opcode) { |
|
|
|
case Translation::JS_FRAME: |
|
|
|
DoComputeJSFrame(&iterator, i); |
|
|
|
jsframe_count_++; |
|
|
|
break; |
|
|
|
case Translation::ARGUMENTS_ADAPTOR_FRAME: |
|
|
|
DoComputeArgumentsAdaptorFrame(&iterator, i); |
|
|
|
break; |
|
|
|
default: |
|
|
|
UNREACHABLE(); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Print some helpful diagnostic information.
|
|
|
@ -565,39 +614,52 @@ void Deoptimizer::MaterializeHeapNumbers() { |
|
|
|
|
|
|
|
#ifdef ENABLE_DEBUGGER_SUPPORT |
|
|
|
void Deoptimizer::MaterializeHeapNumbersForDebuggerInspectableFrame( |
|
|
|
Address top, uint32_t size, DeoptimizedFrameInfo* info) { |
|
|
|
Address parameters_top, |
|
|
|
uint32_t parameters_size, |
|
|
|
Address expressions_top, |
|
|
|
uint32_t expressions_size, |
|
|
|
DeoptimizedFrameInfo* info) { |
|
|
|
ASSERT_EQ(DEBUGGER, bailout_type_); |
|
|
|
Address parameters_bottom = parameters_top + parameters_size; |
|
|
|
Address expressions_bottom = expressions_top + expressions_size; |
|
|
|
for (int i = 0; i < deferred_heap_numbers_.length(); i++) { |
|
|
|
HeapNumberMaterializationDescriptor d = deferred_heap_numbers_[i]; |
|
|
|
|
|
|
|
// Check of the heap number to materialize actually belong to the frame
|
|
|
|
// being extracted.
|
|
|
|
Address slot = d.slot_address(); |
|
|
|
if (top <= slot && slot < top + size) { |
|
|
|
if (parameters_top <= slot && slot < parameters_bottom) { |
|
|
|
Handle<Object> num = isolate_->factory()->NewNumber(d.value()); |
|
|
|
// Calculate the index with the botton of the expression stack
|
|
|
|
// at index 0, and the fixed part (including incoming arguments)
|
|
|
|
// at negative indexes.
|
|
|
|
int index = static_cast<int>( |
|
|
|
info->expression_count_ - (slot - top) / kPointerSize - 1); |
|
|
|
|
|
|
|
int index = (info->parameters_count() - 1) - |
|
|
|
static_cast<int>(slot - parameters_top) / kPointerSize; |
|
|
|
|
|
|
|
if (FLAG_trace_deopt) { |
|
|
|
PrintF("Materializing a new heap number %p [%e] in slot %p" |
|
|
|
"for stack index %d\n", |
|
|
|
"for parameter slot #%d\n", |
|
|
|
reinterpret_cast<void*>(*num), |
|
|
|
d.value(), |
|
|
|
d.slot_address(), |
|
|
|
index); |
|
|
|
} |
|
|
|
if (index >=0) { |
|
|
|
info->SetExpression(index, *num); |
|
|
|
} else { |
|
|
|
// Calculate parameter index subtracting one for the receiver.
|
|
|
|
int parameter_index = |
|
|
|
index + |
|
|
|
static_cast<int>(size) / kPointerSize - |
|
|
|
info->expression_count_ - 1; |
|
|
|
info->SetParameter(parameter_index, *num); |
|
|
|
|
|
|
|
info->SetParameter(index, *num); |
|
|
|
} else if (expressions_top <= slot && slot < expressions_bottom) { |
|
|
|
Handle<Object> num = isolate_->factory()->NewNumber(d.value()); |
|
|
|
|
|
|
|
int index = info->expression_count() - 1 - |
|
|
|
static_cast<int>(slot - expressions_top) / kPointerSize; |
|
|
|
|
|
|
|
if (FLAG_trace_deopt) { |
|
|
|
PrintF("Materializing a new heap number %p [%e] in slot %p" |
|
|
|
"for expression slot #%d\n", |
|
|
|
reinterpret_cast<void*>(*num), |
|
|
|
d.value(), |
|
|
|
d.slot_address(), |
|
|
|
index); |
|
|
|
} |
|
|
|
|
|
|
|
info->SetExpression(index, *num); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -622,7 +684,8 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, |
|
|
|
|
|
|
|
switch (opcode) { |
|
|
|
case Translation::BEGIN: |
|
|
|
case Translation::FRAME: |
|
|
|
case Translation::JS_FRAME: |
|
|
|
case Translation::ARGUMENTS_ADAPTOR_FRAME: |
|
|
|
case Translation::DUPLICATE: |
|
|
|
UNREACHABLE(); |
|
|
|
return; |
|
|
@ -691,7 +754,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, |
|
|
|
case Translation::STACK_SLOT: { |
|
|
|
int input_slot_index = iterator->Next(); |
|
|
|
unsigned input_offset = |
|
|
|
input_->GetOffsetFromSlotIndex(this, input_slot_index); |
|
|
|
input_->GetOffsetFromSlotIndex(input_slot_index); |
|
|
|
intptr_t input_value = input_->GetFrameSlot(input_offset); |
|
|
|
if (FLAG_trace_deopt) { |
|
|
|
PrintF(" 0x%08" V8PRIxPTR ": ", |
|
|
@ -710,7 +773,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, |
|
|
|
case Translation::INT32_STACK_SLOT: { |
|
|
|
int input_slot_index = iterator->Next(); |
|
|
|
unsigned input_offset = |
|
|
|
input_->GetOffsetFromSlotIndex(this, input_slot_index); |
|
|
|
input_->GetOffsetFromSlotIndex(input_slot_index); |
|
|
|
intptr_t value = input_->GetFrameSlot(input_offset); |
|
|
|
bool is_smi = Smi::IsValid(value); |
|
|
|
if (FLAG_trace_deopt) { |
|
|
@ -739,7 +802,7 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator, |
|
|
|
case Translation::DOUBLE_STACK_SLOT: { |
|
|
|
int input_slot_index = iterator->Next(); |
|
|
|
unsigned input_offset = |
|
|
|
input_->GetOffsetFromSlotIndex(this, input_slot_index); |
|
|
|
input_->GetOffsetFromSlotIndex(input_slot_index); |
|
|
|
double value = input_->GetDoubleFrameSlot(input_offset); |
|
|
|
if (FLAG_trace_deopt) { |
|
|
|
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- %e ; [esp + %d]\n", |
|
|
@ -808,7 +871,8 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, |
|
|
|
|
|
|
|
switch (opcode) { |
|
|
|
case Translation::BEGIN: |
|
|
|
case Translation::FRAME: |
|
|
|
case Translation::JS_FRAME: |
|
|
|
case Translation::ARGUMENTS_ADAPTOR_FRAME: |
|
|
|
case Translation::DUPLICATE: |
|
|
|
UNREACHABLE(); // Malformed input.
|
|
|
|
return false; |
|
|
@ -871,7 +935,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, |
|
|
|
case Translation::STACK_SLOT: { |
|
|
|
int output_index = iterator->Next(); |
|
|
|
unsigned output_offset = |
|
|
|
output->GetOffsetFromSlotIndex(this, output_index); |
|
|
|
output->GetOffsetFromSlotIndex(output_index); |
|
|
|
if (FLAG_trace_osr) { |
|
|
|
PrintF(" [sp + %d] <- 0x%08" V8PRIxPTR " ; [sp + %d] ", |
|
|
|
output_offset, |
|
|
@ -890,7 +954,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, |
|
|
|
|
|
|
|
int output_index = iterator->Next(); |
|
|
|
unsigned output_offset = |
|
|
|
output->GetOffsetFromSlotIndex(this, output_index); |
|
|
|
output->GetOffsetFromSlotIndex(output_index); |
|
|
|
int int32_value = input_object->IsSmi() |
|
|
|
? Smi::cast(input_object)->value() |
|
|
|
: DoubleToInt32(input_object->Number()); |
|
|
@ -922,7 +986,7 @@ bool Deoptimizer::DoOsrTranslateCommand(TranslationIterator* iterator, |
|
|
|
|
|
|
|
int output_index = iterator->Next(); |
|
|
|
unsigned output_offset = |
|
|
|
output->GetOffsetFromSlotIndex(this, output_index); |
|
|
|
output->GetOffsetFromSlotIndex(output_index); |
|
|
|
double double_value = input_object->Number(); |
|
|
|
uint64_t int_value = BitCast<uint64_t, double>(double_value); |
|
|
|
int32_t lower = static_cast<int32_t>(int_value); |
|
|
@ -1033,8 +1097,8 @@ unsigned Deoptimizer::ComputeInputFrameSize() const { |
|
|
|
unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const { |
|
|
|
// The fixed part of the frame consists of the return address, frame
|
|
|
|
// pointer, function, context, and all the incoming arguments.
|
|
|
|
static const unsigned kFixedSlotSize = 4 * kPointerSize; |
|
|
|
return ComputeIncomingArgumentSize(function) + kFixedSlotSize; |
|
|
|
return ComputeIncomingArgumentSize(function) + |
|
|
|
StandardFrameConstants::kFixedFrameSize; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1154,49 +1218,62 @@ FrameDescription::FrameDescription(uint32_t frame_size, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
unsigned FrameDescription::GetOffsetFromSlotIndex(Deoptimizer* deoptimizer, |
|
|
|
int slot_index) { |
|
|
|
int FrameDescription::ComputeFixedSize() { |
|
|
|
return StandardFrameConstants::kFixedFrameSize + |
|
|
|
(ComputeParametersCount() + 1) * kPointerSize; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
unsigned FrameDescription::GetOffsetFromSlotIndex(int slot_index) { |
|
|
|
if (slot_index >= 0) { |
|
|
|
// Local or spill slots. Skip the fixed part of the frame
|
|
|
|
// including all arguments.
|
|
|
|
unsigned base = |
|
|
|
GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction()); |
|
|
|
unsigned base = GetFrameSize() - ComputeFixedSize(); |
|
|
|
return base - ((slot_index + 1) * kPointerSize); |
|
|
|
} else { |
|
|
|
// Incoming parameter.
|
|
|
|
unsigned base = GetFrameSize() - |
|
|
|
deoptimizer->ComputeIncomingArgumentSize(GetFunction()); |
|
|
|
int arg_size = (ComputeParametersCount() + 1) * kPointerSize; |
|
|
|
unsigned base = GetFrameSize() - arg_size; |
|
|
|
return base - ((slot_index + 1) * kPointerSize); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int FrameDescription::ComputeParametersCount() { |
|
|
|
return function_->shared()->formal_parameter_count(); |
|
|
|
switch (type_) { |
|
|
|
case StackFrame::JAVA_SCRIPT: |
|
|
|
return function_->shared()->formal_parameter_count(); |
|
|
|
case StackFrame::ARGUMENTS_ADAPTOR: { |
|
|
|
// Last slot contains number of incomming arguments as a smi.
|
|
|
|
// Can't use GetExpression(0) because it would cause infinite recursion.
|
|
|
|
return reinterpret_cast<Smi*>(*GetFrameSlotPointer(0))->value(); |
|
|
|
} |
|
|
|
default: |
|
|
|
UNREACHABLE(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Object* FrameDescription::GetParameter(Deoptimizer* deoptimizer, int index) { |
|
|
|
ASSERT_EQ(Code::FUNCTION, kind_); |
|
|
|
Object* FrameDescription::GetParameter(int index) { |
|
|
|
ASSERT(index >= 0); |
|
|
|
ASSERT(index < ComputeParametersCount()); |
|
|
|
// The slot indexes for incoming arguments are negative.
|
|
|
|
unsigned offset = GetOffsetFromSlotIndex(deoptimizer, |
|
|
|
index - ComputeParametersCount()); |
|
|
|
unsigned offset = GetOffsetFromSlotIndex(index - ComputeParametersCount()); |
|
|
|
return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
unsigned FrameDescription::GetExpressionCount(Deoptimizer* deoptimizer) { |
|
|
|
ASSERT_EQ(Code::FUNCTION, kind_); |
|
|
|
unsigned size = GetFrameSize() - deoptimizer->ComputeFixedSize(GetFunction()); |
|
|
|
unsigned FrameDescription::GetExpressionCount() { |
|
|
|
ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_); |
|
|
|
unsigned size = GetFrameSize() - ComputeFixedSize(); |
|
|
|
return size / kPointerSize; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Object* FrameDescription::GetExpression(Deoptimizer* deoptimizer, int index) { |
|
|
|
ASSERT_EQ(Code::FUNCTION, kind_); |
|
|
|
unsigned offset = GetOffsetFromSlotIndex(deoptimizer, index); |
|
|
|
Object* FrameDescription::GetExpression(int index) { |
|
|
|
ASSERT_EQ(StackFrame::JAVA_SCRIPT, type_); |
|
|
|
unsigned offset = GetOffsetFromSlotIndex(index); |
|
|
|
return reinterpret_cast<Object*>(*GetFrameSlotPointer(offset)); |
|
|
|
} |
|
|
|
|
|
|
@ -1242,8 +1319,15 @@ Handle<ByteArray> TranslationBuffer::CreateByteArray() { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Translation::BeginFrame(int node_id, int literal_id, unsigned height) { |
|
|
|
buffer_->Add(FRAME); |
|
|
|
void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) { |
|
|
|
buffer_->Add(ARGUMENTS_ADAPTOR_FRAME); |
|
|
|
buffer_->Add(literal_id); |
|
|
|
buffer_->Add(height); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Translation::BeginJSFrame(int node_id, int literal_id, unsigned height) { |
|
|
|
buffer_->Add(JS_FRAME); |
|
|
|
buffer_->Add(node_id); |
|
|
|
buffer_->Add(literal_id); |
|
|
|
buffer_->Add(height); |
|
|
@ -1307,7 +1391,6 @@ int Translation::NumberOfOperandsFor(Opcode opcode) { |
|
|
|
case ARGUMENTS_OBJECT: |
|
|
|
case DUPLICATE: |
|
|
|
return 0; |
|
|
|
case BEGIN: |
|
|
|
case REGISTER: |
|
|
|
case INT32_REGISTER: |
|
|
|
case DOUBLE_REGISTER: |
|
|
@ -1316,7 +1399,10 @@ int Translation::NumberOfOperandsFor(Opcode opcode) { |
|
|
|
case DOUBLE_STACK_SLOT: |
|
|
|
case LITERAL: |
|
|
|
return 1; |
|
|
|
case FRAME: |
|
|
|
case BEGIN: |
|
|
|
case ARGUMENTS_ADAPTOR_FRAME: |
|
|
|
return 2; |
|
|
|
case JS_FRAME: |
|
|
|
return 3; |
|
|
|
} |
|
|
|
UNREACHABLE(); |
|
|
@ -1330,8 +1416,10 @@ const char* Translation::StringFor(Opcode opcode) { |
|
|
|
switch (opcode) { |
|
|
|
case BEGIN: |
|
|
|
return "BEGIN"; |
|
|
|
case FRAME: |
|
|
|
return "FRAME"; |
|
|
|
case JS_FRAME: |
|
|
|
return "JS_FRAME"; |
|
|
|
case ARGUMENTS_ADAPTOR_FRAME: |
|
|
|
return "ARGUMENTS_ADAPTOR_FRAME"; |
|
|
|
case REGISTER: |
|
|
|
return "REGISTER"; |
|
|
|
case INT32_REGISTER: |
|
|
@ -1385,7 +1473,8 @@ SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator, |
|
|
|
|
|
|
|
switch (opcode) { |
|
|
|
case Translation::BEGIN: |
|
|
|
case Translation::FRAME: |
|
|
|
case Translation::JS_FRAME: |
|
|
|
case Translation::ARGUMENTS_ADAPTOR_FRAME: |
|
|
|
// Peeled off before getting here.
|
|
|
|
break; |
|
|
|
|
|
|
@ -1431,9 +1520,27 @@ SlotRef SlotRef::ComputeSlotForNextArgument(TranslationIterator* iterator, |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void SlotRef::ComputeSlotMappingForArguments(JavaScriptFrame* frame, |
|
|
|
int inlined_frame_index, |
|
|
|
Vector<SlotRef>* args_slots) { |
|
|
|
void SlotRef::ComputeSlotsForArguments(Vector<SlotRef>* args_slots, |
|
|
|
TranslationIterator* it, |
|
|
|
DeoptimizationInputData* data, |
|
|
|
JavaScriptFrame* frame) { |
|
|
|
// Process the translation commands for the arguments.
|
|
|
|
|
|
|
|
// Skip the translation command for the receiver.
|
|
|
|
it->Skip(Translation::NumberOfOperandsFor( |
|
|
|
static_cast<Translation::Opcode>(it->Next()))); |
|
|
|
|
|
|
|
// Compute slots for arguments.
|
|
|
|
for (int i = 0; i < args_slots->length(); ++i) { |
|
|
|
(*args_slots)[i] = ComputeSlotForNextArgument(it, data, frame); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Vector<SlotRef> SlotRef::ComputeSlotMappingForArguments( |
|
|
|
JavaScriptFrame* frame, |
|
|
|
int inlined_jsframe_index, |
|
|
|
int formal_parameter_count) { |
|
|
|
AssertNoAllocation no_gc; |
|
|
|
int deopt_index = AstNode::kNoNumber; |
|
|
|
DeoptimizationInputData* data = |
|
|
@ -1442,51 +1549,73 @@ void SlotRef::ComputeSlotMappingForArguments(JavaScriptFrame* frame, |
|
|
|
data->TranslationIndex(deopt_index)->value()); |
|
|
|
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next()); |
|
|
|
ASSERT(opcode == Translation::BEGIN); |
|
|
|
int frame_count = it.Next(); |
|
|
|
USE(frame_count); |
|
|
|
ASSERT(frame_count > inlined_frame_index); |
|
|
|
int frames_to_skip = inlined_frame_index; |
|
|
|
it.Next(); // Drop frame count.
|
|
|
|
int jsframe_count = it.Next(); |
|
|
|
USE(jsframe_count); |
|
|
|
ASSERT(jsframe_count > inlined_jsframe_index); |
|
|
|
int jsframes_to_skip = inlined_jsframe_index; |
|
|
|
while (true) { |
|
|
|
opcode = static_cast<Translation::Opcode>(it.Next()); |
|
|
|
// Skip over operands to advance to the next opcode.
|
|
|
|
it.Skip(Translation::NumberOfOperandsFor(opcode)); |
|
|
|
if (opcode == Translation::FRAME) { |
|
|
|
if (frames_to_skip == 0) { |
|
|
|
if (opcode == Translation::ARGUMENTS_ADAPTOR_FRAME) { |
|
|
|
if (jsframes_to_skip == 0) { |
|
|
|
ASSERT(Translation::NumberOfOperandsFor(opcode) == 2); |
|
|
|
|
|
|
|
it.Skip(1); // literal id
|
|
|
|
int height = it.Next(); |
|
|
|
|
|
|
|
// We reached the arguments adaptor frame corresponding to the
|
|
|
|
// inlined function in question. Number of arguments is height - 1.
|
|
|
|
Vector<SlotRef> args_slots = |
|
|
|
Vector<SlotRef>::New(height - 1); // Minus receiver.
|
|
|
|
ComputeSlotsForArguments(&args_slots, &it, data, frame); |
|
|
|
return args_slots; |
|
|
|
} |
|
|
|
} else if (opcode == Translation::JS_FRAME) { |
|
|
|
if (jsframes_to_skip == 0) { |
|
|
|
// Skip over operands to advance to the next opcode.
|
|
|
|
it.Skip(Translation::NumberOfOperandsFor(opcode)); |
|
|
|
|
|
|
|
// We reached the frame corresponding to the inlined function
|
|
|
|
// in question. Process the translation commands for the
|
|
|
|
// arguments.
|
|
|
|
//
|
|
|
|
// Skip the translation command for the receiver.
|
|
|
|
it.Skip(Translation::NumberOfOperandsFor( |
|
|
|
static_cast<Translation::Opcode>(it.Next()))); |
|
|
|
// Compute slots for arguments.
|
|
|
|
for (int i = 0; i < args_slots->length(); ++i) { |
|
|
|
(*args_slots)[i] = ComputeSlotForNextArgument(&it, data, frame); |
|
|
|
} |
|
|
|
return; |
|
|
|
// arguments. Number of arguments is equal to the number of
|
|
|
|
// format parameter count.
|
|
|
|
Vector<SlotRef> args_slots = |
|
|
|
Vector<SlotRef>::New(formal_parameter_count); |
|
|
|
ComputeSlotsForArguments(&args_slots, &it, data, frame); |
|
|
|
return args_slots; |
|
|
|
} |
|
|
|
frames_to_skip--; |
|
|
|
jsframes_to_skip--; |
|
|
|
} |
|
|
|
|
|
|
|
// Skip over operands to advance to the next opcode.
|
|
|
|
it.Skip(Translation::NumberOfOperandsFor(opcode)); |
|
|
|
} |
|
|
|
|
|
|
|
UNREACHABLE(); |
|
|
|
return Vector<SlotRef>(); |
|
|
|
} |
|
|
|
|
|
|
|
#ifdef ENABLE_DEBUGGER_SUPPORT |
|
|
|
|
|
|
|
DeoptimizedFrameInfo::DeoptimizedFrameInfo( |
|
|
|
Deoptimizer* deoptimizer, int frame_index) { |
|
|
|
Deoptimizer* deoptimizer, int frame_index, bool has_arguments_adaptor) { |
|
|
|
FrameDescription* output_frame = deoptimizer->output_[frame_index]; |
|
|
|
SetFunction(output_frame->GetFunction()); |
|
|
|
expression_count_ = output_frame->GetExpressionCount(deoptimizer); |
|
|
|
expression_count_ = output_frame->GetExpressionCount(); |
|
|
|
expression_stack_ = new Object*[expression_count_]; |
|
|
|
for (int i = 0; i < expression_count_; i++) { |
|
|
|
SetExpression(i, output_frame->GetExpression(i)); |
|
|
|
} |
|
|
|
|
|
|
|
if (has_arguments_adaptor) { |
|
|
|
output_frame = deoptimizer->output_[frame_index - 1]; |
|
|
|
ASSERT(output_frame->GetFrameType() == StackFrame::ARGUMENTS_ADAPTOR); |
|
|
|
} |
|
|
|
|
|
|
|
parameters_count_ = output_frame->ComputeParametersCount(); |
|
|
|
parameters_ = new Object*[parameters_count_]; |
|
|
|
for (int i = 0; i < parameters_count_; i++) { |
|
|
|
SetParameter(i, output_frame->GetParameter(deoptimizer, i)); |
|
|
|
} |
|
|
|
expression_stack_ = new Object*[expression_count_]; |
|
|
|
for (int i = 0; i < expression_count_; i++) { |
|
|
|
SetExpression(i, output_frame->GetExpression(deoptimizer, i)); |
|
|
|
SetParameter(i, output_frame->GetParameter(i)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|