Commit 3af35dc9 authored by rossberg@chromium.org's avatar rossberg@chromium.org

Optimize functions needing a local context.

Allocate the context in the prologue. Two issues had to be solved:
(1) deoptimization needs to handle functions with a local context,
(2) we need a safepoint in the prologue.
(Thanks to Kevin.)

Review URL: http://codereview.chromium.org/6534022

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6903 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 56788625
......@@ -429,14 +429,16 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
fp_value, output_offset, value);
}
// The context can be gotten from the function so long as we don't
// optimize functions that need local contexts.
// 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.
output_offset -= kPointerSize;
input_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(function->context());
// The context for the bottommost output frame should also agree with the
// input frame.
ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
if (is_bottommost) {
value = input_->GetFrameSlot(input_offset);
} else {
value = reinterpret_cast<intptr_t>(function->context());
}
output_frame->SetFrameSlot(output_offset, value);
if (is_topmost) {
output_frame->SetRegister(cp.code(), value);
......
......@@ -144,6 +144,44 @@ bool LCodeGen::GeneratePrologue() {
}
}
// Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
if (heap_slots > 0) {
Comment(";;; Allocate local context");
// Argument to NewContext is the function, which is in r1.
__ push(r1);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewContext, 1);
}
RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
// Context is returned in both r0 and cp. It replaces the context
// passed to us. It's saved in the stack and kept live in cp.
__ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
// Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ ldr(r0, MemOperand(fp, parameter_offset));
// Store it in the context.
__ mov(r1, Operand(Context::SlotOffset(slot->index())));
__ str(r0, MemOperand(cp, r1));
// Update the write barrier. This clobbers all involved
// registers, so we have to use two more registers to avoid
// clobbering cp.
__ mov(r2, Operand(cp));
__ RecordWrite(r2, Operand(r1), r3, r0);
}
}
Comment(";;; End allocate local context");
}
// Trace the call.
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceEnter, 0);
......@@ -615,6 +653,12 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers,
}
void LCodeGen::RecordSafepoint(int deoptimization_index) {
LPointerMap empty_pointers(RelocInfo::kNoPosition);
RecordSafepoint(&empty_pointers, deoptimization_index);
}
void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index) {
......
......@@ -221,6 +221,7 @@ class LCodeGen BASE_EMBEDDED {
int arguments,
int deoptimization_index);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
void RecordSafepoint(int deoptimization_index);
void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index);
......
......@@ -2275,9 +2275,6 @@ void HGraphBuilder::SetupScope(Scope* scope) {
// We don't yet handle the function name for named function expressions.
if (scope->function() != NULL) BAILOUT("named function expression");
// We can't handle heap-allocated locals.
if (scope->num_heap_slots() > 0) BAILOUT("heap allocated locals");
HConstant* undefined_constant =
new HConstant(Factory::undefined_value(), Representation::Tagged());
AddInstruction(undefined_constant);
......@@ -2299,6 +2296,10 @@ void HGraphBuilder::SetupScope(Scope* scope) {
// Handle the arguments and arguments shadow variables specially (they do
// not have declarations).
if (scope->arguments() != NULL) {
if (!scope->arguments()->IsStackAllocated() ||
!scope->arguments_shadow()->IsStackAllocated()) {
BAILOUT("context-allocated arguments");
}
HArgumentsObject* object = new HArgumentsObject;
AddInstruction(object);
graph()->SetArgumentsObject(object);
......@@ -4060,6 +4061,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
}
return false;
}
if (inner_info.scope()->num_heap_slots() > 0) return false;
FunctionLiteral* function = inner_info.function();
// Count the number of AST nodes added by inlining this call.
......
......@@ -431,14 +431,16 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
fp_value, output_offset, value);
}
// The context can be gotten from the function so long as we don't
// optimize functions that need local contexts.
// 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.
output_offset -= kPointerSize;
input_offset -= kPointerSize;
value = reinterpret_cast<uint32_t>(function->context());
// The context for the bottommost output frame should also agree with the
// input frame.
ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
if (is_bottommost) {
value = input_->GetFrameSlot(input_offset);
} else {
value = reinterpret_cast<uint32_t>(function->context());
}
output_frame->SetFrameSlot(output_offset, value);
if (is_topmost) output_frame->SetRegister(esi.code(), value);
if (FLAG_trace_deopt) {
......
......@@ -174,6 +174,45 @@ bool LCodeGen::GeneratePrologue() {
}
}
// Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
if (heap_slots > 0) {
Comment(";;; Allocate local context");
// Argument to NewContext is the function, which is still in edi.
__ push(edi);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewContext, 1);
}
RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
// Context is returned in both eax and esi. It replaces the context
// passed to us. It's saved in the stack and kept live in esi.
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
// Copy parameters into context if necessary.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ mov(eax, Operand(ebp, parameter_offset));
// Store it in the context.
int context_offset = Context::SlotOffset(slot->index());
__ mov(Operand(esi, context_offset), eax);
// Update the write barrier. This clobbers all involved
// registers, so we have to use a third register to avoid
// clobbering esi.
__ mov(ecx, esi);
__ RecordWrite(ecx, context_offset, eax, ebx);
}
}
Comment(";;; End allocate local context");
}
// Trace the call.
if (FLAG_trace) {
// We have not executed any compiled code yet, so esi still holds the
......@@ -625,6 +664,12 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers,
}
void LCodeGen::RecordSafepoint(int deoptimization_index) {
LPointerMap empty_pointers(RelocInfo::kNoPosition);
RecordSafepoint(&empty_pointers, deoptimization_index);
}
void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index) {
......
......@@ -210,6 +210,7 @@ class LCodeGen BASE_EMBEDDED {
int arguments,
int deoptimization_index);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
void RecordSafepoint(int deoptimization_index);
void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index);
......
......@@ -358,14 +358,16 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
fp_value, output_offset, value);
}
// The context can be gotten from the function so long as we don't
// optimize functions that need local contexts.
// 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.
output_offset -= kPointerSize;
input_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(function->context());
// The context for the bottommost output frame should also agree with the
// input frame.
ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value);
if (is_bottommost) {
value = input_->GetFrameSlot(input_offset);
} else {
value = reinterpret_cast<intptr_t>(function->context());
}
output_frame->SetFrameSlot(output_offset, value);
if (is_topmost) output_frame->SetRegister(rsi.code(), value);
if (FLAG_trace_deopt) {
......
......@@ -163,6 +163,45 @@ bool LCodeGen::GeneratePrologue() {
}
}
// Possibly allocate a local context.
int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
if (heap_slots > 0) {
Comment(";;; Allocate local context");
// Argument to NewContext is the function, which is still in rdi.
__ push(rdi);
if (heap_slots <= FastNewContextStub::kMaximumSlots) {
FastNewContextStub stub(heap_slots);
__ CallStub(&stub);
} else {
__ CallRuntime(Runtime::kNewContext, 1);
}
RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
// Context is returned in both rax and rsi. It replaces the context
// passed to us. It's saved in the stack and kept live in rsi.
__ movq(Operand(rbp, StandardFrameConstants::kContextOffset), rsi);
// Copy any necessary parameters into the context.
int num_parameters = scope()->num_parameters();
for (int i = 0; i < num_parameters; i++) {
Slot* slot = scope()->parameter(i)->AsSlot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
int parameter_offset = StandardFrameConstants::kCallerSPOffset +
(num_parameters - 1 - i) * kPointerSize;
// Load parameter from stack.
__ movq(rax, Operand(rbp, parameter_offset));
// Store it in the context.
int context_offset = Context::SlotOffset(slot->index());
__ movq(Operand(rsi, context_offset), rax);
// Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid
// clobbering rsi.
__ movq(rcx, rsi);
__ RecordWrite(rcx, context_offset, rax, rbx);
}
}
Comment(";;; End allocate local context");
}
// Trace the call.
if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceEnter, 0);
......@@ -570,6 +609,12 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers,
}
void LCodeGen::RecordSafepoint(int deoptimization_index) {
LPointerMap empty_pointers(RelocInfo::kNoPosition);
RecordSafepoint(&empty_pointers, deoptimization_index);
}
void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index) {
......
......@@ -197,6 +197,7 @@ class LCodeGen BASE_EMBEDDED {
int arguments,
int deoptimization_index);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
void RecordSafepoint(int deoptimization_index);
void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments,
int deoptimization_index);
......
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