Added helper functions for fixed register allocation.

Added helper functions to the fast code generator for temporary, ad hoc
fixed register allocation.  Also inlined some helper functions that had only
one call site to simplify the code generator API for now.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3818 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kmillikin@chromium.org 2010-02-09 10:18:51 +00:00
parent f449fded97
commit 0d6b85b812
4 changed files with 158 additions and 140 deletions

View File

@ -35,49 +35,29 @@ namespace internal {
#define __ ACCESS_MASM(masm())
void FastCodeGenerator::EmitLoadReceiver(Register reg) {
Register FastCodeGenerator::accumulator0() { return r0; }
Register FastCodeGenerator::accumulator1() { return r1; }
Register FastCodeGenerator::scratch0() { return r3; }
Register FastCodeGenerator::scratch1() { return r4; }
Register FastCodeGenerator::receiver_reg() { return r2; }
Register FastCodeGenerator::context_reg() { return cp; }
void FastCodeGenerator::EmitLoadReceiver() {
// Offset 2 is due to return address and saved frame pointer.
int index = 2 + scope()->num_parameters();
__ ldr(reg, MemOperand(sp, index * kPointerSize));
}
void FastCodeGenerator::EmitReceiverMapCheck() {
Comment cmnt(masm(), ";; MapCheck(this)");
if (FLAG_print_ir) {
PrintF("MapCheck(this)\n");
}
ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver(r1);
__ CheckMap(r1, r3, map, bailout(), false);
}
void FastCodeGenerator::EmitGlobalMapCheck() {
Comment cmnt(masm(), ";; GlobalMapCheck");
if (FLAG_print_ir) {
PrintF(";; GlobalMapCheck()");
}
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ ldr(r3, CodeGenerator::GlobalObject());
__ CheckMap(r3, r3, map, bailout(), true);
__ ldr(receiver_reg(), MemOperand(sp, index * kPointerSize));
}
void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> cell) {
ASSERT(cell->IsJSGlobalPropertyCell());
__ mov(r0, Operand(cell));
__ ldr(r0, FieldMemOperand(r0, JSGlobalPropertyCell::kValueOffset));
__ mov(accumulator0(), Operand(cell));
__ ldr(accumulator0(),
FieldMemOperand(accumulator0(), JSGlobalPropertyCell::kValueOffset));
if (FLAG_debug_code) {
__ mov(ip, Operand(Factory::the_hole_value()));
__ cmp(r0, ip);
__ cmp(accumulator0(), ip);
__ Check(ne, "DontDelete cells can't contain the hole");
}
}
@ -96,15 +76,16 @@ void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
// Negative offsets are inobject properties.
if (offset < 0) {
offset += map->instance_size();
__ mov(r2, r1); // Copy receiver for write barrier.
__ mov(scratch0(), receiver_reg()); // Copy receiver for write barrier.
} else {
offset += FixedArray::kHeaderSize;
__ ldr(r2, FieldMemOperand(r1, JSObject::kPropertiesOffset));
__ ldr(scratch0(),
FieldMemOperand(receiver_reg(), JSObject::kPropertiesOffset));
}
// Perform the store.
__ str(r0, FieldMemOperand(r2, offset));
__ mov(r3, Operand(offset));
__ RecordWrite(r2, r3, ip);
__ str(accumulator0(), FieldMemOperand(scratch0(), offset));
__ mov(scratch1(), Operand(offset));
__ RecordWrite(scratch0(), scratch1(), ip);
}
@ -119,19 +100,39 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
// Note that we keep a live register reference to cp (context) at
// this point.
// Receiver (this) is allocated to r1 if there are this properties.
if (info()->has_this_properties()) EmitReceiverMapCheck();
// Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)");
if (FLAG_print_ir) {
PrintF("MapCheck(this)\n");
}
ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver();
__ CheckMap(receiver_reg(), scratch0(), map, bailout(), false);
}
// If there is a global variable access check if the global object
// is the same as at lazy-compilation time.
if (info()->has_globals()) EmitGlobalMapCheck();
// If there is a global variable access check if the global object is the
// same as at lazy-compilation time.
if (info()->has_globals()) {
Comment cmnt(masm(), ";; MapCheck(GLOBAL)");
if (FLAG_print_ir) {
PrintF("MapCheck(GLOBAL)\n");
}
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ ldr(scratch0(), CodeGenerator::GlobalObject());
__ CheckMap(scratch0(), scratch1(), map, bailout(), true);
}
VisitStatements(function()->body());
Comment return_cmnt(masm(), ";; Return(<undefined>)");
if (FLAG_print_ir) {
PrintF("Return(<undefined>)\n");
}
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
Comment epilogue_cmnt(masm(), ";; Epilogue");
__ mov(sp, fp);
__ ldm(ia_w, sp, fp.bit() | lr.bit());
int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;

View File

