diff options
Diffstat (limited to 'deps/v8/src/deoptimizer.cc')
-rw-r--r-- | deps/v8/src/deoptimizer.cc | 344 |
1 files changed, 329 insertions, 15 deletions
diff --git a/deps/v8/src/deoptimizer.cc b/deps/v8/src/deoptimizer.cc index dd012db6ab..4bdafbf1b4 100644 --- a/deps/v8/src/deoptimizer.cc +++ b/deps/v8/src/deoptimizer.cc @@ -5,13 +5,13 @@ #include "src/deoptimizer.h" #include "src/accessors.h" +#include "src/ast/prettyprinter.h" #include "src/codegen.h" #include "src/disasm.h" #include "src/frames-inl.h" #include "src/full-codegen/full-codegen.h" #include "src/global-handles.h" #include "src/macro-assembler.h" -#include "src/prettyprinter.h" #include "src/profiler/cpu-profiler.h" #include "src/v8.h" @@ -763,6 +763,10 @@ void Deoptimizer::DoComputeOutputFrames() { DoComputeJSFrame(frame_index); jsframe_count_++; break; + case TranslatedFrame::kInterpretedFunction: + DoComputeInterpretedFrame(frame_index); + jsframe_count_++; + break; case TranslatedFrame::kArgumentsAdaptor: DoComputeArgumentsAdaptorFrame(frame_index); break; @@ -828,7 +832,7 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) { // The 'fixed' part of the frame consists of the incoming parameters and // the part described by JavaScriptFrameConstants. - unsigned fixed_frame_size = ComputeFixedSize(function); + unsigned fixed_frame_size = ComputeJavascriptFixedSize(function); unsigned input_frame_size = input_->GetFrameSize(); unsigned output_frame_size = height_in_bytes + fixed_frame_size; @@ -943,8 +947,6 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) { input_offset -= kPointerSize; // Read the context from the translations. Object* context = value_iterator->GetRawValue(); - // The context should not be a placeholder for a materialized object. - CHECK(context != isolate_->heap()->arguments_marker()); if (context == isolate_->heap()->undefined_value()) { // If the context was optimized away, just use the context from // the activation. This should only apply to Crankshaft code. @@ -959,6 +961,12 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) { if (is_topmost) output_frame->SetRegister(context_reg.code(), value); WriteValueToOutput(context, input_index, frame_index, output_offset, "context "); + if (context == isolate_->heap()->arguments_marker()) { + Address output_address = + reinterpret_cast<Address>(output_[frame_index]->GetTop()) + + output_offset; + values_to_materialize_.push_back({output_address, value_iterator}); + } value_iterator++; input_index++; @@ -1022,6 +1030,222 @@ void Deoptimizer::DoComputeJSFrame(int frame_index) { } +void Deoptimizer::DoComputeInterpretedFrame(int frame_index) { + TranslatedFrame* translated_frame = + &(translated_state_.frames()[frame_index]); + TranslatedFrame::iterator value_iterator = translated_frame->begin(); + int input_index = 0; + + BailoutId bytecode_offset = translated_frame->node_id(); + unsigned height = translated_frame->height(); + unsigned height_in_bytes = height * kPointerSize; + JSFunction* function = JSFunction::cast(value_iterator->GetRawValue()); + value_iterator++; + input_index++; + if (trace_scope_ != NULL) { + PrintF(trace_scope_->file(), " translating interpreted frame "); + function->PrintName(trace_scope_->file()); + PrintF(trace_scope_->file(), " => bytecode_offset=%d, height=%d\n", + bytecode_offset.ToInt(), height_in_bytes); + } + + // The 'fixed' part of the frame consists of the incoming parameters and + // the part described by InterpreterFrameConstants. + unsigned fixed_frame_size = ComputeInterpretedFixedSize(function); + unsigned input_frame_size = input_->GetFrameSize(); + unsigned output_frame_size = height_in_bytes + fixed_frame_size; + + // Allocate and store the output frame description. + FrameDescription* output_frame = + new (output_frame_size) FrameDescription(output_frame_size, function); + output_frame->SetFrameType(StackFrame::INTERPRETED); + + bool is_bottommost = (0 == frame_index); + bool is_topmost = (output_count_ - 1 == frame_index); + CHECK(frame_index >= 0 && frame_index < output_count_); + CHECK_NULL(output_[frame_index]); + output_[frame_index] = output_frame; + + // The top address for the bottommost output frame can be computed from + // the input frame pointer and the output frame's height. For all + // subsequent output frames, it can be computed from the previous one's + // top address and the current frame's size. + Register fp_reg = InterpretedFrame::fp_register(); + intptr_t top_address; + if (is_bottommost) { + // Subtract interpreter fixed frame size for the context function slots, + // new,target and bytecode offset. + top_address = input_->GetRegister(fp_reg.code()) - + InterpreterFrameConstants::kFixedFrameSizeFromFp - + height_in_bytes; + } else { + top_address = output_[frame_index - 1]->GetTop() - output_frame_size; + } + output_frame->SetTop(top_address); + + // Compute the incoming parameter translation. + int parameter_count = + function->shared()->internal_formal_parameter_count() + 1; + unsigned output_offset = output_frame_size; + unsigned input_offset = input_frame_size; + for (int i = 0; i < parameter_count; ++i) { + output_offset -= kPointerSize; + WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, + output_offset); + } + input_offset -= (parameter_count * kPointerSize); + + // There are no translation commands for the caller's pc and fp, the + // context, the function, new.target and the bytecode offset. Synthesize + // their values and set them up + // explicitly. + // + // The caller's pc for the bottommost output frame is the same as in the + // input frame. For all subsequent output frames, it can be read from the + // previous one. This frame's pc can be computed from the non-optimized + // function code and AST id of the bailout. + output_offset -= kPCOnStackSize; + input_offset -= kPCOnStackSize; + intptr_t value; + if (is_bottommost) { + value = input_->GetFrameSlot(input_offset); + } else { + value = output_[frame_index - 1]->GetPc(); + } + output_frame->SetCallerPc(output_offset, value); + DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n"); + + // The caller's frame pointer for the bottommost output frame is the same + // as in the input frame. For all subsequent output frames, it can be + // read from the previous one. Also compute and set this frame's frame + // pointer. + output_offset -= kFPOnStackSize; + input_offset -= kFPOnStackSize; + if (is_bottommost) { + value = input_->GetFrameSlot(input_offset); + } else { + value = output_[frame_index - 1]->GetFp(); + } + output_frame->SetCallerFp(output_offset, value); + intptr_t fp_value = top_address + output_offset; + DCHECK(!is_bottommost || + (input_->GetRegister(fp_reg.code()) + + has_alignment_padding_ * kPointerSize) == fp_value); + output_frame->SetFp(fp_value); + if (is_topmost) output_frame->SetRegister(fp_reg.code(), fp_value); + DebugPrintOutputSlot(value, frame_index, output_offset, "caller's fp\n"); + DCHECK(!is_bottommost || !has_alignment_padding_ || + (fp_value & kPointerSize) != 0); + + if (FLAG_enable_embedded_constant_pool) { + // For the bottommost output frame the constant pool pointer can be gotten + // from the input frame. For subsequent output frames, it can be read from + // the previous frame. + output_offset -= kPointerSize; + input_offset -= kPointerSize; + if (is_bottommost) { + value = input_->GetFrameSlot(input_offset); + } else { + value = output_[frame_index - 1]->GetConstantPool(); + } + output_frame->SetCallerConstantPool(output_offset, value); + DebugPrintOutputSlot(value, frame_index, output_offset, + "caller's constant_pool\n"); + } + + // For the bottommost output frame the context can be gotten from the input + // frame. For all subsequent output frames it can be gotten from the function + // so long as we don't inline functions that need local contexts. + Register context_reg = InterpretedFrame::context_register(); + output_offset -= kPointerSize; + input_offset -= kPointerSize; + // Read the context from the translations. + Object* context = value_iterator->GetRawValue(); + // The context should not be a placeholder for a materialized object. + CHECK(context != isolate_->heap()->arguments_marker()); + value = reinterpret_cast<intptr_t>(context); + output_frame->SetContext(value); + if (is_topmost) output_frame->SetRegister(context_reg.code(), value); + WriteValueToOutput(context, input_index, frame_index, output_offset, + "context "); + value_iterator++; + input_index++; + + // The function was mentioned explicitly in the BEGIN_FRAME. + output_offset -= kPointerSize; + input_offset -= kPointerSize; + value = reinterpret_cast<intptr_t>(function); + // The function for the bottommost output frame should also agree with the + // input frame. + DCHECK(!is_bottommost || input_->GetFrameSlot(input_offset) == value); + WriteValueToOutput(function, 0, frame_index, output_offset, "function "); + + // TODO(rmcilroy): Deal with new.target correctly - currently just set it to + // undefined. + output_offset -= kPointerSize; + input_offset -= kPointerSize; + Object* new_target = isolate_->heap()->undefined_value(); + WriteValueToOutput(new_target, 0, frame_index, output_offset, "new_target "); + + // The bytecode offset was mentioned explicitly in the BEGIN_FRAME. + output_offset -= kPointerSize; + input_offset -= kPointerSize; + int raw_bytecode_offset = + BytecodeArray::kHeaderSize - kHeapObjectTag + bytecode_offset.ToInt(); + Smi* smi_bytecode_offset = Smi::FromInt(raw_bytecode_offset); + WriteValueToOutput(smi_bytecode_offset, 0, frame_index, output_offset, + "bytecode offset "); + + // Translate the rest of the interpreter registers in the frame. + for (unsigned i = 0; i < height; ++i) { + output_offset -= kPointerSize; + WriteTranslatedValueToOutput(&value_iterator, &input_index, frame_index, + output_offset); + } + CHECK_EQ(0u, output_offset); + + // Set the accumulator register. + output_frame->SetRegister( + kInterpreterAccumulatorRegister.code(), + reinterpret_cast<intptr_t>(value_iterator->GetRawValue())); + value_iterator++; + + Builtins* builtins = isolate_->builtins(); + Code* trampoline = builtins->builtin(Builtins::kInterpreterEntryTrampoline); + output_frame->SetPc(reinterpret_cast<intptr_t>(trampoline->entry())); + output_frame->SetState(0); + + // Update constant pool. + if (FLAG_enable_embedded_constant_pool) { + intptr_t constant_pool_value = + reinterpret_cast<intptr_t>(trampoline->constant_pool()); + output_frame->SetConstantPool(constant_pool_value); + if (is_topmost) { + Register constant_pool_reg = + InterpretedFrame::constant_pool_pointer_register(); + output_frame->SetRegister(constant_pool_reg.code(), constant_pool_value); + } + } + + // Set the continuation for the topmost frame. + if (is_topmost && bailout_type_ != DEBUGGER) { + Code* continuation = + builtins->builtin(Builtins::kInterpreterNotifyDeoptimized); + if (bailout_type_ == LAZY) { + continuation = + builtins->builtin(Builtins::kInterpreterNotifyLazyDeoptimized); + } else if (bailout_type_ == SOFT) { + continuation = + builtins->builtin(Builtins::kInterpreterNotifySoftDeoptimized); + } else { + CHECK_EQ(bailout_type_, EAGER); + } + output_frame->SetContinuation( + reinterpret_cast<intptr_t>(continuation->entry())); + } +} + + void Deoptimizer::DoComputeArgumentsAdaptorFrame(int frame_index) { TranslatedFrame* translated_frame = &(translated_state_.frames()[frame_index]); @@ -1235,12 +1459,6 @@ void Deoptimizer::DoComputeConstructStubFrame(int frame_index) { PrintF(trace_scope_->file(), "(%d)\n", height - 1); } - // The original constructor. - output_offset -= kPointerSize; - value = reinterpret_cast<intptr_t>(isolate_->heap()->undefined_value()); - output_frame->SetFrameSlot(output_offset, value); - DebugPrintOutputSlot(value, frame_index, output_offset, "new.target\n"); - // The newly allocated object was passed as receiver in the artificial // constructor stub environment created by HEnvironment::CopyForInlining(). output_offset -= kPointerSize; @@ -1762,7 +1980,7 @@ void Deoptimizer::DebugPrintOutputSlot(intptr_t value, int frame_index, unsigned Deoptimizer::ComputeInputFrameSize() const { - unsigned fixed_size = ComputeFixedSize(function_); + unsigned fixed_size = ComputeJavascriptFixedSize(function_); // The fp-to-sp delta already takes the context, constant pool pointer and the // function into account so we have to avoid double counting them. unsigned result = fixed_size + fp_to_sp_delta_ - @@ -1777,7 +1995,7 @@ unsigned Deoptimizer::ComputeInputFrameSize() const { } -unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const { +unsigned Deoptimizer::ComputeJavascriptFixedSize(JSFunction* function) const { // The fixed part of the frame consists of the return address, frame // pointer, function, context, and all the incoming arguments. return ComputeIncomingArgumentSize(function) + @@ -1785,6 +2003,15 @@ unsigned Deoptimizer::ComputeFixedSize(JSFunction* function) const { } +unsigned Deoptimizer::ComputeInterpretedFixedSize(JSFunction* function) const { + // The fixed part of the frame consists of the return address, frame + // pointer, function, context, new.target, bytecode offset and all the + // incoming arguments. + return ComputeIncomingArgumentSize(function) + + InterpreterFrameConstants::kFixedFrameSize; +} + + unsigned Deoptimizer::ComputeIncomingArgumentSize(JSFunction* function) const { // The incoming arguments is the values for formal parameters and // the receiver. Every slot contains a pointer. @@ -1831,7 +2058,7 @@ void Deoptimizer::EnsureCodeForDeoptimizationEntry(Isolate* isolate, while (max_entry_id >= entry_count) entry_count *= 2; CHECK(entry_count <= Deoptimizer::kMaxNumberOfEntries); - MacroAssembler masm(isolate, NULL, 16 * KB); + MacroAssembler masm(isolate, NULL, 16 * KB, CodeObjectRequired::kYes); masm.set_emit_debug_code(false); GenerateDeoptimizationEntries(&masm, entry_count, type); CodeDesc desc; @@ -1878,8 +2105,13 @@ FrameDescription::FrameDescription(uint32_t frame_size, int FrameDescription::ComputeFixedSize() { - return StandardFrameConstants::kFixedFrameSize + - (ComputeParametersCount() + 1) * kPointerSize; + if (type_ == StackFrame::INTERPRETED) { + return InterpreterFrameConstants::kFixedFrameSize + + (ComputeParametersCount() + 1) * kPointerSize; + } else { + return StandardFrameConstants::kFixedFrameSize + + (ComputeParametersCount() + 1) * kPointerSize; + } } @@ -2017,6 +2249,15 @@ void Translation::BeginJSFrame(BailoutId node_id, } +void Translation::BeginInterpretedFrame(BailoutId bytecode_offset, + int literal_id, unsigned height) { + buffer_->Add(INTERPRETED_FRAME, zone()); + buffer_->Add(bytecode_offset.ToInt(), zone()); + buffer_->Add(literal_id, zone()); + buffer_->Add(height, zone()); +} + + void Translation::BeginCompiledStubFrame(int height) { buffer_->Add(COMPILED_STUB_FRAME, zone()); buffer_->Add(height, zone()); @@ -2149,6 +2390,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) { case CONSTRUCT_STUB_FRAME: return 2; case JS_FRAME: + case INTERPRETED_FRAME: return 3; } FATAL("Unexpected translation type"); @@ -2622,6 +2864,15 @@ TranslatedFrame TranslatedFrame::JSFrame(BailoutId node_id, } +TranslatedFrame TranslatedFrame::InterpretedFrame( + BailoutId bytecode_offset, SharedFunctionInfo* shared_info, int height) { + TranslatedFrame frame(kInterpretedFunction, shared_info->GetIsolate(), + shared_info, height); + frame.node_id_ = bytecode_offset; + return frame; +} + + TranslatedFrame TranslatedFrame::AccessorFrame( Kind kind, SharedFunctionInfo* shared_info) { DCHECK(kind == kSetter || kind == kGetter); @@ -2648,9 +2899,17 @@ int TranslatedFrame::GetValueCount() { case kFunction: { int parameter_count = raw_shared_info_->internal_formal_parameter_count() + 1; + // + 1 for function. return height_ + parameter_count + 1; } + case kInterpretedFunction: { + int parameter_count = + raw_shared_info_->internal_formal_parameter_count() + 1; + // + 3 for function, context and accumulator. + return height_ + parameter_count + 3; + } + case kGetter: return 2; // Function and receiver. @@ -2706,6 +2965,24 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame( return TranslatedFrame::JSFrame(node_id, shared_info, height); } + case Translation::INTERPRETED_FRAME: { + BailoutId bytecode_offset = BailoutId(iterator->Next()); + SharedFunctionInfo* shared_info = + SharedFunctionInfo::cast(literal_array->get(iterator->Next())); + int height = iterator->Next(); + if (trace_file != nullptr) { + base::SmartArrayPointer<char> name = + shared_info->DebugName()->ToCString(); + PrintF(trace_file, " reading input frame %s", name.get()); + int arg_count = shared_info->internal_formal_parameter_count() + 1; + PrintF(trace_file, + " => bytecode_offset=%d, args=%d, height=%d; inputs:\n", + bytecode_offset.ToInt(), arg_count, height); + } + return TranslatedFrame::InterpretedFrame(bytecode_offset, shared_info, + height); + } + case Translation::ARGUMENTS_ADAPTOR_FRAME: { SharedFunctionInfo* shared_info = SharedFunctionInfo::cast(literal_array->get(iterator->Next())); @@ -2818,6 +3095,7 @@ TranslatedValue TranslatedState::CreateNextTranslatedValue( switch (opcode) { case Translation::BEGIN: case Translation::JS_FRAME: + case Translation::INTERPRETED_FRAME: case Translation::ARGUMENTS_ADAPTOR_FRAME: case Translation::CONSTRUCT_STUB_FRAME: case Translation::GETTER_STUB_FRAME: @@ -3212,6 +3490,42 @@ Handle<Object> TranslatedState::MaterializeAt(int frame_index, object->set_length(*length); return object; } + case FIXED_ARRAY_TYPE: { + Handle<Object> lengthObject = MaterializeAt(frame_index, value_index); + int32_t length = 0; + CHECK(lengthObject->ToInt32(&length)); + Handle<FixedArray> object = + isolate_->factory()->NewFixedArray(length); + // We need to set the map, because the fixed array we are + // materializing could be a context or an arguments object, + // in which case we must retain that information. + object->set_map(*map); + slot->value_ = object; + for (int i = 0; i < length; ++i) { + Handle<Object> value = MaterializeAt(frame_index, value_index); + object->set(i, *value); + } + return object; + } + case FIXED_DOUBLE_ARRAY_TYPE: { + DCHECK_EQ(*map, isolate_->heap()->fixed_double_array_map()); + Handle<Object> lengthObject = MaterializeAt(frame_index, value_index); + int32_t length = 0; + CHECK(lengthObject->ToInt32(&length)); + Handle<FixedArrayBase> object = + isolate_->factory()->NewFixedDoubleArray(length); + slot->value_ = object; + if (length > 0) { + Handle<FixedDoubleArray> double_array = + Handle<FixedDoubleArray>::cast(object); + for (int i = 0; i < length; ++i) { + Handle<Object> value = MaterializeAt(frame_index, value_index); + CHECK(value->IsNumber()); + double_array->set(i, value->Number()); + } + } + return object; + } default: PrintF(stderr, "[couldn't handle instance type %d]\n", map->instance_type()); |