| Index: src/x64/ic-x64.cc
|
| ===================================================================
|
| --- src/x64/ic-x64.cc (revision 2628)
|
| +++ src/x64/ic-x64.cc (working copy)
|
| @@ -562,13 +562,175 @@
|
| __ 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)));
|
| }
|
|
|
|
|