@ -79,13 +79,22 @@ class FastCodeGenerator: public AstVisitor {
FunctionLiteral* function() { return info_->function(); }
Scope* scope() { return info_->scope(); }
// Platform-specific fixed registers, all guaranteed distinct.
Register accumulator0();
Register accumulator1();
Register scratch0();
Register scratch1();
Register receiver_reg();
Register context_reg();
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
// Emit code to load the receiver from the stack into a given register.
void EmitLoadReceiver(Register reg);
// Emit code to load the receiver from the stack into the fixed receiver
// register.
void EmitLoadReceiver();
// Emit code to check that the receiver has the same map as the
// compile-time receiver. Receiver is expected in {ia32-edx, x64-rdx,

View File

@ -35,48 +35,28 @@ namespace internal {
#define __ ACCESS_MASM(masm())
void FastCodeGenerator::EmitLoadReceiver(Register reg) {
Register FastCodeGenerator::accumulator0() { return eax; }
Register FastCodeGenerator::accumulator1() { return edx; }
Register FastCodeGenerator::scratch0() { return ecx; }
Register FastCodeGenerator::scratch1() { return edi; }
Register FastCodeGenerator::receiver_reg() { return ebx; }
Register FastCodeGenerator::context_reg() { return esi; }
void FastCodeGenerator::EmitLoadReceiver() {
// Offset 2 is due to return address and saved frame pointer.
int index = 2 + function()->scope()->num_parameters();
__ mov(reg, Operand(ebp, index * kPointerSize));
}
void FastCodeGenerator::EmitReceiverMapCheck() {
Comment cmnt(masm(), ";; MapCheck(this)");
if (FLAG_print_ir) {
PrintF("MapCheck(this)\n");
}
ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver(edx);
__ CheckMap(edx, map, bailout(), false);
}
void FastCodeGenerator::EmitGlobalMapCheck() {
Comment cmnt(masm(), ";; GlobalMapCheck");
if (FLAG_print_ir) {
PrintF(";; GlobalMapCheck()");
}
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ mov(ebx, CodeGenerator::GlobalObject());
__ CheckMap(ebx, map, bailout(), true);
__ mov(receiver_reg(), Operand(ebp, index * kPointerSize));
}
void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> cell) {
ASSERT(cell->IsJSGlobalPropertyCell());
__ mov(eax, Immediate(cell));
__ mov(eax, FieldOperand(eax, JSGlobalPropertyCell::kValueOffset));
__ mov(accumulator0(), Immediate(cell));
__ mov(accumulator0(),
FieldOperand(accumulator0(), JSGlobalPropertyCell::kValueOffset));
if (FLAG_debug_code) {
__ cmp(eax, Factory::the_hole_value());
__ cmp(accumulator0(), Factory::the_hole_value());
__ Check(not_equal, "DontDelete cells can't contain the hole");
}
}
@ -95,16 +75,19 @@ void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
// Negative offsets are inobject properties.
if (offset < 0) {
offset += map->instance_size();
__ mov(ecx, edx); // Copy receiver for write barrier.
__ mov(scratch0(), receiver_reg()); // Copy receiver for write barrier.
} else {
offset += FixedArray::kHeaderSize;
__ mov(ecx, FieldOperand(edx, JSObject::kPropertiesOffset));
__ mov(scratch0(),
FieldOperand(receiver_reg(), JSObject::kPropertiesOffset));
}
// Perform the store.
__ mov(FieldOperand(ecx, offset), eax);
__ mov(FieldOperand(scratch0(), offset), accumulator0());
// Preserve value from write barrier in case it's needed.
__ mov(ebx, eax);
__ RecordWrite(ecx, offset, ebx, edi);
__ mov(accumulator1(), accumulator0());
// The other accumulator register is available as a scratch register
// because this is not an AST leaf node.
__ RecordWrite(scratch0(), offset, accumulator1(), scratch1());
}
@ -121,19 +104,39 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
// Note that we keep a live register reference to esi (context) at this
// point.
// Receiver (this) is allocated to edx if there are this properties.
if (info()->has_this_properties()) EmitReceiverMapCheck();
// Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)");
if (FLAG_print_ir) {
PrintF("MapCheck(this)\n");
}
ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver();
__ CheckMap(receiver_reg(), map, bailout(), false);
}
// If there is a global variable access check if the global object
// is the same as at lazy-compilation time.
if (info()->has_globals()) EmitGlobalMapCheck();
// If there is a global variable access check if the global object is the
// same as at lazy-compilation time.
if (info()->has_globals()) {
Comment cmnt(masm(), ";; MapCheck(GLOBAL)");
if (FLAG_print_ir) {
PrintF("MapCheck(GLOBAL)\n");
}
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ mov(scratch0(), CodeGenerator::GlobalObject());
__ CheckMap(scratch0(), map, bailout(), true);
}
VisitStatements(function()->body());
Comment return_cmnt(masm(), ";; Return(<undefined>)");
if (FLAG_print_ir) {
PrintF("Return(<undefined>)\n");
}
__ mov(eax, Factory::undefined_value());
Comment epilogue_cmnt(masm(), ";; Epilogue");
__ mov(esp, ebp);
__ pop(ebp);
__ ret((scope()->num_parameters() + 1) * kPointerSize);

View File

@ -35,48 +35,30 @@ namespace internal {
#define __ ACCESS_MASM(masm())
void FastCodeGenerator::EmitLoadReceiver(Register reg) {
// Registers rcx, rdi, and r8-r15 are free to use as scratch registers
// without saving and restoring any other registers.
Register FastCodeGenerator::accumulator0() { return rax; }
Register FastCodeGenerator::accumulator1() { return rdx; }
Register FastCodeGenerator::scratch0() { return rcx; }
Register FastCodeGenerator::scratch1() { return rdi; }
Register FastCodeGenerator::receiver_reg() { return rbx; }
Register FastCodeGenerator::context_reg() { return rsi; }
void FastCodeGenerator::EmitLoadReceiver() {
// Offset 2 is due to return address and saved frame pointer.
int index = 2 + scope()->num_parameters();
__ movq(reg, Operand(rbp, index * kPointerSize));
}
void FastCodeGenerator::EmitReceiverMapCheck() {
Comment cmnt(masm(), ";; MapCheck(this)");
if (FLAG_print_ir) {
PrintF("MapCheck(this)\n");
}
ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver(rdx);
__ CheckMap(rdx, map, bailout(), false);
}
void FastCodeGenerator::EmitGlobalMapCheck() {
Comment cmnt(masm(), ";; GlobalMapCheck");
if (FLAG_print_ir) {
PrintF(";; GlobalMapCheck()");
}
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ movq(rbx, CodeGenerator::GlobalObject());
__ CheckMap(rbx, map, bailout(), true);
__ movq(receiver_reg(), Operand(rbp, index * kPointerSize));
}
void FastCodeGenerator::EmitGlobalVariableLoad(Handle<Object> cell) {
ASSERT(cell->IsJSGlobalPropertyCell());
__ Move(rax, cell);
__ movq(rax, FieldOperand(rax, JSGlobalPropertyCell::kValueOffset));
__ Move(accumulator0(), cell);
__ movq(accumulator0(),
FieldOperand(accumulator0(), JSGlobalPropertyCell::kValueOffset));
if (FLAG_debug_code) {
__ Cmp(rax, Factory::the_hole_value());
__ Cmp(accumulator0(), Factory::the_hole_value());
__ Check(not_equal, "DontDelete cells can't contain the hole");
}
}
@ -95,16 +77,19 @@ void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
// Negative offsets are inobject properties.
if (offset < 0) {
offset += map->instance_size();
__ movq(rcx, rdx); // Copy receiver for write barrier.
__ movq(scratch0(), receiver_reg()); // Copy receiver for write barrier.
} else {
offset += FixedArray::kHeaderSize;
__ movq(rcx, FieldOperand(rdx, JSObject::kPropertiesOffset));
__ movq(scratch0(),
FieldOperand(receiver_reg(), JSObject::kPropertiesOffset));
}
// Perform the store.
__ movq(FieldOperand(rcx, offset), rax);
__ movq(FieldOperand(scratch0(), offset), accumulator0());
// Preserve value from write barrier in case it's needed.
__ movq(rbx, rax);
__ RecordWrite(rcx, offset, rbx, rdi);
__ movq(accumulator1(), accumulator0());
// The other accumulator register is available as a scratch register
// because this is not an AST leaf node.
__ RecordWrite(scratch0(), offset, accumulator1(), scratch1());
}
@ -121,19 +106,39 @@ void FastCodeGenerator::Generate(CompilationInfo* compilation_info) {
// Note that we keep a live register reference to esi (context) at this
// point.
// Receiver (this) is allocated to rdx if there are this properties.
if (info()->has_this_properties()) EmitReceiverMapCheck();
// Receiver (this) is allocated to a fixed register.
if (info()->has_this_properties()) {
Comment cmnt(masm(), ";; MapCheck(this)");
if (FLAG_print_ir) {
PrintF("MapCheck(this)\n");
}
ASSERT(info()->has_receiver() && info()->receiver()->IsHeapObject());
Handle<HeapObject> object = Handle<HeapObject>::cast(info()->receiver());
Handle<Map> map(object->map());
EmitLoadReceiver();
__ CheckMap(receiver_reg(), map, bailout(), false);
}
// If there is a global variable access check if the global object
// is the same as at lazy-compilation time.
if (info()->has_globals()) EmitGlobalMapCheck();
// If there is a global variable access check if the global object is the
// same as at lazy-compilation time.
if (info()->has_globals()) {
Comment cmnt(masm(), ";; MapCheck(GLOBAL)");
if (FLAG_print_ir) {
PrintF("MapCheck(GLOBAL)\n");
}
ASSERT(info()->has_global_object());
Handle<Map> map(info()->global_object()->map());
__ movq(scratch0(), CodeGenerator::GlobalObject());
__ CheckMap(scratch0(), map, bailout(), true);
}
VisitStatements(info()->function()->body());
Comment return_cmnt(masm(), ";; Return(<undefined>)");
if (FLAG_print_ir) {
PrintF("Return(<undefined>)\n");
}
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
Comment epilogue_cmnt(masm(), ";; Epilogue");
__ movq(rsp, rbp);
__ pop(rbp);
__ ret((scope()->num_parameters() + 1) * kPointerSize);