MIPS: Implement inlining of constructor calls.
Port r10849 (b0fe79c). Also included: Fixed a bug in GenerateRecordCallTarget. This bug prevented certain functions from being registered as Monomorphic and thus prevented them from being inlined using the new system (b0fe79c). BUG= TEST= Review URL: https://chromiumcodereview.appspot.com/9511002 Patch from Daniel Kalmar <kalmard@homejinni.com>. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10862 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
20f2c9b645
commit
66a94223db
@ -1008,6 +1008,11 @@ static void Generate_JSConstructStubHelper(MacroAssembler* masm,
|
|||||||
NullCallWrapper(), CALL_AS_METHOD);
|
NullCallWrapper(), CALL_AS_METHOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store offset of return address for deoptimizer.
|
||||||
|
if (!is_api_function && !count_constructions) {
|
||||||
|
masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
|
||||||
|
}
|
||||||
|
|
||||||
// Restore context from the frame.
|
// Restore context from the frame.
|
||||||
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
|
|
||||||
@ -1777,7 +1782,9 @@ void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
|
|||||||
|
|
||||||
__ Call(a3);
|
__ Call(a3);
|
||||||
|
|
||||||
|
// Store offset of return address for deoptimizer.
|
||||||
masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
|
masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
|
||||||
|
|
||||||
// Exit frame and return.
|
// Exit frame and return.
|
||||||
LeaveArgumentsAdaptorFrame(masm);
|
LeaveArgumentsAdaptorFrame(masm);
|
||||||
__ Ret();
|
__ Ret();
|
||||||
|
@ -5363,16 +5363,18 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
|
|||||||
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
|
// A monomorphic miss (i.e, here the cache is not uninitialized) goes
|
||||||
// megamorphic.
|
// megamorphic.
|
||||||
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
|
||||||
__ Branch(&done, eq, a3, Operand(at));
|
|
||||||
|
__ Branch(USE_DELAY_SLOT, &done, eq, a3, Operand(at));
|
||||||
|
// An uninitialized cache is patched with the function.
|
||||||
|
// Store a1 in the delay slot. This may or may not get overwritten depending
|
||||||
|
// on the result of the comparison.
|
||||||
|
__ sw(a1, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
|
||||||
|
// No need for a write barrier here - cells are rescanned.
|
||||||
|
|
||||||
// MegamorphicSentinel is an immortal immovable object (undefined) so no
|
// MegamorphicSentinel is an immortal immovable object (undefined) so no
|
||||||
// write-barrier is needed.
|
// write-barrier is needed.
|
||||||
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
|
||||||
__ sw(at, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
|
__ sw(at, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
|
||||||
__ Branch(&done);
|
|
||||||
|
|
||||||
// An uninitialized cache is patched with the function.
|
|
||||||
__ sw(a1, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
|
|
||||||
// No need for a write barrier here - cells are rescanned.
|
|
||||||
|
|
||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,6 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
|
unsigned fixed_frame_size = ArgumentsAdaptorFrameConstants::kFrameSize;
|
||||||
unsigned input_frame_size = input_->GetFrameSize();
|
|
||||||
unsigned output_frame_size = height_in_bytes + fixed_frame_size;
|
unsigned output_frame_size = height_in_bytes + fixed_frame_size;
|
||||||
|
|
||||||
// Allocate and store the output frame description.
|
// Allocate and store the output frame description.
|
||||||
@ -377,16 +376,13 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
|||||||
// Compute the incoming parameter translation.
|
// Compute the incoming parameter translation.
|
||||||
int parameter_count = height;
|
int parameter_count = height;
|
||||||
unsigned output_offset = output_frame_size;
|
unsigned output_offset = output_frame_size;
|
||||||
unsigned input_offset = input_frame_size;
|
|
||||||
for (int i = 0; i < parameter_count; ++i) {
|
for (int i = 0; i < parameter_count; ++i) {
|
||||||
output_offset -= kPointerSize;
|
output_offset -= kPointerSize;
|
||||||
DoTranslateCommand(iterator, frame_index, output_offset);
|
DoTranslateCommand(iterator, frame_index, output_offset);
|
||||||
}
|
}
|
||||||
input_offset -= (parameter_count * kPointerSize);
|
|
||||||
|
|
||||||
// Read caller's PC from the previous frame.
|
// Read caller's PC from the previous frame.
|
||||||
output_offset -= kPointerSize;
|
output_offset -= kPointerSize;
|
||||||
input_offset -= kPointerSize;
|
|
||||||
intptr_t callers_pc = output_[frame_index - 1]->GetPc();
|
intptr_t callers_pc = output_[frame_index - 1]->GetPc();
|
||||||
output_frame->SetFrameSlot(output_offset, callers_pc);
|
output_frame->SetFrameSlot(output_offset, callers_pc);
|
||||||
if (FLAG_trace_deopt) {
|
if (FLAG_trace_deopt) {
|
||||||
@ -396,7 +392,6 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
|||||||
|
|
||||||
// Read caller's FP from the previous frame, and set this frame's FP.
|
// Read caller's FP from the previous frame, and set this frame's FP.
|
||||||
output_offset -= kPointerSize;
|
output_offset -= kPointerSize;
|
||||||
input_offset -= kPointerSize;
|
|
||||||
intptr_t value = output_[frame_index - 1]->GetFp();
|
intptr_t value = output_[frame_index - 1]->GetFp();
|
||||||
output_frame->SetFrameSlot(output_offset, value);
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
intptr_t fp_value = top_address + output_offset;
|
intptr_t fp_value = top_address + output_offset;
|
||||||
@ -408,7 +403,6 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
|||||||
|
|
||||||
// A marker value is used in place of the context.
|
// A marker value is used in place of the context.
|
||||||
output_offset -= kPointerSize;
|
output_offset -= kPointerSize;
|
||||||
input_offset -= kPointerSize;
|
|
||||||
intptr_t context = reinterpret_cast<intptr_t>(
|
intptr_t context = reinterpret_cast<intptr_t>(
|
||||||
Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
||||||
output_frame->SetFrameSlot(output_offset, context);
|
output_frame->SetFrameSlot(output_offset, context);
|
||||||
@ -419,7 +413,6 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
|||||||
|
|
||||||
// The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
|
// The function was mentioned explicitly in the ARGUMENTS_ADAPTOR_FRAME.
|
||||||
output_offset -= kPointerSize;
|
output_offset -= kPointerSize;
|
||||||
input_offset -= kPointerSize;
|
|
||||||
value = reinterpret_cast<intptr_t>(function);
|
value = reinterpret_cast<intptr_t>(function);
|
||||||
output_frame->SetFrameSlot(output_offset, value);
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
if (FLAG_trace_deopt) {
|
if (FLAG_trace_deopt) {
|
||||||
@ -429,7 +422,6 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
|||||||
|
|
||||||
// Number of incoming arguments.
|
// Number of incoming arguments.
|
||||||
output_offset -= kPointerSize;
|
output_offset -= kPointerSize;
|
||||||
input_offset -= kPointerSize;
|
|
||||||
value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
|
value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
|
||||||
output_frame->SetFrameSlot(output_offset, value);
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
if (FLAG_trace_deopt) {
|
if (FLAG_trace_deopt) {
|
||||||
@ -449,6 +441,119 @@ void Deoptimizer::DoComputeArgumentsAdaptorFrame(TranslationIterator* iterator,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Deoptimizer::DoComputeConstructStubFrame(TranslationIterator* iterator,
|
||||||
|
int frame_index) {
|
||||||
|
JSFunction* function = JSFunction::cast(ComputeLiteral(iterator->Next()));
|
||||||
|
unsigned height = iterator->Next();
|
||||||
|
unsigned height_in_bytes = height * kPointerSize;
|
||||||
|
if (FLAG_trace_deopt) {
|
||||||
|
PrintF(" translating construct stub => height=%d\n", height_in_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned fixed_frame_size = 7 * kPointerSize;
|
||||||
|
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::CONSTRUCT);
|
||||||
|
|
||||||
|
// Construct stub can not be topmost or bottommost.
|
||||||
|
ASSERT(frame_index > 0 && frame_index < output_count_ - 1);
|
||||||
|
ASSERT(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.
|
||||||
|
uint32_t top_address;
|
||||||
|
top_address = output_[frame_index - 1]->GetTop() - output_frame_size;
|
||||||
|
output_frame->SetTop(top_address);
|
||||||
|
|
||||||
|
// Compute the incoming parameter translation.
|
||||||
|
int parameter_count = height;
|
||||||
|
unsigned output_offset = output_frame_size;
|
||||||
|
for (int i = 0; i < parameter_count; ++i) {
|
||||||
|
output_offset -= kPointerSize;
|
||||||
|
DoTranslateCommand(iterator, frame_index, output_offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read caller's PC from the previous frame.
|
||||||
|
output_offset -= kPointerSize;
|
||||||
|
intptr_t callers_pc = output_[frame_index - 1]->GetPc();
|
||||||
|
output_frame->SetFrameSlot(output_offset, callers_pc);
|
||||||
|
if (FLAG_trace_deopt) {
|
||||||
|
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's pc\n",
|
||||||
|
top_address + output_offset, output_offset, callers_pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read caller's FP from the previous frame, and set this frame's FP.
|
||||||
|
output_offset -= kPointerSize;
|
||||||
|
intptr_t value = output_[frame_index - 1]->GetFp();
|
||||||
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
|
intptr_t fp_value = top_address + output_offset;
|
||||||
|
output_frame->SetFp(fp_value);
|
||||||
|
if (FLAG_trace_deopt) {
|
||||||
|
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; caller's fp\n",
|
||||||
|
fp_value, output_offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The context can be gotten from the previous frame.
|
||||||
|
output_offset -= kPointerSize;
|
||||||
|
value = output_[frame_index - 1]->GetContext();
|
||||||
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
|
if (FLAG_trace_deopt) {
|
||||||
|
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
|
||||||
|
top_address + output_offset, output_offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// A marker value is used in place of the function.
|
||||||
|
output_offset -= kPointerSize;
|
||||||
|
value = reinterpret_cast<intptr_t>(Smi::FromInt(StackFrame::CONSTRUCT));
|
||||||
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
|
if (FLAG_trace_deopt) {
|
||||||
|
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; function (construct sentinel)\n",
|
||||||
|
top_address + output_offset, output_offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Number of incoming arguments.
|
||||||
|
output_offset -= kPointerSize;
|
||||||
|
value = reinterpret_cast<uint32_t>(Smi::FromInt(height - 1));
|
||||||
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
|
if (FLAG_trace_deopt) {
|
||||||
|
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; argc (%d)\n",
|
||||||
|
top_address + output_offset, output_offset, value, height - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor function being invoked by the stub.
|
||||||
|
output_offset -= kPointerSize;
|
||||||
|
value = reinterpret_cast<intptr_t>(function);
|
||||||
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
|
if (FLAG_trace_deopt) {
|
||||||
|
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; constructor function\n",
|
||||||
|
top_address + output_offset, output_offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The newly allocated object was passed as receiver in the artificial
|
||||||
|
// constructor stub environment created by HEnvironment::CopyForInlining().
|
||||||
|
output_offset -= kPointerSize;
|
||||||
|
value = output_frame->GetFrameSlot(output_frame_size - kPointerSize);
|
||||||
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
|
if (FLAG_trace_deopt) {
|
||||||
|
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; allocated receiver\n",
|
||||||
|
top_address + output_offset, output_offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(0 == output_offset);
|
||||||
|
|
||||||
|
Builtins* builtins = isolate_->builtins();
|
||||||
|
Code* construct_stub = builtins->builtin(Builtins::kJSConstructStubGeneric);
|
||||||
|
uint32_t pc = reinterpret_cast<uint32_t>(
|
||||||
|
construct_stub->instruction_start() +
|
||||||
|
isolate_->heap()->construct_stub_deopt_pc_offset()->value());
|
||||||
|
output_frame->SetPc(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// This code is very similar to ia32/arm code, but relies on register names
|
// This code is very similar to ia32/arm code, but relies on register names
|
||||||
// (fp, sp) and how the frame is laid out.
|
// (fp, sp) and how the frame is laid out.
|
||||||
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
|
void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
|
||||||
@ -561,9 +666,8 @@ void Deoptimizer::DoComputeJSFrame(TranslationIterator* iterator,
|
|||||||
value = reinterpret_cast<intptr_t>(function->context());
|
value = reinterpret_cast<intptr_t>(function->context());
|
||||||
}
|
}
|
||||||
output_frame->SetFrameSlot(output_offset, value);
|
output_frame->SetFrameSlot(output_offset, value);
|
||||||
if (is_topmost) {
|
output_frame->SetContext(value);
|
||||||
output_frame->SetRegister(cp.code(), value);
|
if (is_topmost) output_frame->SetRegister(cp.code(), value);
|
||||||
}
|
|
||||||
if (FLAG_trace_deopt) {
|
if (FLAG_trace_deopt) {
|
||||||
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
|
PrintF(" 0x%08x: [top + %d] <- 0x%08x ; context\n",
|
||||||
top_address + output_offset, output_offset, value);
|
top_address + output_offset, output_offset, value);
|
||||||
|
@ -447,10 +447,18 @@ void LCodeGen::WriteTranslation(LEnvironment* environment,
|
|||||||
|
|
||||||
WriteTranslation(environment->outer(), translation);
|
WriteTranslation(environment->outer(), translation);
|
||||||
int closure_id = DefineDeoptimizationLiteral(environment->closure());
|
int closure_id = DefineDeoptimizationLiteral(environment->closure());
|
||||||
if (environment->is_arguments_adaptor()) {
|
switch (environment->frame_type()) {
|
||||||
translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
|
case JS_FUNCTION:
|
||||||
} else {
|
|
||||||
translation->BeginJSFrame(environment->ast_id(), closure_id, height);
|
translation->BeginJSFrame(environment->ast_id(), closure_id, height);
|
||||||
|
break;
|
||||||
|
case JS_CONSTRUCT:
|
||||||
|
translation->BeginConstructStubFrame(closure_id, translation_size);
|
||||||
|
break;
|
||||||
|
case ARGUMENTS_ADAPTOR:
|
||||||
|
translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < translation_size; ++i) {
|
for (int i = 0; i < translation_size; ++i) {
|
||||||
LOperand* value = environment->values()->at(i);
|
LOperand* value = environment->values()->at(i);
|
||||||
@ -580,7 +588,7 @@ void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
|
|||||||
int jsframe_count = 0;
|
int jsframe_count = 0;
|
||||||
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
|
for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
|
||||||
++frame_count;
|
++frame_count;
|
||||||
if (!e->is_arguments_adaptor()) {
|
if (e->frame_type() == JS_FUNCTION) {
|
||||||
++jsframe_count;
|
++jsframe_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -995,10 +995,11 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
|||||||
LEnvironment* outer =
|
LEnvironment* outer =
|
||||||
CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
|
CreateEnvironment(hydrogen_env->outer(), argument_index_accumulator);
|
||||||
int ast_id = hydrogen_env->ast_id();
|
int ast_id = hydrogen_env->ast_id();
|
||||||
ASSERT(ast_id != AstNode::kNoNumber || hydrogen_env->is_arguments_adaptor());
|
ASSERT(ast_id != AstNode::kNoNumber ||
|
||||||
|
hydrogen_env->frame_type() != JS_FUNCTION);
|
||||||
int value_count = hydrogen_env->length();
|
int value_count = hydrogen_env->length();
|
||||||
LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
|
LEnvironment* result = new LEnvironment(hydrogen_env->closure(),
|
||||||
hydrogen_env->is_arguments_adaptor(),
|
hydrogen_env->frame_type(),
|
||||||
ast_id,
|
ast_id,
|
||||||
hydrogen_env->parameter_count(),
|
hydrogen_env->parameter_count(),
|
||||||
argument_count_,
|
argument_count_,
|
||||||
@ -1020,7 +1021,7 @@ LEnvironment* LChunkBuilder::CreateEnvironment(
|
|||||||
result->AddValue(op, value->representation());
|
result->AddValue(op, value->representation());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hydrogen_env->is_arguments_adaptor()) {
|
if (hydrogen_env->frame_type() == JS_FUNCTION) {
|
||||||
*argument_index_accumulator = argument_index;
|
*argument_index_accumulator = argument_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2256,7 +2257,8 @@ LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
|
|||||||
instr->arguments_count(),
|
instr->arguments_count(),
|
||||||
instr->function(),
|
instr->function(),
|
||||||
undefined,
|
undefined,
|
||||||
instr->call_kind());
|
instr->call_kind(),
|
||||||
|
instr->is_construct());
|
||||||
current_block_->UpdateEnvironment(inner);
|
current_block_->UpdateEnvironment(inner);
|
||||||
chunk_->AddInlinedClosure(instr->closure());
|
chunk_->AddInlinedClosure(instr->closure());
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user