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, ...@@ -429,14 +429,16 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
fp_value, output_offset, value); fp_value, output_offset, value);
} }
// The context can be gotten from the function so long as we don't // For the bottommost output frame the context can be gotten from the input
// optimize functions that need local contexts. // 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; output_offset -= kPointerSize;
input_offset -= kPointerSize; input_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(function->context()); if (is_bottommost) {
// The context for the bottommost output frame should also agree with the value = input_->GetFrameSlot(input_offset);
// input frame. } else {
ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); value = reinterpret_cast<intptr_t>(function->context());
}
output_frame->SetFrameSlot(output_offset, value); output_frame->SetFrameSlot(output_offset, value);
if (is_topmost) { if (is_topmost) {
output_frame->SetRegister(cp.code(), value); output_frame->SetRegister(cp.code(), value);
......
...@@ -144,6 +144,44 @@ bool LCodeGen::GeneratePrologue() { ...@@ -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. // Trace the call.
if (FLAG_trace) { if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceEnter, 0); __ CallRuntime(Runtime::kTraceEnter, 0);
...@@ -615,6 +653,12 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers, ...@@ -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, void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index) { int deoptimization_index) {
......
...@@ -221,6 +221,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -221,6 +221,7 @@ class LCodeGen BASE_EMBEDDED {
int arguments, int arguments,
int deoptimization_index); int deoptimization_index);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
void RecordSafepoint(int deoptimization_index);
void RecordSafepointWithRegisters(LPointerMap* pointers, void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index); int deoptimization_index);
......
...@@ -2275,9 +2275,6 @@ void HGraphBuilder::SetupScope(Scope* scope) { ...@@ -2275,9 +2275,6 @@ void HGraphBuilder::SetupScope(Scope* scope) {
// We don't yet handle the function name for named function expressions. // We don't yet handle the function name for named function expressions.
if (scope->function() != NULL) BAILOUT("named function expression"); 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 = HConstant* undefined_constant =
new HConstant(Factory::undefined_value(), Representation::Tagged()); new HConstant(Factory::undefined_value(), Representation::Tagged());
AddInstruction(undefined_constant); AddInstruction(undefined_constant);
...@@ -2299,6 +2296,10 @@ void HGraphBuilder::SetupScope(Scope* scope) { ...@@ -2299,6 +2296,10 @@ void HGraphBuilder::SetupScope(Scope* scope) {
// Handle the arguments and arguments shadow variables specially (they do // Handle the arguments and arguments shadow variables specially (they do
// not have declarations). // not have declarations).
if (scope->arguments() != NULL) { if (scope->arguments() != NULL) {
if (!scope->arguments()->IsStackAllocated() ||
!scope->arguments_shadow()->IsStackAllocated()) {
BAILOUT("context-allocated arguments");
}
HArgumentsObject* object = new HArgumentsObject; HArgumentsObject* object = new HArgumentsObject;
AddInstruction(object); AddInstruction(object);
graph()->SetArgumentsObject(object); graph()->SetArgumentsObject(object);
...@@ -4060,6 +4061,7 @@ bool HGraphBuilder::TryInline(Call* expr) { ...@@ -4060,6 +4061,7 @@ bool HGraphBuilder::TryInline(Call* expr) {
} }
return false; return false;
} }
if (inner_info.scope()->num_heap_slots() > 0) return false;
FunctionLiteral* function = inner_info.function(); FunctionLiteral* function = inner_info.function();
// Count the number of AST nodes added by inlining this call. // Count the number of AST nodes added by inlining this call.
......
...@@ -431,14 +431,16 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator, ...@@ -431,14 +431,16 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
fp_value, output_offset, value); fp_value, output_offset, value);
} }
// The context can be gotten from the function so long as we don't // For the bottommost output frame the context can be gotten from the input
// optimize functions that need local contexts. // 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; output_offset -= kPointerSize;
input_offset -= kPointerSize; input_offset -= kPointerSize;
value = reinterpret_cast<uint32_t>(function->context()); if (is_bottommost) {
// The context for the bottommost output frame should also agree with the value = input_->GetFrameSlot(input_offset);
// input frame. } else {
ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); value = reinterpret_cast<uint32_t>(function->context());
}
output_frame->SetFrameSlot(output_offset, value); output_frame->SetFrameSlot(output_offset, value);
if (is_topmost) output_frame->SetRegister(esi.code(), value); if (is_topmost) output_frame->SetRegister(esi.code(), value);
if (FLAG_trace_deopt) { if (FLAG_trace_deopt) {
......
...@@ -174,6 +174,45 @@ bool LCodeGen::GeneratePrologue() { ...@@ -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. // Trace the call.
if (FLAG_trace) { if (FLAG_trace) {
// We have not executed any compiled code yet, so esi still holds the // We have not executed any compiled code yet, so esi still holds the
...@@ -625,6 +664,12 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers, ...@@ -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, void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index) { int deoptimization_index) {
......
...@@ -210,6 +210,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -210,6 +210,7 @@ class LCodeGen BASE_EMBEDDED {
int arguments, int arguments,
int deoptimization_index); int deoptimization_index);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
void RecordSafepoint(int deoptimization_index);
void RecordSafepointWithRegisters(LPointerMap* pointers, void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index); int deoptimization_index);
......
...@@ -358,14 +358,16 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator, ...@@ -358,14 +358,16 @@ void Deoptimizer::DoComputeFrame(TranslationIterator* iterator,
fp_value, output_offset, value); fp_value, output_offset, value);
} }
// The context can be gotten from the function so long as we don't // For the bottommost output frame the context can be gotten from the input
// optimize functions that need local contexts. // 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; output_offset -= kPointerSize;
input_offset -= kPointerSize; input_offset -= kPointerSize;
value = reinterpret_cast<intptr_t>(function->context()); if (is_bottommost) {
// The context for the bottommost output frame should also agree with the value = input_->GetFrameSlot(input_offset);
// input frame. } else {
ASSERT(!is_bottommost || input_->GetFrameSlot(input_offset) == value); value = reinterpret_cast<intptr_t>(function->context());
}
output_frame->SetFrameSlot(output_offset, value); output_frame->SetFrameSlot(output_offset, value);
if (is_topmost) output_frame->SetRegister(rsi.code(), value); if (is_topmost) output_frame->SetRegister(rsi.code(), value);
if (FLAG_trace_deopt) { if (FLAG_trace_deopt) {
......
...@@ -163,6 +163,45 @@ bool LCodeGen::GeneratePrologue() { ...@@ -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. // Trace the call.
if (FLAG_trace) { if (FLAG_trace) {
__ CallRuntime(Runtime::kTraceEnter, 0); __ CallRuntime(Runtime::kTraceEnter, 0);
...@@ -570,6 +609,12 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers, ...@@ -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, void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index) { int deoptimization_index) {
......
...@@ -197,6 +197,7 @@ class LCodeGen BASE_EMBEDDED { ...@@ -197,6 +197,7 @@ class LCodeGen BASE_EMBEDDED {
int arguments, int arguments,
int deoptimization_index); int deoptimization_index);
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index); void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
void RecordSafepoint(int deoptimization_index);
void RecordSafepointWithRegisters(LPointerMap* pointers, void RecordSafepointWithRegisters(LPointerMap* pointers,
int arguments, int arguments,
int deoptimization_index); 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