From 23507e34db4fb3e53ba85d23477dafa890290f3c Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Thu, 6 Aug 2009 07:42:04 +0000 Subject: [PATCH] X64: Make megamorphic and normal calls use stub cache and stub code. Review URL: http://codereview.chromium.org/162009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2629 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/x64/ic-x64.cc | 162 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/src/x64/ic-x64.cc b/src/x64/ic-x64.cc index 86595331ab..86008eb325 100644 --- a/src/x64/ic-x64.cc +++ b/src/x64/ic-x64.cc @@ -562,13 +562,175 @@ void CallIC::Generate(MacroAssembler* masm, __ InvokeFunction(rdi, actual, JUMP_FUNCTION); } + +// Defined in ic.cc. +Object* CallIC_Miss(Arguments args); + void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { + // ----------- S t a t e ------------- + // rsp[0] return address + // rsp[8] argument argc + // rsp[16] argument argc - 1 + // ... + // rsp[argc * 8] argument 1 + // rsp[(argc + 1) * 8] argument 0 = reciever + // rsp[(argc + 2) * 8] function name + // ----------------------------------- + Label number, non_number, non_string, boolean, probe, miss; + + // Get the receiver of the function from the stack; 1 ~ return address. + __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); + // Get the name of the function from the stack; 2 ~ return address, receiver + __ movq(rcx, Operand(rsp, (argc + 2) * kPointerSize)); + + // Probe the stub cache. + Code::Flags flags = + Code::ComputeFlags(Code::CALL_IC, NOT_IN_LOOP, MONOMORPHIC, NORMAL, argc); + StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, rax); + + // If the stub cache probing failed, the receiver might be a value. + // For value objects, we use the map of the prototype objects for + // the corresponding JSValue for the cache and that is what we need + // to probe. + // + // Check for number. + __ testl(rdx, Immediate(kSmiTagMask)); + __ j(zero, &number); + __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rbx); + __ j(not_equal, &non_number); + __ bind(&number); + StubCompiler::GenerateLoadGlobalFunctionPrototype( + masm, Context::NUMBER_FUNCTION_INDEX, rdx); + __ jmp(&probe); + + // Check for string. + __ bind(&non_number); + __ CmpInstanceType(rbx, FIRST_NONSTRING_TYPE); + __ j(above_equal, &non_string); + StubCompiler::GenerateLoadGlobalFunctionPrototype( + masm, Context::STRING_FUNCTION_INDEX, rdx); + __ jmp(&probe); + + // Check for boolean. + __ bind(&non_string); + __ Cmp(rdx, Factory::true_value()); + __ j(equal, &boolean); + __ Cmp(rdx, Factory::false_value()); + __ j(not_equal, &miss); + __ bind(&boolean); + StubCompiler::GenerateLoadGlobalFunctionPrototype( + masm, Context::BOOLEAN_FUNCTION_INDEX, rdx); + + // Probe the stub cache for the value object. + __ bind(&probe); + StubCache::GenerateProbe(masm, flags, rdx, rcx, rbx, no_reg); + // Cache miss: Jump to runtime. + __ bind(&miss); Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); } + +static void GenerateNormalHelper(MacroAssembler* masm, + int argc, + bool is_global_object, + Label* miss) { + // Search dictionary - put result in register edx. + GenerateDictionaryLoad(masm, miss, rax, rdx, rbx, rcx); + + // Move the result to register rdi and check that it isn't a smi. + __ movq(rdi, rdx); + __ testl(rdx, Immediate(kSmiTagMask)); + __ j(zero, miss); + + // Check that the value is a JavaScript function. + __ CmpObjectType(rdx, JS_FUNCTION_TYPE, rdx); + __ j(not_equal, miss); + // Check that the function has been loaded. + __ testb(FieldOperand(rdx, Map::kBitField2Offset), + Immediate(1 << Map::kNeedsLoading)); + __ j(not_zero, miss); + + // Patch the receiver with the global proxy if necessary. + if (is_global_object) { + __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); + __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); + __ movq(Operand(rsp, (argc + 1) * kPointerSize), rdx); + } + + // Invoke the function. + ParameterCount actual(argc); + __ InvokeFunction(rdi, actual, JUMP_FUNCTION); +} + + void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { + // ----------- S t a t e ------------- + // rsp[0] return address + // rsp[8] argument argc + // rsp[16] argument argc - 1 + // ... + // rsp[argc * 8] argument 1 + // rsp[(argc + 1) * 8] argument 0 = reciever + // rsp[(argc + 2) * 8] function name + // ----------------------------------- + + Label miss, global_object, non_global_object; + + // Get the receiver of the function from the stack. + __ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize)); + // Get the name of the function from the stack. + __ movq(rcx, Operand(rsp, (argc + 2) * kPointerSize)); + + // Check that the receiver isn't a smi. + __ testl(rdx, Immediate(kSmiTagMask)); + __ j(zero, &miss); + + // Check that the receiver is a valid JS object. + // Because there are so many map checks and type checks, do not + // use CmpObjectType, but load map and type into registers. + __ movq(rbx, FieldOperand(rdx, HeapObject::kMapOffset)); + __ movb(rax, FieldOperand(rbx, Map::kInstanceTypeOffset)); + __ cmpb(rax, Immediate(FIRST_JS_OBJECT_TYPE)); + __ j(below, &miss); + + // If this assert fails, we have to check upper bound too. + ASSERT(LAST_TYPE == JS_FUNCTION_TYPE); + + // Check for access to global object. + __ cmpb(rax, Immediate(JS_GLOBAL_OBJECT_TYPE)); + __ j(equal, &global_object); + __ cmpb(rax, Immediate(JS_BUILTINS_OBJECT_TYPE)); + __ j(not_equal, &non_global_object); + + // Accessing global object: Load and invoke. + __ bind(&global_object); + // Check that the global object does not require access checks. + __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset)); + __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded)); + __ j(not_equal, &miss); + GenerateNormalHelper(masm, argc, true, &miss); + + // Accessing non-global object: Check for access to global proxy. + Label global_proxy, invoke; + __ bind(&non_global_object); + __ cmpb(rax, Immediate(JS_GLOBAL_PROXY_TYPE)); + __ j(equal, &global_proxy); + // Check that the non-global, non-global-proxy object does not + // require access checks. + __ movb(rbx, FieldOperand(rbx, Map::kBitFieldOffset)); + __ testb(rbx, Immediate(1 << Map::kIsAccessCheckNeeded)); + __ j(not_equal, &miss); + __ bind(&invoke); + GenerateNormalHelper(masm, argc, false, &miss); + + // Global object proxy access: Check access rights. + __ bind(&global_proxy); + __ CheckAccessGlobalProxy(rdx, rax, &miss); + __ jmp(&invoke); + // Cache miss: Jump to runtime. + __ bind(&miss); Generate(masm, argc, ExternalReference(IC_Utility(kCallIC_Miss))); }