Commit c29a4560 authored by ishell's avatar ishell Committed by Commit bot

[turbofan] [deoptimizer] Support inlining of ES6 tail calls.

In case when F was called with incompatible number of arguments (and therefore
the arguments adator frame was created), F inlines a tail call of G which then
deopts the deoptimizer should also remove the arguments adaptor frame for F.

This CL adds required machinery to the deoptimizer.

BUG=v8:4698
LOG=N

Review URL: https://codereview.chromium.org/1768263004

Cr-Commit-Position: refs/heads/master@{#34610}
parent e260bd53
......@@ -234,6 +234,8 @@ void Deoptimizer::TableEntryGenerator::Generate() {
}
__ pop(r0); // Restore deoptimizer object (class Deoptimizer).
__ ldr(sp, MemOperand(r0, Deoptimizer::caller_frame_top_offset()));
// Replace the current (input) frame with the output frames.
Label outer_push_loop, inner_push_loop,
outer_loop_header, inner_loop_header;
......
......@@ -126,7 +126,7 @@ void Deoptimizer::TableEntryGenerator::Generate() {
// address for lazy deoptimization.
__ Mov(code_object, lr);
// Compute the fp-to-sp delta, and correct one word for bailout id.
__ Add(fp_to_sp, masm()->StackPointer(),
__ Add(fp_to_sp, __ StackPointer(),
kSavedRegistersAreaSize + (1 * kPointerSize));
__ Sub(fp_to_sp, fp, fp_to_sp);
......@@ -209,6 +209,9 @@ void Deoptimizer::TableEntryGenerator::Generate() {
}
__ Pop(x4); // Restore deoptimizer object (class Deoptimizer).
__ Ldr(__ StackPointer(),
MemOperand(x4, Deoptimizer::caller_frame_top_offset()));
// Replace the current (input) frame with the output frames.
Label outer_push_loop, inner_push_loop,
outer_loop_header, inner_loop_header;
......
......@@ -629,6 +629,9 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
shared_info_id,
static_cast<unsigned int>(descriptor->parameters_count()));
break;
case FrameStateType::kTailCallerFunction:
translation->BeginTailCallerFrame(shared_info_id);
break;
case FrameStateType::kConstructStub:
translation->BeginConstructStubFrame(
shared_info_id,
......
......@@ -58,6 +58,9 @@ std::ostream& operator<<(std::ostream& os, FrameStateType type) {
case FrameStateType::kArgumentsAdaptor:
os << "ARGUMENTS_ADAPTOR";
break;
case FrameStateType::kTailCallerFunction:
os << "TAIL_CALLER_FRAME";
break;
case FrameStateType::kConstructStub:
os << "CONSTRUCT_STUB";
break;
......
......@@ -79,10 +79,10 @@ enum class FrameStateType {
kJavaScriptFunction, // Represents an unoptimized JavaScriptFrame.
kInterpretedFunction, // Represents an InterpretedFrame.
kArgumentsAdaptor, // Represents an ArgumentsAdaptorFrame.
kTailCallerFunction, // Represents a frame removed by tail call elimination.
kConstructStub // Represents a ConstructStubFrame.
};
class FrameStateFunctionInfo {
public:
FrameStateFunctionInfo(FrameStateType type, int parameter_count,
......
......@@ -263,6 +263,35 @@ Node* JSInliner::CreateArtificialFrameState(Node* node, Node* outer_frame_state,
node->InputAt(0), outer_frame_state);
}
Node* JSInliner::CreateTailCallerFrameState(Node* node, Node* frame_state) {
FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
Handle<SharedFunctionInfo> shared =
frame_info.shared_info().ToHandleChecked();
Node* function = frame_state->InputAt(kFrameStateFunctionInput);
// If we are inlining a tail call drop caller's frame state and an
// arguments adaptor if it exists.
frame_state = NodeProperties::GetFrameStateInput(frame_state, 0);
if (frame_state->opcode() == IrOpcode::kFrameState) {
FrameStateInfo state_info = OpParameter<FrameStateInfo>(frame_state);
if (state_info.type() == FrameStateType::kArgumentsAdaptor) {
frame_state = NodeProperties::GetFrameStateInput(frame_state, 0);
}
}
const FrameStateFunctionInfo* state_info =
jsgraph_->common()->CreateFrameStateFunctionInfo(
FrameStateType::kTailCallerFunction, 0, 0, shared);
const Operator* op = jsgraph_->common()->FrameState(
BailoutId(-1), OutputFrameStateCombine::Ignore(), state_info);
const Operator* op0 = jsgraph_->common()->StateValues(0);
Node* node0 = jsgraph_->graph()->NewNode(op0);
return jsgraph_->graph()->NewNode(op, node0, node0, node0,
jsgraph_->UndefinedConstant(), function,
frame_state);
}
namespace {
......@@ -508,6 +537,20 @@ Reduction JSInliner::ReduceJSCall(Node* node, Handle<JSFunction> function) {
NodeProperties::ReplaceEffectInput(node, convert);
}
// If we are inlining a JS call at tail position then we have to pop current
// frame state and its potential arguments adaptor frame state in order to
// make the call stack be consistent with non-inlining case.
// After that we add a tail caller frame state which lets deoptimizer handle
// the case when the outermost function inlines a tail call (it should remove
// potential arguments adaptor frame that belongs to outermost function when
// deopt happens).
if (node->opcode() == IrOpcode::kJSCallFunction) {
const CallFunctionParameters& p = CallFunctionParametersOf(node->op());
if (p.tail_call_mode() == TailCallMode::kAllow) {
frame_state = CreateTailCallerFrameState(node, frame_state);
}
}
// Insert argument adaptor frame if required. The callees formal parameter
// count (i.e. value outputs of start node minus target, receiver, new target,
// arguments count and context) have to match the number of arguments passed
......
......@@ -45,6 +45,8 @@ class JSInliner final : public AdvancedReducer {
FrameStateType frame_state_type,
Handle<SharedFunctionInfo> shared);
Node* CreateTailCallerFrameState(Node* node, Node* outer_frame_state);
Reduction InlineCall(Node* call, Node* new_target, Node* context,
Node* frame_state, Node* start, Node* end);
};
......
......@@ -711,16 +711,38 @@ void Deoptimizer::DoComputeOutputFrames() {
DeoptimizationInputData* input_data =
DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
{
// Read caller's PC, caller's FP and caller's constant pool values
// from input frame. Compute caller's frame top address.
Register fp_reg = JavaScriptFrame::fp_register();
stack_fp_ = input_->GetRegister(fp_reg.code());
caller_frame_top_ = stack_fp_ + ComputeInputFrameAboveFpFixedSize();
Address fp_address = input_->GetFramePointerAddress();
caller_fp_ = Memory::intptr_at(fp_address);
caller_pc_ =
Memory::intptr_at(fp_address + CommonFrameConstants::kCallerPCOffset);
input_frame_context_ = Memory::intptr_at(
fp_address + CommonFrameConstants::kContextOrFrameTypeOffset);
if (FLAG_enable_embedded_constant_pool) {
caller_constant_pool_ = Memory::intptr_at(
fp_address + CommonFrameConstants::kConstantPoolOffset);
}
}
if (trace_scope_ != NULL) {
timer.Start();
PrintF(trace_scope_->file(), "[deoptimizing (DEOPT %s): begin ",
MessageFor(bailout_type_));
PrintFunctionName();
PrintF(trace_scope_->file(),
" (opt #%d) @%d, FP to SP delta: %d]\n",
input_data->OptimizationId()->value(),
bailout_id_,
fp_to_sp_delta_);
" (opt #%d) @%d, FP to SP delta: %d, caller sp: 0x%08" V8PRIxPTR
"]\n",
input_data->OptimizationId()->value(), bailout_id_, fp_to_sp_delta_,
caller_frame_top_);
if (bailout_type_ == EAGER || bailout_type_ == SOFT ||
(compiled_code_->is_hydrogen_stub())) {
compiled_code_->PrintDeoptLocation(trace_scope_->file(), from_);
......@@ -763,56 +785,42 @@ void Deoptimizer::DoComputeOutputFrames() {
}
output_count_ = static_cast<int>(count);
{
// Read caller's PC, caller's FP and caller's constant pool values
// from input frame. Compute caller's frame top address.
Register fp_reg = JavaScriptFrame::fp_register();
stack_fp_ = input_->GetRegister(fp_reg.code());
caller_frame_top_ = stack_fp_ + ComputeInputFrameAboveFpFixedSize();
Address fp_address = input_->GetFramePointerAddress();
caller_fp_ = Memory::intptr_at(fp_address);
caller_pc_ =
Memory::intptr_at(fp_address + StandardFrameConstants::kCallerPCOffset);
input_frame_context_ =
Memory::intptr_at(fp_address + StandardFrameConstants::kContextOffset);
if (FLAG_enable_embedded_constant_pool) {
caller_constant_pool_ = Memory::intptr_at(
fp_address + StandardFrameConstants::kConstantPoolOffset);
}
}
// Translate each output frame.
for (size_t i = 0; i < count; ++i) {
int frame_index = 0; // output_frame_index
for (size_t i = 0; i < count; ++i, ++frame_index) {
// Read the ast node id, function, and frame height for this output frame.
int frame_index = static_cast<int>(i);
switch (translated_state_.frames()[i].kind()) {
TranslatedFrame* translated_frame = &(translated_state_.frames()[i]);
switch (translated_frame->kind()) {
case TranslatedFrame::kFunction:
DoComputeJSFrame(frame_index, deoptimizing_throw_ && i == count - 1);
DoComputeJSFrame(translated_frame, frame_index,
deoptimizing_throw_ && i == count - 1);
jsframe_count_++;
break;
case TranslatedFrame::kInterpretedFunction:
DoComputeInterpretedFrame(frame_index,
DoComputeInterpretedFrame(translated_frame, frame_index,
deoptimizing_throw_ && i == count - 1);
jsframe_count_++;
break;
case TranslatedFrame::kArgumentsAdaptor:
DoComputeArgumentsAdaptorFrame(frame_index);
DoComputeArgumentsAdaptorFrame(translated_frame, frame_index);
break;
case TranslatedFrame::kTailCallerFunction:
DoComputeTailCallerFrame(translated_frame, frame_index);
// Tail caller frame translations do not produce output frames.
frame_index--;
output_count_--;
break;
case TranslatedFrame::kConstructStub:
DoComputeConstructStubFrame(frame_index);
DoComputeConstructStubFrame(translated_frame, frame_index);
break;
case TranslatedFrame::kGetter:
DoComputeAccessorStubFrame(frame_index, false);
DoComputeAccessorStubFrame(translated_frame, frame_index, false);
break;
case TranslatedFrame::kSetter:
DoComputeAccessorStubFrame(frame_index, true);
DoComputeAccessorStubFrame(translated_frame, frame_index, true);
break;
case TranslatedFrame::kCompiledStub:
DoComputeCompiledStubFrame(frame_index);
DoComputeCompiledStubFrame(translated_frame, frame_index);
break;
case TranslatedFrame::kInvalid:
FATAL("invalid frame");
......@@ -827,19 +835,19 @@ void Deoptimizer::DoComputeOutputFrames() {
PrintF(trace_scope_->file(), "[deoptimizing (%s): end ",
MessageFor(bailout_type_));
PrintFunctionName();
PrintF(
trace_scope_->file(),
" @%d => node=%d, pc=0x%08" V8PRIxPTR ", state=%s, took %0.3f ms]\n",
bailout_id_, node_id.ToInt(), output_[index]->GetPc(),
FullCodeGenerator::State2String(static_cast<FullCodeGenerator::State>(
output_[index]->GetState()->value())),
ms);
PrintF(trace_scope_->file(),
" @%d => node=%d, pc=0x%08" V8PRIxPTR ", caller sp=0x%08" V8PRIxPTR
", state=%s, took %0.3f ms]\n",
bailout_id_, node_id.ToInt(), output_[index]->GetPc(),
caller_frame_top_, FullCodeGenerator::State2String(
static_cast<FullCodeGenerator::State>(
output_[index]->GetState()->value())),
ms);
}
}
void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
TranslatedFrame* translated_frame =
&(translated_state_.frames()[frame_index]);
void Deoptimizer::DoComputeJSFrame(TranslatedFrame* translated_frame,
int frame_index, bool goto_catch_handler) {
SharedFunctionInfo* shared = translated_frame->raw_shared_info();
TranslatedFrame::iterator value_iterator = translated_frame->begin();
......@@ -866,8 +874,6 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
PrintF(trace_scope_->file(), " translating frame ");
base::SmartArrayPointer<char> name = shared->DebugName()->ToCString();
PrintF(trace_scope_->file(), "%s", name.get());
PrintF(trace_scope_->file(),
" => node=%d, height=%d\n", node_id.ToInt(), height_in_bytes);
PrintF(trace_scope_->file(), " => node=%d, height=%d%s\n", node_id.ToInt(),
height_in_bytes, goto_catch_handler ? " (throw)" : "");
}
......@@ -1001,9 +1007,6 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
// The function was mentioned explicitly in the BEGIN_FRAME.
output_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 || reinterpret_cast<intptr_t>(function_) == value);
WriteValueToOutput(function, 0, frame_index, output_offset, "function ");
// Translate the rest of the frame.
......@@ -1070,10 +1073,9 @@ void Deoptimizer::DoComputeJSFrame(int frame_index, bool goto_catch_handler) {
}
}
void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
int frame_index,
bool goto_catch_handler) {
TranslatedFrame* translated_frame =
&(translated_state_.frames()[frame_index]);
SharedFunctionInfo* shared = translated_frame->raw_shared_info();
TranslatedFrame::iterator value_iterator = translated_frame->begin();
......@@ -1219,9 +1221,6 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
// The function was mentioned explicitly in the BEGIN_FRAME.
output_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 || reinterpret_cast<intptr_t>(function_) == value);
WriteValueToOutput(function, 0, frame_index, output_offset, "function ");
// The new.target slot is only used during function activiation which is
......@@ -1305,11 +1304,10 @@ void Deoptimizer::DoComputeInterpretedFrame(int frame_index,
}
}
void Deoptimizer::DoComputeArgumentsAdaptorFrame(int frame_index) {
TranslatedFrame* translated_frame =
&(translated_state_.frames()[frame_index]);
void Deoptimizer::DoComputeArgumentsAdaptorFrame(
TranslatedFrame* translated_frame, int frame_index) {
TranslatedFrame::iterator value_iterator = translated_frame->begin();
bool is_bottommost = (0 == frame_index);
int input_index = 0;
unsigned height = translated_frame->height();
......@@ -1331,15 +1329,19 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(int frame_index) {
FrameDescription(output_frame_size, parameter_count);
output_frame->SetFrameType(StackFrame::ARGUMENTS_ADAPTOR);
// Arguments adaptor can not be topmost or bottommost.
CHECK(frame_index > 0 && frame_index < output_count_ - 1);
// Arguments adaptor can not be topmost.
CHECK(frame_index < output_count_ - 1);
CHECK(output_[frame_index] == NULL);
output_[frame_index] = output_frame;
// The top address of the frame is computed from the previous
// frame's top and this frame's size.
intptr_t top_address;
top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
if (is_bottommost) {
top_address = caller_frame_top_ - output_frame_size;
} else {
top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
}
output_frame->SetTop(top_address);
// Compute the incoming parameter translation.
......@@ -1352,13 +1354,22 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(int frame_index) {
// Read caller's PC from the previous frame.
output_offset -= kPCOnStackSize;
intptr_t callers_pc = output_[frame_index - 1]->GetPc();
output_frame->SetCallerPc(output_offset, callers_pc);
DebugPrintOutputSlot(callers_pc, frame_index, output_offset, "caller's pc\n");
intptr_t value;
if (is_bottommost) {
value = caller_pc_;
} else {
value = output_[frame_index - 1]->GetPc();
}
output_frame->SetCallerPc(output_offset, value);
DebugPrintOutputSlot(value, frame_index, output_offset, "caller's pc\n");
// Read caller's FP from the previous frame, and set this frame's FP.
output_offset -= kFPOnStackSize;
intptr_t value = output_[frame_index - 1]->GetFp();
if (is_bottommost) {
value = caller_fp_;
} else {
value = output_[frame_index - 1]->GetFp();
}
output_frame->SetCallerFp(output_offset, value);
intptr_t fp_value = top_address + output_offset;
output_frame->SetFp(fp_value);
......@@ -1411,10 +1422,73 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(int frame_index) {
}
}
void Deoptimizer::DoComputeTailCallerFrame(TranslatedFrame* translated_frame,
int frame_index) {
SharedFunctionInfo* shared = translated_frame->raw_shared_info();
void Deoptimizer::DoComputeConstructStubFrame(int frame_index) {
TranslatedFrame* translated_frame =
&(translated_state_.frames()[frame_index]);
bool is_bottommost = (0 == frame_index);
// Tail caller frame can't be topmost.
DCHECK_NE(output_count_ - 1, frame_index);
if (trace_scope_ != NULL) {
PrintF(trace_scope_->file(), " translating tail caller frame ");
base::SmartArrayPointer<char> name = shared->DebugName()->ToCString();
PrintF(trace_scope_->file(), "%s\n", name.get());
}
if (!is_bottommost) return;
// Drop arguments adaptor frame below current frame if it exsits.
Address fp_address = input_->GetFramePointerAddress();
Address adaptor_fp_address =
Memory::Address_at(fp_address + CommonFrameConstants::kCallerFPOffset);
if (Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR) !=
Memory::Object_at(adaptor_fp_address +
CommonFrameConstants::kContextOrFrameTypeOffset)) {
return;
}
int caller_params_count =
Smi::cast(
Memory::Object_at(adaptor_fp_address +
ArgumentsAdaptorFrameConstants::kLengthOffset))
->value();
int callee_params_count =
function_->shared()->internal_formal_parameter_count();
// Both caller and callee parameters count do not include receiver.
int offset = (caller_params_count - callee_params_count) * kPointerSize;
intptr_t new_stack_fp =
reinterpret_cast<intptr_t>(adaptor_fp_address) + offset;
intptr_t new_caller_frame_top = new_stack_fp +
(callee_params_count + 1) * kPointerSize +
CommonFrameConstants::kFixedFrameSizeAboveFp;
intptr_t adaptor_caller_pc = Memory::intptr_at(
adaptor_fp_address + CommonFrameConstants::kCallerPCOffset);
intptr_t adaptor_caller_fp = Memory::intptr_at(
adaptor_fp_address + CommonFrameConstants::kCallerFPOffset);
if (trace_scope_ != NULL) {
PrintF(trace_scope_->file(),
" dropping caller arguments adaptor frame: offset=%d, "
"fp: 0x%08" V8PRIxPTR " -> 0x%08" V8PRIxPTR
", "
"caller sp: 0x%08" V8PRIxPTR " -> 0x%08" V8PRIxPTR "\n",
offset, stack_fp_, new_stack_fp, caller_frame_top_,
new_caller_frame_top);
}
stack_fp_ = new_stack_fp;
caller_frame_top_ = new_caller_frame_top;
caller_fp_ = adaptor_caller_fp;
caller_pc_ = adaptor_caller_pc;
}
void Deoptimizer::DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
int frame_index) {
TranslatedFrame::iterator value_iterator = translated_frame->begin();
int input_index = 0;
......@@ -1534,11 +1608,9 @@ void Deoptimizer::DoComputeConstructStubFrame(int frame_index) {
}
}
void Deoptimizer::DoComputeAccessorStubFrame(int frame_index,
void Deoptimizer::DoComputeAccessorStubFrame(TranslatedFrame* translated_frame,
int frame_index,
bool is_setter_stub_frame) {
TranslatedFrame* translated_frame =
&(translated_state_.frames()[frame_index]);
TranslatedFrame::iterator value_iterator = translated_frame->begin();
int input_index = 0;
......@@ -1659,8 +1731,8 @@ void Deoptimizer::DoComputeAccessorStubFrame(int frame_index,
}
}
void Deoptimizer::DoComputeCompiledStubFrame(int frame_index) {
void Deoptimizer::DoComputeCompiledStubFrame(TranslatedFrame* translated_frame,
int frame_index) {
//
// FROM TO
// | .... | | .... |
......@@ -1696,8 +1768,6 @@ void Deoptimizer::DoComputeCompiledStubFrame(int frame_index) {
// and then, if the descriptor specifies a constant number of stack
// parameters, the stack parameters as well.
TranslatedFrame* translated_frame =
&(translated_state_.frames()[frame_index]);
TranslatedFrame::iterator value_iterator = translated_frame->begin();
int input_index = 0;
......@@ -1738,8 +1808,7 @@ void Deoptimizer::DoComputeCompiledStubFrame(int frame_index) {
// context and function slots.
Register fp_reg = StubFailureTrampolineFrame::fp_register();
intptr_t top_address =
stack_fp_ - // input_->GetRegister(fp_reg.code()) -
StubFailureTrampolineFrameConstants::kFixedFrameSizeFromFp -
stack_fp_ - StubFailureTrampolineFrameConstants::kFixedFrameSizeFromFp -
height_in_bytes;
output_frame->SetTop(top_address);
......@@ -1990,15 +2059,15 @@ unsigned Deoptimizer::ComputeInputFrameAboveFpFixedSize() const {
unsigned Deoptimizer::ComputeInputFrameSize() const {
// 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 fixed_size_from_fp = ComputeInputFrameAboveFpFixedSize();
unsigned result = fixed_size_from_fp + fp_to_sp_delta_;
unsigned fixed_size_above_fp = ComputeInputFrameAboveFpFixedSize();
unsigned result = fixed_size_above_fp + fp_to_sp_delta_;
if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
unsigned stack_slots = compiled_code_->stack_slots();
unsigned outgoing_size =
ComputeOutgoingArgumentSize(compiled_code_, bailout_id_);
CHECK(result ==
fixed_size_from_fp + (stack_slots * kPointerSize) -
CommonFrameConstants::kFixedFrameSizeAboveFp + outgoing_size);
CHECK_EQ(fixed_size_above_fp + (stack_slots * kPointerSize) -
CommonFrameConstants::kFixedFrameSizeAboveFp + outgoing_size,
result);
}
return result;
}
......@@ -2196,6 +2265,10 @@ void Translation::BeginArgumentsAdaptorFrame(int literal_id, unsigned height) {
buffer_->Add(height, zone());
}
void Translation::BeginTailCallerFrame(int literal_id) {
buffer_->Add(TAIL_CALLER_FRAME, zone());
buffer_->Add(literal_id, zone());
}
void Translation::BeginJSFrame(BailoutId node_id,
int literal_id,
......@@ -2341,6 +2414,7 @@ int Translation::NumberOfOperandsFor(Opcode opcode) {
case DOUBLE_STACK_SLOT:
case LITERAL:
case COMPILED_STUB_FRAME:
case TAIL_CALLER_FRAME:
return 1;
case BEGIN:
case ARGUMENTS_ADAPTOR_FRAME:
......@@ -2900,6 +2974,11 @@ TranslatedFrame TranslatedFrame::ArgumentsAdaptorFrame(
shared_info, height);
}
TranslatedFrame TranslatedFrame::TailCallerFrame(
SharedFunctionInfo* shared_info) {
return TranslatedFrame(kTailCallerFunction, shared_info->GetIsolate(),
shared_info, 0);
}
TranslatedFrame TranslatedFrame::ConstructStubFrame(
SharedFunctionInfo* shared_info, int height) {
......@@ -2934,6 +3013,9 @@ int TranslatedFrame::GetValueCount() {
case kConstructStub:
return 1 + height_;
case kTailCallerFunction:
return 1; // Function.
case kCompiledStub:
return height_;
......@@ -3010,6 +3092,18 @@ TranslatedFrame TranslatedState::CreateNextTranslatedFrame(
return TranslatedFrame::ArgumentsAdaptorFrame(shared_info, height);
}
case Translation::TAIL_CALLER_FRAME: {
SharedFunctionInfo* shared_info =
SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
if (trace_file != nullptr) {
base::SmartArrayPointer<char> name =
shared_info->DebugName()->ToCString();
PrintF(trace_file, " reading tail caller frame marker %s\n",
name.get());
}
return TranslatedFrame::TailCallerFrame(shared_info);
}
case Translation::CONSTRUCT_STUB_FRAME: {
SharedFunctionInfo* shared_info =
SharedFunctionInfo::cast(literal_array->get(iterator->Next()));
......@@ -3110,6 +3204,7 @@ TranslatedValue TranslatedState::CreateNextTranslatedValue(
case Translation::JS_FRAME:
case Translation::INTERPRETED_FRAME:
case Translation::ARGUMENTS_ADAPTOR_FRAME:
case Translation::TAIL_CALLER_FRAME:
case Translation::CONSTRUCT_STUB_FRAME:
case Translation::GETTER_STUB_FRAME:
case Translation::SETTER_STUB_FRAME:
......
......@@ -116,6 +116,7 @@ class TranslatedFrame {
kInterpretedFunction,
kGetter,
kSetter,
kTailCallerFunction,
kArgumentsAdaptor,
kConstructStub,
kCompiledStub,
......@@ -186,6 +187,7 @@ class TranslatedFrame {
SharedFunctionInfo* shared_info);
static TranslatedFrame ArgumentsAdaptorFrame(SharedFunctionInfo* shared_info,
int height);
static TranslatedFrame TailCallerFrame(SharedFunctionInfo* shared_info);
static TranslatedFrame ConstructStubFrame(SharedFunctionInfo* shared_info,
int height);
static TranslatedFrame CompiledStubFrame(int height, Isolate* isolate) {
......@@ -529,6 +531,10 @@ class Deoptimizer : public Malloced {
}
static int output_offset() { return OFFSET_OF(Deoptimizer, output_); }
static int caller_frame_top_offset() {
return OFFSET_OF(Deoptimizer, caller_frame_top_);
}
static int GetDeoptimizedCodeCount(Isolate* isolate);
static const int kNotDeoptimizationEntry = -1;
......@@ -582,12 +588,20 @@ class Deoptimizer : public Malloced {
void DeleteFrameDescriptions();
void DoComputeOutputFrames();
void DoComputeJSFrame(int frame_index, bool goto_catch_handler);
void DoComputeInterpretedFrame(int frame_index, bool goto_catch_handler);
void DoComputeArgumentsAdaptorFrame(int frame_index);
void DoComputeConstructStubFrame(int frame_index);
void DoComputeAccessorStubFrame(int frame_index, bool is_setter_stub_frame);
void DoComputeCompiledStubFrame(int frame_index);
void DoComputeJSFrame(TranslatedFrame* translated_frame, int frame_index,
bool goto_catch_handler);
void DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
int frame_index, bool goto_catch_handler);
void DoComputeArgumentsAdaptorFrame(TranslatedFrame* translated_frame,
int frame_index);
void DoComputeTailCallerFrame(TranslatedFrame* translated_frame,
int frame_index);
void DoComputeConstructStubFrame(TranslatedFrame* translated_frame,
int frame_index);
void DoComputeAccessorStubFrame(TranslatedFrame* translated_frame,
int frame_index, bool is_setter_stub_frame);
void DoComputeCompiledStubFrame(TranslatedFrame* translated_frame,
int frame_index);
void WriteTranslatedValueToOutput(
TranslatedFrame::iterator* iterator, int* input_index, int frame_index,
......@@ -935,6 +949,7 @@ class TranslationIterator BASE_EMBEDDED {
V(GETTER_STUB_FRAME) \
V(SETTER_STUB_FRAME) \
V(ARGUMENTS_ADAPTOR_FRAME) \
V(TAIL_CALLER_FRAME) \
V(COMPILED_STUB_FRAME) \
V(DUPLICATED_OBJECT) \
V(ARGUMENTS_OBJECT) \
......@@ -978,6 +993,7 @@ class Translation BASE_EMBEDDED {
unsigned height);
void BeginCompiledStubFrame(int height);
void BeginArgumentsAdaptorFrame(int literal_id, unsigned height);
void BeginTailCallerFrame(int literal_id);
void BeginConstructStubFrame(int literal_id, unsigned height);
void BeginGetterStubFrame(int literal_id);
void BeginSetterStubFrame(int literal_id);
......
......@@ -302,7 +302,9 @@ void Deoptimizer::TableEntryGenerator::Generate() {
}
__ pop(eax);
// Replace the current frame with the output frames.
__ mov(esp, Operand(eax, Deoptimizer::caller_frame_top_offset()));
// Replace the current (input) frame with the output frames.
Label outer_push_loop, inner_push_loop,
outer_loop_header, inner_loop_header;
// Outer loop state: eax = current FrameDescription**, edx = one past the
......
......@@ -238,6 +238,8 @@ void Deoptimizer::TableEntryGenerator::Generate() {
}
__ pop(a0); // Restore deoptimizer object (class Deoptimizer).
__ lw(sp, MemOperand(a0, Deoptimizer::caller_frame_top_offset()));
// Replace the current (input) frame with the output frames.
Label outer_push_loop, inner_push_loop,
outer_loop_header, inner_loop_header;
......
......@@ -237,6 +237,8 @@ void Deoptimizer::TableEntryGenerator::Generate() {
}
__ pop(a0); // Restore deoptimizer object (class Deoptimizer).
__ ld(sp, MemOperand(a0, Deoptimizer::caller_frame_top_offset()));
// Replace the current (input) frame with the output frames.
Label outer_push_loop, inner_push_loop,
outer_loop_header, inner_loop_header;
......
......@@ -862,6 +862,8 @@ void JSFunction::JSFunctionPrint(std::ostream& os) { // NOLINT
if (has_initial_map()) os << Brief(initial_map());
os << "\n - shared_info = " << Brief(shared());
os << "\n - name = " << Brief(shared()->name());
os << "\n - formal_parameter_count = "
<< shared()->internal_formal_parameter_count();
if (shared()->is_generator()) {
os << "\n - generator";
}
......@@ -874,9 +876,10 @@ void JSFunction::JSFunctionPrint(std::ostream& os) { // NOLINT
void SharedFunctionInfo::SharedFunctionInfoPrint(std::ostream& os) { // NOLINT
HeapObject::PrintHeader(os, "SharedFunctionInfo");
os << "\n - name: " << Brief(name());
os << "\n - expected_nof_properties: " << expected_nof_properties();
os << "\n - ast_node_count: " << ast_node_count();
os << "\n - name = " << Brief(name());
os << "\n - formal_parameter_count = " << internal_formal_parameter_count();
os << "\n - expected_nof_properties = " << expected_nof_properties();
os << "\n - ast_node_count = " << ast_node_count();
os << "\n - instance class name = ";
instance_class_name()->Print(os);
os << "\n - code = " << Brief(code());
......
......@@ -14682,6 +14682,15 @@ void DeoptimizationInputData::DeoptimizationInputDataPrint(
break;
}
case Translation::TAIL_CALLER_FRAME: {
int shared_info_id = iterator.Next();
Object* shared_info = LiteralArray()->get(shared_info_id);
os << "{function="
<< Brief(SharedFunctionInfo::cast(shared_info)->DebugName())
<< "}";
break;
}
case Translation::GETTER_STUB_FRAME:
case Translation::SETTER_STUB_FRAME: {
int shared_info_id = iterator.Next();
......
......@@ -122,10 +122,6 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
deoptimizer->MaterializeHeapObjects(&it);
delete deoptimizer;
JavaScriptFrame* frame = it.frame();
RUNTIME_ASSERT(frame->function()->IsJSFunction());
DCHECK(frame->function() == *function);
// Ensure the context register is updated for materialized objects.
JavaScriptFrameIterator top_it(isolate);
JavaScriptFrame* top_frame = top_it.frame();
......@@ -135,7 +131,10 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
return isolate->heap()->undefined_value();
}
// Search for other activations of the same function and code.
// Search for other activations of the same optimized code.
// At this point {it} is at the topmost frame of all the frames materialized
// by the deoptimizer. Note that this frame does not necessarily represent
// an activation of {function} because of potential inlined tail-calls.
ActivationsFinder activations_finder(*optimized_code);
activations_finder.VisitFrames(&it);
isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
......
......@@ -231,7 +231,9 @@ void Deoptimizer::TableEntryGenerator::Generate() {
}
__ popq(rax);
// Replace the current frame with the output frames.
__ movp(rsp, Operand(rax, Deoptimizer::caller_frame_top_offset()));
// Replace the current (input) frame with the output frames.
Label outer_push_loop, inner_push_loop,
outer_loop_header, inner_loop_header;
// Outer loop state: rax = current FrameDescription**, rdx = one past the
......
......@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls --no-turbo-inlining
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --nostress-opt
// Flags: --turbo --nostress-opt
Error.prepareStackTrace = (error,stack) => {
......@@ -306,11 +306,10 @@ function run_tests() {
return source;
}
// TODO(v8:4698), TODO(ishell): support all commented cases.
var f_args_variants = ["", "1", "1, 2"];
var g_args_variants = ["", "10", "10, 20"];
var f_inlinable_variants = [/*true,*/ false];
var g_inlinable_variants = [/*true,*/ false];
var f_inlinable_variants = [true, false];
var g_inlinable_variants = [true, false];
var f_variants = [
f_cfg_sloppy,
f_cfg_strict,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment