From 9d06372cfef216a784a8f9325acb5665a92ad3f9 Mon Sep 17 00:00:00 2001 From: "feng@chromium.org" Date: Thu, 13 Nov 2008 01:18:31 +0000 Subject: [PATCH] Enable IC stubs for KeyedLaod/Store on ARM. Several functions are not complete yet, always fall back to slow case. It fixes test-api/AccessControlIC test. Review URL: http://codereview.chromium.org/10624 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@745 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/codegen-arm.cc | 19 ++- src/ic-arm.cc | 85 +++++++--- src/stub-cache-arm.cc | 360 ++++++++++++++++++++++++++++++++---------- 3 files changed, 351 insertions(+), 113 deletions(-) diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc index 9114b5af27..e5120ae734 100644 --- a/src/codegen-arm.cc +++ b/src/codegen-arm.cc @@ -3239,9 +3239,15 @@ void Reference::GetValue(TypeofState typeof_state) { // distinction between expressions in a typeof and not in a typeof. Comment cmnt(masm, "[ Load from keyed Property"); ASSERT(property != NULL); - // TODO(1224671): Implement inline caching for keyed loads as on ia32. - GetPropertyStub stub; - __ CallStub(&stub); + Handle ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); + + Variable* var = expression_->AsVariableProxy()->AsVariable(); + if (var != NULL) { + ASSERT(var->is_global()); + __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); + } else { + __ Call(ic, RelocInfo::CODE_TARGET); + } frame->Push(r0); break; } @@ -3363,9 +3369,12 @@ void Reference::SetValue(InitState init_state) { Property* property = expression_->AsProperty(); ASSERT(property != NULL); __ RecordPosition(property->position()); + + // Call IC code. + Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); + // TODO(1222589): Make the IC grab the values from the stack. frame->Pop(r0); // value - SetPropertyStub stub; - __ CallStub(&stub); + __ Call(ic, RelocInfo::CODE_TARGET); frame->Push(r0); break; } diff --git a/src/ic-arm.cc b/src/ic-arm.cc index ccaf27729e..92eb5d36dd 100644 --- a/src/ic-arm.cc +++ b/src/ic-arm.cc @@ -136,24 +136,9 @@ void LoadIC::GenerateArrayLength(MacroAssembler* masm) { __ ldr(r0, MemOperand(sp, 0)); - // Check that the receiver isn't a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &miss); - - // Check that the object is a JS array. - __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); - __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset)); - __ cmp(r1, Operand(JS_ARRAY_TYPE)); - __ b(ne, &miss); - - // Load length directly from the JS array. - __ ldr(r0, FieldMemOperand(r0, JSArray::kLengthOffset)); - __ Ret(); - - // Cache miss: Jump to runtime. + StubCompiler::GenerateLoadArrayLength(masm, r0, r3, &miss); __ bind(&miss); - Handle ic(Builtins::builtin(Builtins::LoadIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); + StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } @@ -185,7 +170,6 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) { // -- lr : return address // -- [sp] : receiver // ----------------------------------- - Label miss, load_length, check_wrapper; __ ldr(r0, MemOperand(sp, 0)); @@ -216,8 +200,7 @@ void LoadIC::GenerateStringLength(MacroAssembler* masm) { // Cache miss: Jump to runtime. __ bind(&miss); - Handle ic(Builtins::builtin(Builtins::LoadIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); + StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); } @@ -509,33 +492,87 @@ void LoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) { // -- [sp] : receiver // ----------------------------------- - __ ldr(r0, MemOperand(sp, 0)); - __ push(r0); - __ push(r2); + __ ldr(r3, MemOperand(sp, 0)); + __ stm(db_w, sp, r2.bit() | r3.bit()); // Perform tail call to the entry. __ TailCallRuntime(f, 2); } -// TODO(1224671): ICs for keyed load/store is not implemented on ARM. +// TODO(1224671): ICs for keyed load/store is not completed on ARM. +Object* KeyedLoadIC_Miss(Arguments args); + + void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) { + Generate(masm, ExternalReference(IC_Utility(kKeyedLoadIC_Miss))); } + void KeyedLoadIC::Generate(MacroAssembler* masm, const ExternalReference& f) { + // ---------- S t a t e -------------- + // -- lr : return address + // -- sp[0] : key + // -- sp[4] : receiver + __ ldm(ia, sp, r2.bit() | r3.bit()); + __ stm(db_w, sp, r2.bit() | r3.bit()); + + __ TailCallRuntime(f, 2); } + +// TODO(1224671): implement the fast case. void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { + // ---------- S t a t e -------------- + // -- lr : return address + // -- sp[0] : key + // -- sp[4] : receiver + + KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty)); } + void KeyedStoreIC::Generate(MacroAssembler* masm, const ExternalReference& f) { + // ---------- S t a t e -------------- + // -- r0 : value + // -- lr : return address + // -- sp[0] : key + // -- sp[1] : receiver + + __ ldm(ia, sp, r2.bit() | r3.bit()); + __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit()); + + __ TailCallRuntime(f, 3); } + +// TODO(1224671): implement the fast case. void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { + // ---------- S t a t e -------------- + // -- r0 : value + // -- lr : return address + // -- sp[0] : key + // -- sp[1] : receiver + + KeyedStoreIC::Generate(masm, ExternalReference(Runtime::kSetProperty)); } + void KeyedStoreIC::GenerateExtendStorage(MacroAssembler* masm) { + // ---------- S t a t e -------------- + // -- r0 : value + // -- lr : return address + // -- sp[0] : key + // -- sp[1] : receiver + // ----------- S t a t e ------------- + + __ ldm(ia, sp, r2.bit() | r3.bit()); + __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit()); + + // Perform tail call to the entry. + __ TailCallRuntime( + ExternalReference(IC_Utility(kSharedStoreIC_ExtendStorage)), 3); } diff --git a/src/stub-cache-arm.cc b/src/stub-cache-arm.cc index 2ef657e2ca..e7fe0b9bdf 100644 --- a/src/stub-cache-arm.cc +++ b/src/stub-cache-arm.cc @@ -169,6 +169,141 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, } +void StubCompiler::GenerateLoadField(MacroAssembler* masm, + JSObject* object, + JSObject* holder, + Register receiver, + Register scratch1, + Register scratch2, + int index, + Label* miss_label) { + // Check that the receiver isn't a smi. + __ tst(receiver, Operand(kSmiTagMask)); + __ b(eq, miss_label); + + // Check that the maps haven't changed. + Register reg = + __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + GenerateFastPropertyLoad(masm, r0, reg, holder, index); + __ Ret(); +} + + +void StubCompiler::GenerateLoadConstant(MacroAssembler* masm, + JSObject* object, + JSObject* holder, + Register receiver, + Register scratch1, + Register scratch2, + Object* value, + Label* miss_label) { + // Check that the receiver isn't a smi. + __ tst(receiver, Operand(kSmiTagMask)); + __ b(eq, miss_label); + + // Check that the maps haven't changed. + Register reg = + __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + + // Return the constant value. + __ mov(r0, Operand(Handle(value))); + __ Ret(); +} + + +void StubCompiler::GenerateLoadCallback(MacroAssembler* masm, + JSObject* object, + JSObject* holder, + Register receiver, + Register name, + Register scratch1, + Register scratch2, + AccessorInfo* callback, + Label* miss_label) { + // Check that the receiver isn't a smi. + __ tst(receiver, Operand(kSmiTagMask)); + __ b(eq, miss_label); + + // Check that the maps haven't changed. + Register reg = + __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + + // Push the arguments on the JS stack of the caller. + __ push(receiver); // receiver + __ mov(ip, Operand(Handle(callback))); // callback data + __ push(ip); + __ push(name); // name + __ push(reg); // holder + + // Do tail-call to the runtime system. + ExternalReference load_callback_property = + ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); + __ TailCallRuntime(load_callback_property, 4); +} + + +void StubCompiler::GenerateLoadInterceptor(MacroAssembler* masm, + JSObject* object, + JSObject* holder, + Register receiver, + Register name, + Register scratch1, + Register scratch2, + Label* miss_label) { + // Check that the receiver isn't a smi. + __ tst(receiver, Operand(kSmiTagMask)); + __ b(eq, miss_label); + + // Check that the maps haven't changed. + Register reg = + __ CheckMaps(object, receiver, holder, scratch1, scratch2, miss_label); + + // Push the arguments on the JS stack of the caller. + __ push(receiver); // receiver + __ push(reg); // holder + __ push(name); // name + + // Do tail-call to the runtime system. + ExternalReference load_ic_property = + ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)); + __ TailCallRuntime(load_ic_property, 3); +} + + +void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, + Register receiver, + Register scratch, + Label* miss_label) { + // Check that the receiver isn't a smi. + __ tst(receiver, Operand(kSmiTagMask)); + __ b(eq, miss_label); + + // Check that the object is a JS array. + __ ldr(scratch, FieldMemOperand(receiver, HeapObject::kMapOffset)); + __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset)); + __ cmp(scratch, Operand(JS_ARRAY_TYPE)); + __ b(ne, miss_label); + + // Load length directly from the JS array. + __ ldr(r0, FieldMemOperand(receiver, JSArray::kLengthOffset)); + __ Ret(); +} + + +void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { + ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); + Code* code = NULL; + if (kind == Code::LOAD_IC) { + code = Builtins::builtin(Builtins::LoadIC_Miss); + } else { + code = Builtins::builtin(Builtins::KeyedLoadIC_Miss); + } + + Handle ic(code); + __ Jump(ic, RelocInfo::CODE_TARGET); +} + + #undef __ #define __ masm()-> @@ -633,20 +768,9 @@ Object* LoadStubCompiler::CompileLoadField(JSObject* object, __ ldr(r0, MemOperand(sp, 0)); - // Check that the receiver isn't a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &miss); - - // Check that the maps haven't changed. - Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss); - GenerateFastPropertyLoad(masm(), r0, reg, holder, index); - __ Ret(); - - // Handle load cache miss. + GenerateLoadField(masm(), object, holder, r0, r3, r1, index, &miss); __ bind(&miss); - __ ldr(r0, MemOperand(sp)); // restore receiver - Handle ic(Builtins::builtin(Builtins::LoadIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); + GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. return GetCode(FIELD); @@ -666,29 +790,9 @@ Object* LoadStubCompiler::CompileLoadCallback(JSObject* object, Label miss; __ ldr(r0, MemOperand(sp, 0)); - // Check that the receiver isn't a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &miss); - - // Check that the maps haven't changed. - Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss); - - // Push the arguments on the JS stack of the caller. - __ push(r0); // receiver - __ mov(ip, Operand(Handle(callback))); // callback data - __ push(ip); - __ push(r2); // name - __ push(reg); // holder - - // Do tail-call to the runtime system. - ExternalReference load_callback_property = - ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); - __ TailCallRuntime(load_callback_property, 4); - - // Handle load cache miss. + GenerateLoadCallback(masm(), object, holder, r0, r2, r3, r1, callback, &miss); __ bind(&miss); - Handle ic(Builtins::builtin(Builtins::LoadIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); + GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. return GetCode(CALLBACKS); @@ -708,21 +812,10 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object, Label miss; __ ldr(r0, MemOperand(sp, 0)); - // Check that the receiver isn't a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &miss); - // Check that the maps haven't changed. - Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss); - - // Return the constant value. - __ mov(r0, Operand(Handle(value))); - __ Ret(); - - // Handle load cache miss. + GenerateLoadConstant(masm(), object, holder, r0, r3, r1, value, &miss); __ bind(&miss); - Handle ic(Builtins::builtin(Builtins::LoadIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); + GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. return GetCode(CONSTANT_FUNCTION); @@ -742,27 +835,10 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object, Label miss; __ ldr(r0, MemOperand(sp, 0)); - // Check that the receiver isn't a smi. - __ tst(r0, Operand(kSmiTagMask)); - __ b(eq, &miss); - // Check that the maps haven't changed. - Register reg = __ CheckMaps(object, r0, holder, r3, r1, &miss); - - // Push the arguments on the JS stack of the caller. - __ push(r0); // receiver - __ push(reg); // holder - __ push(r2); // name - - // Do tail-call to the runtime system. - ExternalReference load_ic_property = - ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)); - __ TailCallRuntime(load_ic_property, 3); - - // Handle load cache miss. + GenerateLoadInterceptor(masm(), object, holder, r0, r2, r3, r1, &miss); __ bind(&miss); - Handle ic(Builtins::builtin(Builtins::LoadIC_Miss)); - __ Jump(ic, RelocInfo::CODE_TARGET); + GenerateLoadMiss(masm(), Code::LOAD_IC); // Return the generated code. return GetCode(INTERCEPTOR); @@ -775,8 +851,25 @@ Object* KeyedLoadStubCompiler::CompileLoadField(String* name, JSObject* receiver, JSObject* holder, int index) { - UNIMPLEMENTED(); - return Heap::undefined_value(); + // ----------- S t a t e ------------- + // -- lr : return address + // -- sp[0] : key + // -- sp[4] : receiver + // ----------------------------------- + HandleScope scope; + Label miss; + + __ ldr(r2, MemOperand(sp, 0)); + __ ldr(r0, MemOperand(sp, kPointerSize)); + + __ cmp(r2, Operand(Handle(name))); + __ b(ne, &miss); + + GenerateLoadField(masm(), receiver, holder, r0, r3, r1, index, &miss); + __ bind(&miss); + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); + + return GetCode(FIELD); } @@ -784,8 +877,26 @@ Object* KeyedLoadStubCompiler::CompileLoadCallback(String* name, JSObject* receiver, JSObject* holder, AccessorInfo* callback) { - UNIMPLEMENTED(); - return Heap::undefined_value(); + // ----------- S t a t e ------------- + // -- lr : return address + // -- sp[0] : key + // -- sp[4] : receiver + // ----------------------------------- + HandleScope scope; + Label miss; + + __ ldr(r2, MemOperand(sp, 0)); + __ ldr(r0, MemOperand(sp, kPointerSize)); + + __ cmp(r2, Operand(Handle(name))); + __ b(ne, &miss); + + GenerateLoadCallback(masm(), receiver, holder, r0, r2, r3, + r1, callback, &miss); + __ bind(&miss); + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); + + return GetCode(CALLBACKS); } @@ -793,45 +904,126 @@ Object* KeyedLoadStubCompiler::CompileLoadConstant(String* name, JSObject* receiver, JSObject* holder, Object* value) { - UNIMPLEMENTED(); - return Heap::undefined_value(); + // ----------- S t a t e ------------- + // -- lr : return address + // -- sp[0] : key + // -- sp[4] : receiver + // ----------------------------------- + HandleScope scope; + Label miss; + + // Check the key is the cached one + __ ldr(r2, MemOperand(sp, 0)); + __ ldr(r0, MemOperand(sp, kPointerSize)); + + __ cmp(r2, Operand(Handle(name))); + __ b(ne, &miss); + + GenerateLoadConstant(masm(), receiver, holder, r0, r3, r1, value, &miss); + __ bind(&miss); + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); + + // Return the generated code. + return GetCode(CONSTANT_FUNCTION); } Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, JSObject* holder, String* name) { - UNIMPLEMENTED(); - return Heap::undefined_value(); + // ----------- S t a t e ------------- + // -- lr : return address + // -- sp[0] : key + // -- sp[4] : receiver + // ----------------------------------- + HandleScope scope; + Label miss; + + // Check the key is the cached one + __ ldr(r2, MemOperand(sp, 0)); + __ ldr(r0, MemOperand(sp, kPointerSize)); + + __ cmp(r2, Operand(Handle(name))); + __ b(ne, &miss); + + GenerateLoadInterceptor(masm(), receiver, holder, r0, r2, r3, r1, &miss); + __ bind(&miss); + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); + + return GetCode(INTERCEPTOR); } Object* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { - UNIMPLEMENTED(); - return Heap::undefined_value(); + // ----------- S t a t e ------------- + // -- lr : return address + // -- sp[0] : key + // -- sp[4] : receiver + // ----------------------------------- + HandleScope scope; + Label miss; + + // Check the key is the cached one + __ ldr(r2, MemOperand(sp, 0)); + __ ldr(r0, MemOperand(sp, kPointerSize)); + + __ cmp(r2, Operand(Handle(name))); + __ b(ne, &miss); + + GenerateLoadArrayLength(masm(), r0, r3, &miss); + __ bind(&miss); + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); + + return GetCode(CALLBACKS); } +// TODO(1224671): implement the fast case. Object* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { - UNIMPLEMENTED(); - return Heap::undefined_value(); + // ----------- S t a t e ------------- + // -- lr : return address + // -- sp[0] : key + // -- sp[4] : receiver + // ----------------------------------- + HandleScope scope; + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); + + return GetCode(CALLBACKS); } +// TODO(1224671): implement the fast case. Object* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { - UNIMPLEMENTED(); - return Heap::undefined_value(); + // ----------- S t a t e ------------- + // -- lr : return address + // -- sp[0] : key + // -- sp[4] : receiver + // ----------------------------------- + HandleScope scope; + GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); + + return GetCode(CALLBACKS); } +// TODO(1224671): implement the fast case. Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, int index, Map* transition, String* name) { - UNIMPLEMENTED(); - return Heap::undefined_value(); -} + // ----------- S t a t e ------------- + // -- r0 : value + // -- r2 : name + // -- lr : return address + // -- [sp] : receiver + // ----------------------------------- + HandleScope scope; + Handle ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); + __ Jump(ic, RelocInfo::CODE_TARGET); + // Return the generated code. + return GetCode(transition == NULL ? FIELD : MAP_TRANSITION); +} #undef __