From 02c02fe5673569a79b0b469480e9640be63d4a47 Mon Sep 17 00:00:00 2001 From: "dcarney@chromium.org" Date: Thu, 23 Jan 2014 08:14:00 +0000 Subject: [PATCH] Reland r18714 'Unify calling to GenerateFastApiCallBody before stubbing it' TBR=verwaest@chromium.org BUG= Review URL: https://codereview.chromium.org/144543004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18762 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/stub-cache-arm.cc | 280 +++++++++++++++++++--------------- src/ia32/stub-cache-ia32.cc | 282 ++++++++++++++-------------------- src/stub-cache.cc | 46 ++++-- src/stub-cache.h | 34 ++--- src/x64/stub-cache-x64.cc | 295 ++++++++++++++---------------------- 5 files changed, 428 insertions(+), 509 deletions(-) diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 8625ed6f35..987437bbd7 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -779,64 +779,72 @@ static void CompileCallLoadPropertyWithInterceptor( static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; -// Reserves space for the extra arguments to API function in the -// caller's frame. -// -// These arguments are set by CheckPrototypes and GenerateFastApiDirectCall. -static void ReserveSpaceForFastApiCall(MacroAssembler* masm, - Register scratch) { - __ mov(scratch, Operand(Smi::FromInt(0))); - for (int i = 0; i < kFastApiCallArguments; i++) { - __ push(scratch); - } -} - -// Undoes the effects of ReserveSpaceForFastApiCall. -static void FreeSpaceForFastApiCall(MacroAssembler* masm) { - __ Drop(kFastApiCallArguments); -} - - -static void GenerateFastApiDirectCall(MacroAssembler* masm, - const CallOptimization& optimization, - int argc, - bool restore_context) { +static void GenerateFastApiCallBody(MacroAssembler* masm, + const CallOptimization& optimization, + int argc, + Register holder, + Register scratch1, + Register scratch2, + Register scratch3, + bool restore_context) { // ----------- S t a t e ------------- - // -- sp[0] - sp[24] : FunctionCallbackInfo, incl. - // : holder (set by CheckPrototypes) - // -- sp[28] : last JS argument + // -- sp[0] : last JS argument // -- ... - // -- sp[(argc + 6) * 4] : first JS argument - // -- sp[(argc + 7) * 4] : receiver + // -- sp[(argc - 1) * 4] : first JS argument + // -- sp[argc * 4] : receiver // ----------------------------------- + ASSERT(optimization.is_simple_api_call()); + typedef FunctionCallbackArguments FCA; + + STATIC_ASSERT(FCA::kHolderIndex == 0); + STATIC_ASSERT(FCA::kIsolateIndex == 1); + STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2); + STATIC_ASSERT(FCA::kReturnValueOffset == 3); + STATIC_ASSERT(FCA::kDataIndex == 4); + STATIC_ASSERT(FCA::kCalleeIndex == 5); + STATIC_ASSERT(FCA::kContextSaveIndex == 6); + STATIC_ASSERT(FCA::kArgsLength == 7); + + ASSERT(!holder.is(cp)); + // Save calling context. - __ str(cp, MemOperand(sp, FCA::kContextSaveIndex * kPointerSize)); + __ push(cp); // Get the function and setup the context. Handle function = optimization.constant_function(); - __ Move(r5, function); - __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset)); - __ str(r5, MemOperand(sp, FCA::kCalleeIndex * kPointerSize)); + __ Move(scratch1, function); + __ ldr(cp, FieldMemOperand(scratch1, JSFunction::kContextOffset)); + __ push(scratch1); // Construct the FunctionCallbackInfo. Handle api_call_info = optimization.api_call_info(); Handle call_data(api_call_info->data(), masm->isolate()); + bool call_data_undefined = false; if (masm->isolate()->heap()->InNewSpace(*call_data)) { - __ Move(r0, api_call_info); - __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset)); + __ Move(scratch1, api_call_info); + __ ldr(scratch1, FieldMemOperand(scratch1, CallHandlerInfo::kDataOffset)); + } else if (call_data->IsUndefined()) { + call_data_undefined = true; + __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex); } else { - __ Move(r6, call_data); + __ Move(scratch1, call_data); } // Store call data. - __ str(r6, MemOperand(sp, FCA::kDataIndex * kPointerSize)); - // Store isolate. - __ mov(r5, Operand(ExternalReference::isolate_address(masm->isolate()))); - __ str(r5, MemOperand(sp, FCA::kIsolateIndex * kPointerSize)); + __ push(scratch1); + if (!call_data_undefined) { + __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); + } // Store ReturnValue default and ReturnValue. - __ LoadRoot(r5, Heap::kUndefinedValueRootIndex); - __ str(r5, MemOperand(sp, FCA::kReturnValueOffset * kPointerSize)); - __ str(r5, MemOperand(sp, FCA::kReturnValueDefaultValueIndex * kPointerSize)); + __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); + __ push(scratch1); + __ push(scratch1); + // Store isolate. + __ mov(scratch1, + Operand(ExternalReference::isolate_address(masm->isolate()))); + __ push(scratch1); + // holder + __ push(holder); // Prepare arguments. __ mov(r2, sp); @@ -893,6 +901,50 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm, } +// Generates call to API function. +static void GenerateFastApiCall(MacroAssembler* masm, + const CallOptimization& optimization, + int argc, + Handle map_to_holder, + CallOptimization::HolderLookup holder_lookup) { + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r1); + + // Move holder to a register + Register holder_reg = r0; + switch (holder_lookup) { + case CallOptimization::kHolderIsReceiver: + { + ASSERT(map_to_holder.is_null()); + __ ldr(holder_reg, MemOperand(sp, argc * kPointerSize)); + } + break; + case CallOptimization::kHolderIsPrototypeOfMap: + { + Handle holder(JSObject::cast(map_to_holder->prototype())); + if (!masm->isolate()->heap()->InNewSpace(*holder)) { + __ Move(holder_reg, holder); + } else { + __ Move(holder_reg, map_to_holder); + __ ldr(holder_reg, + FieldMemOperand(holder_reg, Map::kPrototypeOffset)); + } + } + break; + case CallOptimization::kHolderNotFound: + UNREACHABLE(); + } + GenerateFastApiCallBody(masm, + optimization, + argc, + holder_reg, + r1, + r2, + r3, + false); +} + + // Generate call to api function. static void GenerateFastApiCall(MacroAssembler* masm, const CallOptimization& optimization, @@ -900,26 +952,31 @@ static void GenerateFastApiCall(MacroAssembler* masm, Register scratch, int argc, Register* values) { - ASSERT(optimization.is_simple_api_call()); ASSERT(!receiver.is(scratch)); - - typedef FunctionCallbackArguments FCA; - const int stack_space = kFastApiCallArguments + argc + 1; - // Assign stack space for the call arguments. - __ sub(sp, sp, Operand(stack_space * kPointerSize)); - // Write holder to stack frame. - __ str(receiver, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); - // Write receiver to stack frame. - int index = stack_space - 1; - __ str(receiver, MemOperand(sp, index-- * kPointerSize)); + __ push(receiver); // Write the arguments to stack frame. for (int i = 0; i < argc; i++) { - ASSERT(!receiver.is(values[i])); - ASSERT(!scratch.is(values[i])); - __ str(values[i], MemOperand(sp, index-- * kPointerSize)); + Register arg = values[argc-1-i]; + ASSERT(!receiver.is(arg)); + ASSERT(!scratch.is(arg)); + __ push(arg); } - - GenerateFastApiDirectCall(masm, optimization, argc, true); + Register scratch1 = r0; + Register scratch2 = r1; + Register scratch3 = r2; + if (!r3.is(receiver)) { + __ mov(r3, receiver); + receiver = r3; + } + // Stack now matches JSFunction abi. + GenerateFastApiCallBody(masm, + optimization, + argc, + receiver, + scratch1, + scratch2, + scratch3, + true); } @@ -972,39 +1029,17 @@ class CallInterceptorCompiler BASE_EMBEDDED { ASSERT(optimization.is_constant_call()); ASSERT(!lookup->holder()->IsGlobalObject()); Counters* counters = masm->isolate()->counters(); - int depth1 = kInvalidProtoDepth; - int depth2 = kInvalidProtoDepth; - bool can_do_fast_api_call = false; - if (optimization.is_simple_api_call() && - !lookup->holder()->IsGlobalObject()) { - depth1 = optimization.GetPrototypeDepthOfExpectedType( - object, interceptor_holder); - if (depth1 == kInvalidProtoDepth) { - depth2 = optimization.GetPrototypeDepthOfExpectedType( - interceptor_holder, Handle(lookup->holder())); - } - can_do_fast_api_call = - depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; - } - __ IncrementCounter(counters->call_const_interceptor(), 1, scratch1, scratch2); - if (can_do_fast_api_call) { - __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1, - scratch1, scratch2); - ReserveSpaceForFastApiCall(masm, scratch1); - } - // Check that the maps from receiver to interceptor's holder // haven't changed and thus we can invoke interceptor. Label miss_cleanup; - Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; Register holder = stub_compiler_->CheckPrototypes( IC::CurrentTypeOf(object, masm->isolate()), receiver, interceptor_holder, scratch1, scratch2, scratch3, - name, depth1, miss); + name, miss_label); // Invoke an interceptor and if it provides a value, // branch to |regular_invoke|. @@ -1021,37 +1056,42 @@ class CallInterceptorCompiler BASE_EMBEDDED { stub_compiler_->CheckPrototypes( IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, handle(lookup->holder()), scratch1, scratch2, scratch3, - name, depth2, miss); - } else { - // CheckPrototypes has a side effect of fetching a 'holder' - // for API (object which is instanceof for the signature). It's - // safe to omit it here, as if present, it should be fetched - // by the previous CheckPrototypes. - ASSERT(depth2 == kInvalidProtoDepth); + name, miss_label); + } + + Handle lookup_map; + CallOptimization::HolderLookup holder_lookup = + CallOptimization::kHolderNotFound; + if (optimization.is_simple_api_call() && + !lookup->holder()->IsGlobalObject()) { + lookup_map = optimization.LookupHolderOfExpectedType( + object, object, interceptor_holder, &holder_lookup); + if (holder_lookup == CallOptimization::kHolderNotFound) { + lookup_map = + optimization.LookupHolderOfExpectedType( + object, + interceptor_holder, + Handle(lookup->holder()), + &holder_lookup); + } } // Invoke function. - if (can_do_fast_api_call) { - GenerateFastApiDirectCall( - masm, optimization, arguments_.immediate(), false); + if (holder_lookup != CallOptimization::kHolderNotFound) { + int argc = arguments_.immediate(); + GenerateFastApiCall(masm, + optimization, + argc, + lookup_map, + holder_lookup); } else { Handle function = optimization.constant_function(); __ Move(r0, receiver); stub_compiler_->GenerateJumpFunction(object, function); } - // Deferred code for fast API call case---clean preallocated space. - if (can_do_fast_api_call) { - __ bind(&miss_cleanup); - FreeSpaceForFastApiCall(masm); - __ b(miss_label); - } - // Invoke a regular function. __ bind(®ular_invoke); - if (can_do_fast_api_call) { - FreeSpaceForFastApiCall(masm); - } } void CompileRegular(MacroAssembler* masm, @@ -1127,7 +1167,6 @@ Register StubCompiler::CheckPrototypes(Handle type, Register scratch1, Register scratch2, Handle name, - int save_at_depth, Label* miss, PrototypeCheckType check) { Handle receiver_map(IC::TypeToMap(*type, isolate())); @@ -1144,11 +1183,6 @@ Register StubCompiler::CheckPrototypes(Handle type, Register reg = object_reg; int depth = 0; - typedef FunctionCallbackArguments FCA; - if (save_at_depth == depth) { - __ str(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); - } - Handle current = Handle::null(); if (type->IsConstant()) current = Handle::cast(type->AsConstant()); Handle prototype = Handle::null(); @@ -1214,10 +1248,6 @@ Register StubCompiler::CheckPrototypes(Handle type, } } - if (save_at_depth == depth) { - __ str(reg, MemOperand(sp, FCA::kHolderIndex * kPointerSize)); - } - // Go to the next object in the prototype chain. current = prototype; current_map = handle(current->map()); @@ -1586,36 +1616,36 @@ Handle CallStubCompiler::CompileFastApiCall( if (object->IsGlobalObject()) return Handle::null(); if (!cell.is_null()) return Handle::null(); if (!object->IsJSObject()) return Handle::null(); - int depth = optimization.GetPrototypeDepthOfExpectedType( - Handle::cast(object), holder); - if (depth == kInvalidProtoDepth) return Handle::null(); + Handle receiver = Handle::cast(object); + CallOptimization::HolderLookup holder_lookup = + CallOptimization::kHolderNotFound; + Handle lookup_map = optimization.LookupHolderOfExpectedType( + receiver, receiver, holder, &holder_lookup); + if (holder_lookup == CallOptimization::kHolderNotFound) { + return Handle::null(); + } - Label miss, miss_before_stack_reserved; - GenerateNameCheck(name, &miss_before_stack_reserved); + Label miss; + GenerateNameCheck(name, &miss); // Get the receiver from the stack. const int argc = arguments().immediate(); __ ldr(r1, MemOperand(sp, argc * kPointerSize)); // Check that the receiver isn't a smi. - __ JumpIfSmi(r1, &miss_before_stack_reserved); + __ JumpIfSmi(r1, &miss); __ IncrementCounter(counters->call_const(), 1, r0, r3); - __ IncrementCounter(counters->call_const_fast_api(), 1, r0, r3); - - ReserveSpaceForFastApiCall(masm(), r0); // Check that the maps haven't changed and find a Holder as a side effect. CheckPrototypes( IC::CurrentTypeOf(object, isolate()), - r1, holder, r0, r3, r4, name, depth, &miss); + r1, holder, r0, r3, r4, name, &miss); - GenerateFastApiDirectCall(masm(), optimization, argc, false); + GenerateFastApiCall( + masm(), optimization, argc, lookup_map, holder_lookup); - __ bind(&miss); - FreeSpaceForFastApiCall(masm()); - - HandlerFrontendFooter(&miss_before_stack_reserved); + HandlerFrontendFooter(&miss); // Return the generated code. return GetCode(function); diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 0a0e0f9689..e76bfb5f3b 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -418,82 +418,55 @@ static void CompileCallLoadPropertyWithInterceptor( static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; -// Reserves space for the extra arguments to API function in the -// caller's frame. -// -// These arguments are set by CheckPrototypes and GenerateFastApiCall. -static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { - // ----------- S t a t e ------------- - // -- esp[0] : return address - // -- esp[4] : last argument in the internal frame of the caller - // ----------------------------------- - __ pop(scratch); - for (int i = 0; i < kFastApiCallArguments; i++) { - __ push(Immediate(Smi::FromInt(0))); - } - __ push(scratch); -} - - -// Undoes the effects of ReserveSpaceForFastApiCall. -static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { - // ----------- S t a t e ------------- - // -- esp[0] : return address. - // -- esp[4] : last fast api call extra argument. - // -- ... - // -- esp[kFastApiCallArguments * 4] : first fast api call extra argument. - // -- esp[kFastApiCallArguments * 4 + 4] : last argument in the internal - // frame. - // ----------------------------------- - __ pop(scratch); - __ add(esp, Immediate(kPointerSize * kFastApiCallArguments)); - __ push(scratch); -} - - static void GenerateFastApiCallBody(MacroAssembler* masm, const CallOptimization& optimization, int argc, + Register holder, + Register scratch1, + Register scratch2, + Register scratch3, bool restore_context); - // Generates call to API function. static void GenerateFastApiCall(MacroAssembler* masm, const CallOptimization& optimization, - int argc) { - typedef FunctionCallbackArguments FCA; - // Save calling context. - __ mov(Operand(esp, (1 + FCA::kContextSaveIndex) * kPointerSize), esi); + int argc, + Handle map_to_holder, + CallOptimization::HolderLookup holder_lookup) { + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->call_const_fast_api(), 1); - // Get the function and setup the context. - Handle function = optimization.constant_function(); - __ LoadHeapObject(edi, function); - __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); - - // Construct the FunctionCallbackInfo. - __ mov(Operand(esp, (1 + FCA::kCalleeIndex) * kPointerSize), edi); - Handle api_call_info = optimization.api_call_info(); - Handle call_data(api_call_info->data(), masm->isolate()); - if (masm->isolate()->heap()->InNewSpace(*call_data)) { - __ mov(ecx, api_call_info); - __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); - __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize), ebx); - } else { - __ mov(Operand(esp, (1 + FCA::kDataIndex) * kPointerSize), - Immediate(call_data)); + // Move holder to a register + Register holder_reg = eax; + switch (holder_lookup) { + case CallOptimization::kHolderIsReceiver: + { + ASSERT(map_to_holder.is_null()); + __ mov(holder_reg, Operand(esp, (argc + 1)* kPointerSize)); + } + break; + case CallOptimization::kHolderIsPrototypeOfMap: + { + Handle holder(JSObject::cast(map_to_holder->prototype())); + if (!masm->isolate()->heap()->InNewSpace(*holder)) { + __ mov(holder_reg, holder); + } else { + __ mov(holder_reg, map_to_holder); + __ mov(holder_reg, FieldOperand(holder_reg, Map::kPrototypeOffset)); + } + } + break; + case CallOptimization::kHolderNotFound: + UNREACHABLE(); } - __ mov(Operand(esp, (1 + FCA::kIsolateIndex) * kPointerSize), - Immediate(reinterpret_cast(masm->isolate()))); - __ mov(Operand(esp, (1 + FCA::kReturnValueOffset) * kPointerSize), - masm->isolate()->factory()->undefined_value()); - __ mov(Operand(esp, (1 + FCA::kReturnValueDefaultValueIndex) * kPointerSize), - masm->isolate()->factory()->undefined_value()); - - // Prepare arguments. - STATIC_ASSERT(kFastApiCallArguments == 7); - __ lea(eax, Operand(esp, 1 * kPointerSize)); - - GenerateFastApiCallBody(masm, optimization, argc, false); + GenerateFastApiCallBody(masm, + optimization, + argc, + holder_reg, + ebx, + ecx, + edx, + false); } @@ -509,14 +482,10 @@ static void GenerateFastApiCall(MacroAssembler* masm, Register scratch3, int argc, Register* values) { - ASSERT(optimization.is_simple_api_call()); - // Copy return value. __ pop(scratch1); - // receiver __ push(receiver); - // Write the arguments to stack frame. for (int i = 0; i < argc; i++) { Register arg = values[argc-1-i]; @@ -526,6 +495,34 @@ static void GenerateFastApiCall(MacroAssembler* masm, ASSERT(!scratch3.is(arg)); __ push(arg); } + __ push(scratch1); + // Stack now matches JSFunction abi. + GenerateFastApiCallBody(masm, + optimization, + argc, + receiver, + scratch1, + scratch2, + scratch3, + true); +} + + +static void GenerateFastApiCallBody(MacroAssembler* masm, + const CallOptimization& optimization, + int argc, + Register holder, + Register scratch1, + Register scratch2, + Register scratch3, + bool restore_context) { + // ----------- S t a t e ------------- + // -- esp[0] : return address + // -- esp[4] : last argument + // -- ... + // -- esp[argc * 4] : first argument + // -- esp[(argc + 1) * 4] : receiver + ASSERT(optimization.is_simple_api_call()); typedef FunctionCallbackArguments FCA; @@ -538,6 +535,9 @@ static void GenerateFastApiCall(MacroAssembler* masm, STATIC_ASSERT(FCA::kContextSaveIndex == 6); STATIC_ASSERT(FCA::kArgsLength == 7); + __ pop(scratch1); + + ASSERT(!holder.is(esi)); // context save __ push(esi); @@ -566,7 +566,7 @@ static void GenerateFastApiCall(MacroAssembler* masm, // isolate __ push(Immediate(reinterpret_cast(isolate))); // holder - __ push(receiver); + __ push(holder); // store receiver address for GenerateFastApiCallBody ASSERT(!scratch1.is(eax)); @@ -575,28 +575,6 @@ static void GenerateFastApiCall(MacroAssembler* masm, // return address __ push(scratch1); - GenerateFastApiCallBody(masm, optimization, argc, true); -} - - -static void GenerateFastApiCallBody(MacroAssembler* masm, - const CallOptimization& optimization, - int argc, - bool restore_context) { - // ----------- S t a t e ------------- - // -- esp[0] : return address - // -- esp[4] - esp[28] : FunctionCallbackInfo, incl. - // : object passing the type check - // (set by CheckPrototypes) - // -- esp[32] : last argument - // -- ... - // -- esp[(argc + 7) * 4] : first argument - // -- esp[(argc + 8) * 4] : receiver - // - // -- eax : receiver address - // ----------------------------------- - typedef FunctionCallbackArguments FCA; - // API function gets reference to the v8::Arguments. If CPU profiler // is enabled wrapper function will be called and we need to pass // address of the callback as additional parameter, always allocate @@ -607,8 +585,6 @@ static void GenerateFastApiCallBody(MacroAssembler* masm, // it's not controlled by GC. const int kApiStackSpace = 4; - Handle api_call_info = optimization.api_call_info(); - // Function address is a foreign pointer outside V8's heap. Address function_address = v8::ToCData
(api_call_info->callback()); __ PrepareCallApiFunction(kApiArgc + kApiStackSpace); @@ -693,38 +669,16 @@ class CallInterceptorCompiler BASE_EMBEDDED { ASSERT(optimization.is_constant_call()); ASSERT(!lookup->holder()->IsGlobalObject()); - int depth1 = kInvalidProtoDepth; - int depth2 = kInvalidProtoDepth; - bool can_do_fast_api_call = false; - if (optimization.is_simple_api_call() && - !lookup->holder()->IsGlobalObject()) { - depth1 = optimization.GetPrototypeDepthOfExpectedType( - object, interceptor_holder); - if (depth1 == kInvalidProtoDepth) { - depth2 = optimization.GetPrototypeDepthOfExpectedType( - interceptor_holder, Handle(lookup->holder())); - } - can_do_fast_api_call = - depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; - } - Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->call_const_interceptor(), 1); - if (can_do_fast_api_call) { - __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1); - ReserveSpaceForFastApiCall(masm, scratch1); - } - // Check that the maps from receiver to interceptor's holder // haven't changed and thus we can invoke interceptor. - Label miss_cleanup; - Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; Register holder = stub_compiler_->CheckPrototypes( IC::CurrentTypeOf(object, masm->isolate()), receiver, interceptor_holder, scratch1, scratch2, scratch3, - name, depth1, miss); + name, miss_label); // Invoke an interceptor and if it provides a value, // branch to |regular_invoke|. @@ -741,35 +695,41 @@ class CallInterceptorCompiler BASE_EMBEDDED { stub_compiler_->CheckPrototypes( IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, handle(lookup->holder()), scratch1, scratch2, scratch3, - name, depth2, miss); - } else { - // CheckPrototypes has a side effect of fetching a 'holder' - // for API (object which is instanceof for the signature). It's - // safe to omit it here, as if present, it should be fetched - // by the previous CheckPrototypes. - ASSERT(depth2 == kInvalidProtoDepth); + name, miss_label); + } + + Handle lookup_map; + CallOptimization::HolderLookup holder_lookup = + CallOptimization::kHolderNotFound; + if (optimization.is_simple_api_call() && + !lookup->holder()->IsGlobalObject()) { + lookup_map = optimization.LookupHolderOfExpectedType( + object, object, interceptor_holder, &holder_lookup); + if (holder_lookup == CallOptimization::kHolderNotFound) { + lookup_map = + optimization.LookupHolderOfExpectedType( + object, + interceptor_holder, + Handle(lookup->holder()), + &holder_lookup); + } } // Invoke function. - if (can_do_fast_api_call) { - GenerateFastApiCall(masm, optimization, arguments_.immediate()); + if (holder_lookup != CallOptimization::kHolderNotFound) { + int argc = arguments_.immediate(); + GenerateFastApiCall(masm, + optimization, + argc, + lookup_map, + holder_lookup); } else { Handle fun = optimization.constant_function(); stub_compiler_->GenerateJumpFunction(object, fun); } - // Deferred code for fast API call case---clean preallocated space. - if (can_do_fast_api_call) { - __ bind(&miss_cleanup); - FreeSpaceForFastApiCall(masm, scratch1); - __ jmp(miss_label); - } - // Invoke a regular function. __ bind(®ular_invoke); - if (can_do_fast_api_call) { - FreeSpaceForFastApiCall(masm, scratch1); - } } void CompileRegular(MacroAssembler* masm, @@ -1190,7 +1150,6 @@ Register StubCompiler::CheckPrototypes(Handle type, Register scratch1, Register scratch2, Handle name, - int save_at_depth, Label* miss, PrototypeCheckType check) { Handle receiver_map(IC::TypeToMap(*type, isolate())); @@ -1207,11 +1166,6 @@ Register StubCompiler::CheckPrototypes(Handle type, Register reg = object_reg; int depth = 0; - const int kHolderIndex = FunctionCallbackArguments::kHolderIndex + 1; - if (save_at_depth == depth) { - __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); - } - Handle current = Handle::null(); if (type->IsConstant()) current = Handle::cast(type->AsConstant()); Handle prototype = Handle::null(); @@ -1279,10 +1233,6 @@ Register StubCompiler::CheckPrototypes(Handle type, } } - if (save_at_depth == depth) { - __ mov(Operand(esp, kHolderIndex * kPointerSize), reg); - } - // Go to the next object in the prototype chain. current = prototype; current_map = handle(current->map()); @@ -1679,45 +1629,35 @@ Handle CallStubCompiler::CompileFastApiCall( if (object->IsGlobalObject()) return Handle::null(); if (!cell.is_null()) return Handle::null(); if (!object->IsJSObject()) return Handle::null(); - int depth = optimization.GetPrototypeDepthOfExpectedType( - Handle::cast(object), holder); - if (depth == kInvalidProtoDepth) return Handle::null(); + Handle receiver = Handle::cast(object); + CallOptimization::HolderLookup holder_lookup = + CallOptimization::kHolderNotFound; + Handle lookup_map = optimization.LookupHolderOfExpectedType( + receiver, receiver, holder, &holder_lookup); + if (holder_lookup == CallOptimization::kHolderNotFound) { + return Handle::null(); + } - Label miss, miss_before_stack_reserved; - - GenerateNameCheck(name, &miss_before_stack_reserved); + Label miss; + GenerateNameCheck(name, &miss); // Get the receiver from the stack. const int argc = arguments().immediate(); __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // Check that the receiver isn't a smi. - __ JumpIfSmi(edx, &miss_before_stack_reserved); + __ JumpIfSmi(edx, &miss); Counters* counters = isolate()->counters(); __ IncrementCounter(counters->call_const(), 1); - __ IncrementCounter(counters->call_const_fast_api(), 1); - - // Allocate space for v8::Arguments implicit values. Must be initialized - // before calling any runtime function. - __ sub(esp, Immediate(kFastApiCallArguments * kPointerSize)); // Check that the maps haven't changed and find a Holder as a side effect. CheckPrototypes(IC::CurrentTypeOf(object, isolate()), edx, holder, - ebx, eax, edi, name, depth, &miss); + ebx, eax, edi, name, &miss); - // Move the return address on top of the stack. - __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize)); - __ mov(Operand(esp, 0 * kPointerSize), eax); + GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup); - // esp[2 * kPointerSize] is uninitialized, esp[3 * kPointerSize] contains - // duplicate of return address and will be overwritten. - GenerateFastApiCall(masm(), optimization, argc); - - __ bind(&miss); - __ add(esp, Immediate(kFastApiCallArguments * kPointerSize)); - - HandlerFrontendFooter(&miss_before_stack_reserved); + HandlerFrontendFooter(&miss); // Return the generated code. return GetCode(function); diff --git a/src/stub-cache.cc b/src/stub-cache.cc index e2558e82cd..89ed586c64 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -1994,20 +1994,44 @@ CallOptimization::CallOptimization(Handle function) { } -int CallOptimization::GetPrototypeDepthOfExpectedType( +Handle CallOptimization::LookupHolderOfExpectedType( + Handle receiver, Handle object, - Handle holder) const { + Handle holder, + HolderLookup* holder_lookup) const { ASSERT(is_simple_api_call()); - if (expected_receiver_type_.is_null()) return 0; - int depth = 0; - while (!object.is_identical_to(holder)) { - if (expected_receiver_type_->IsTemplateFor(object->map())) return depth; - object = Handle(JSObject::cast(object->GetPrototype())); - if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth; - ++depth; + ASSERT_EQ(kHolderNotFound, *holder_lookup); + *holder_lookup = kHolderIsReceiver; + Handle map_to_holder; + if (expected_receiver_type_.is_null()) { + // no expected type, load from receiver. + return map_to_holder; } - if (expected_receiver_type_->IsTemplateFor(holder->map())) return depth; - return kInvalidProtoDepth; + // walk down the prototype chain to the object + while (!receiver.is_identical_to(object)) { + *holder_lookup = kHolderIsPrototypeOfMap; + map_to_holder = Handle(receiver->map()); + receiver = Handle(JSObject::cast(map_to_holder->prototype())); + } + // start looking for the holder + while (!object.is_identical_to(holder)) { + Handle object_map(object->map()); + if (expected_receiver_type_->IsTemplateFor(*object_map)) { + return map_to_holder; + } + if (!object_map->is_hidden_prototype()) { + *holder_lookup = kHolderNotFound; + return Handle::null(); + } + *holder_lookup = kHolderIsPrototypeOfMap; + map_to_holder = object_map; + object = Handle(JSObject::cast(object_map->prototype())); + } + if (expected_receiver_type_->IsTemplateFor(holder->map())) { + return map_to_holder; + } + *holder_lookup = kHolderNotFound; + return Handle::null(); } diff --git a/src/stub-cache.h b/src/stub-cache.h index 737b069599..72ca16e428 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -472,9 +472,6 @@ class StubCompiler BASE_EMBEDDED { // register is only clobbered if it the same as the holder register. The // function returns a register containing the holder - either object_reg or // holder_reg. - // The function can optionally (when save_at_depth != - // kInvalidProtoDepth) save the object at the given depth by moving - // it to [esp + kPointerSize]. Register CheckPrototypes(Handle type, Register object_reg, Handle holder, @@ -483,20 +480,6 @@ class StubCompiler BASE_EMBEDDED { Register scratch2, Handle name, Label* miss, - PrototypeCheckType check = CHECK_ALL_MAPS) { - return CheckPrototypes(type, object_reg, holder, holder_reg, scratch1, - scratch2, name, kInvalidProtoDepth, miss, check); - } - - Register CheckPrototypes(Handle type, - Register object_reg, - Handle holder, - Register holder_reg, - Register scratch1, - Register scratch2, - Handle name, - int save_at_depth, - Label* miss, PrototypeCheckType check = CHECK_ALL_MAPS); void GenerateBooleanCheck(Register object, Label* miss); @@ -1028,10 +1011,19 @@ class CallOptimization BASE_EMBEDDED { return api_call_info_; } - // Returns the depth of the object having the expected type in the - // prototype chain between the two arguments. - int GetPrototypeDepthOfExpectedType(Handle object, - Handle holder) const; + enum HolderLookup { + kHolderNotFound, + kHolderIsReceiver, + kHolderIsPrototypeOfMap + }; + // Returns a map whose prototype has the expected type in the + // prototype chain between the two arguments + // null will be returned if the first argument has that property + // lookup will be set accordingly + Handle LookupHolderOfExpectedType(Handle receiver, + Handle object, + Handle holder, + HolderLookup* holder_lookup) const; bool IsCompatibleReceiver(Object* receiver) { ASSERT(is_simple_api_call()); diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 392c96be6c..dbfd419290 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -392,92 +392,57 @@ static void CompileCallLoadPropertyWithInterceptor( static const int kFastApiCallArguments = FunctionCallbackArguments::kArgsLength; -// Reserves space for the extra arguments to API function in the -// caller's frame. -// -// These arguments are set by CheckPrototypes and GenerateFastApiCall. -static void ReserveSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { - // ----------- S t a t e ------------- - // -- rsp[0] : return address - // -- rsp[8] : last argument in the internal frame of the caller - // ----------------------------------- - __ movq(scratch, StackOperandForReturnAddress(0)); - __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); - __ movq(StackOperandForReturnAddress(0), scratch); - __ Move(scratch, Smi::FromInt(0)); - StackArgumentsAccessor args(rsp, kFastApiCallArguments, - ARGUMENTS_DONT_CONTAIN_RECEIVER); - for (int i = 0; i < kFastApiCallArguments; i++) { - __ movp(args.GetArgumentOperand(i), scratch); - } -} - - -// Undoes the effects of ReserveSpaceForFastApiCall. -static void FreeSpaceForFastApiCall(MacroAssembler* masm, Register scratch) { - // ----------- S t a t e ------------- - // -- rsp[0] : return address. - // -- rsp[8] : last fast api call extra argument. - // -- ... - // -- rsp[kFastApiCallArguments * 8] : first fast api call extra - // argument. - // -- rsp[kFastApiCallArguments * 8 + 8] : last argument in the internal - // frame. - // ----------------------------------- - __ movq(scratch, StackOperandForReturnAddress(0)); - __ movq(StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize), - scratch); - __ addq(rsp, Immediate(kPointerSize * kFastApiCallArguments)); -} - - static void GenerateFastApiCallBody(MacroAssembler* masm, const CallOptimization& optimization, int argc, + Register holder, + Register scratch1, + Register scratch2, + Register scratch3, bool restore_context); // Generates call to API function. static void GenerateFastApiCall(MacroAssembler* masm, const CallOptimization& optimization, - int argc) { - typedef FunctionCallbackArguments FCA; - StackArgumentsAccessor args(rsp, argc + kFastApiCallArguments); + int argc, + Handle map_to_holder, + CallOptimization::HolderLookup holder_lookup) { + Counters* counters = masm->isolate()->counters(); + __ IncrementCounter(counters->call_const_fast_api(), 1); - // Save calling context. - int offset = argc + kFastApiCallArguments; - __ movp(args.GetArgumentOperand(offset - FCA::kContextSaveIndex), rsi); - - // Get the function and setup the context. - Handle function = optimization.constant_function(); - __ Move(rdi, function); - __ movp(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); - // Construct the FunctionCallbackInfo on the stack. - __ movp(args.GetArgumentOperand(offset - FCA::kCalleeIndex), rdi); - Handle api_call_info = optimization.api_call_info(); - Handle call_data(api_call_info->data(), masm->isolate()); - if (masm->isolate()->heap()->InNewSpace(*call_data)) { - __ Move(rcx, api_call_info); - __ movp(rbx, FieldOperand(rcx, CallHandlerInfo::kDataOffset)); - __ movp(args.GetArgumentOperand(offset - FCA::kDataIndex), rbx); - } else { - __ Move(args.GetArgumentOperand(offset - FCA::kDataIndex), call_data); + // Move holder to a register + Register holder_reg = rax; + switch (holder_lookup) { + case CallOptimization::kHolderIsReceiver: + { + ASSERT(map_to_holder.is_null()); + StackArgumentsAccessor args(rsp, argc); + __ movp(holder_reg, args.GetReceiverOperand()); + } + break; + case CallOptimization::kHolderIsPrototypeOfMap: + { + Handle holder(JSObject::cast(map_to_holder->prototype())); + if (!masm->isolate()->heap()->InNewSpace(*holder)) { + __ Move(holder_reg, holder); + } else { + __ Move(holder_reg, map_to_holder); + __ movp(holder_reg, FieldOperand(holder_reg, Map::kPrototypeOffset)); + } + } + break; + case CallOptimization::kHolderNotFound: + UNREACHABLE(); } - __ Move(kScratchRegister, - ExternalReference::isolate_address(masm->isolate())); - __ movp(args.GetArgumentOperand(offset - FCA::kIsolateIndex), - kScratchRegister); - __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex); - __ movp(args.GetArgumentOperand(offset - FCA::kReturnValueDefaultValueIndex), - kScratchRegister); - __ movp(args.GetArgumentOperand(offset - FCA::kReturnValueOffset), - kScratchRegister); - - // Prepare arguments. - STATIC_ASSERT(kFastApiCallArguments == 7); - __ lea(rax, args.GetArgumentOperand(offset - FCA::kHolderIndex)); - - GenerateFastApiCallBody(masm, optimization, argc, false); + GenerateFastApiCallBody(masm, + optimization, + argc, + holder_reg, + rbx, + rcx, + rdx, + false); } @@ -493,13 +458,9 @@ static void GenerateFastApiCall(MacroAssembler* masm, Register scratch3, int argc, Register* values) { - ASSERT(optimization.is_simple_api_call()); - __ PopReturnAddressTo(scratch1); - // receiver __ push(receiver); - // Write the arguments to stack frame. for (int i = 0; i < argc; i++) { Register arg = values[argc-1-i]; @@ -509,6 +470,35 @@ static void GenerateFastApiCall(MacroAssembler* masm, ASSERT(!scratch3.is(arg)); __ push(arg); } + __ PushReturnAddressFrom(scratch1); + // Stack now matches JSFunction abi. + GenerateFastApiCallBody(masm, + optimization, + argc, + receiver, + scratch1, + scratch2, + scratch3, + true); +} + + +static void GenerateFastApiCallBody(MacroAssembler* masm, + const CallOptimization& optimization, + int argc, + Register holder, + Register scratch1, + Register scratch2, + Register scratch3, + bool restore_context) { + // ----------- S t a t e ------------- + // -- rsp[0] : return address + // -- rsp[8] : last argument + // -- ... + // -- rsp[argc * 8] : first argument + // -- rsp[(argc + 1) * 8] : receiver + // ----------------------------------- + ASSERT(optimization.is_simple_api_call()); typedef FunctionCallbackArguments FCA; @@ -521,6 +511,9 @@ static void GenerateFastApiCall(MacroAssembler* masm, STATIC_ASSERT(FCA::kContextSaveIndex == 6); STATIC_ASSERT(FCA::kArgsLength == 7); + __ PopReturnAddressTo(scratch1); + + ASSERT(!holder.is(rsi)); // context save __ push(rsi); @@ -557,36 +550,13 @@ static void GenerateFastApiCall(MacroAssembler* masm, ExternalReference::isolate_address(masm->isolate())); __ push(scratch3); // holder - __ push(receiver); + __ push(holder); ASSERT(!scratch1.is(rax)); - // store receiver address for GenerateFastApiCallBody __ movp(rax, rsp); + // Push return address back on stack. __ PushReturnAddressFrom(scratch1); - GenerateFastApiCallBody(masm, optimization, argc, true); -} - - -static void GenerateFastApiCallBody(MacroAssembler* masm, - const CallOptimization& optimization, - int argc, - bool restore_context) { - // ----------- S t a t e ------------- - // -- rsp[0] : return address - // -- rsp[8] - rsp[56] : FunctionCallbackInfo, incl. - // : object passing the type check - // (set by CheckPrototypes) - // -- rsp[64] : last argument - // -- ... - // -- rsp[(argc + 7) * 8] : first argument - // -- rsp[(argc + 8) * 8] : receiver - // - // rax : receiver address - // ----------------------------------- - typedef FunctionCallbackArguments FCA; - - Handle api_call_info = optimization.api_call_info(); // Function address is a foreign pointer outside V8's heap. Address function_address = v8::ToCData
(api_call_info->callback()); @@ -682,38 +652,17 @@ class CallInterceptorCompiler BASE_EMBEDDED { ASSERT(optimization.is_constant_call()); ASSERT(!lookup->holder()->IsGlobalObject()); - int depth1 = kInvalidProtoDepth; - int depth2 = kInvalidProtoDepth; - bool can_do_fast_api_call = false; - if (optimization.is_simple_api_call() && - !lookup->holder()->IsGlobalObject()) { - depth1 = optimization.GetPrototypeDepthOfExpectedType( - object, interceptor_holder); - if (depth1 == kInvalidProtoDepth) { - depth2 = optimization.GetPrototypeDepthOfExpectedType( - interceptor_holder, Handle(lookup->holder())); - } - can_do_fast_api_call = - depth1 != kInvalidProtoDepth || depth2 != kInvalidProtoDepth; - } - Counters* counters = masm->isolate()->counters(); __ IncrementCounter(counters->call_const_interceptor(), 1); - if (can_do_fast_api_call) { - __ IncrementCounter(counters->call_const_interceptor_fast_api(), 1); - ReserveSpaceForFastApiCall(masm, scratch1); - } - // Check that the maps from receiver to interceptor's holder // haven't changed and thus we can invoke interceptor. Label miss_cleanup; - Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; Register holder = stub_compiler_->CheckPrototypes( IC::CurrentTypeOf(object, masm->isolate()), receiver, interceptor_holder, scratch1, scratch2, scratch3, - name, depth1, miss); + name, miss_label); // Invoke an interceptor and if it provides a value, // branch to |regular_invoke|. @@ -730,35 +679,41 @@ class CallInterceptorCompiler BASE_EMBEDDED { stub_compiler_->CheckPrototypes( IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, handle(lookup->holder()), scratch1, scratch2, scratch3, - name, depth2, miss); - } else { - // CheckPrototypes has a side effect of fetching a 'holder' - // for API (object which is instanceof for the signature). It's - // safe to omit it here, as if present, it should be fetched - // by the previous CheckPrototypes. - ASSERT(depth2 == kInvalidProtoDepth); + name, miss_label); + } + + Handle lookup_map; + CallOptimization::HolderLookup holder_lookup = + CallOptimization::kHolderNotFound; + if (optimization.is_simple_api_call() && + !lookup->holder()->IsGlobalObject()) { + lookup_map = optimization.LookupHolderOfExpectedType( + object, object, interceptor_holder, &holder_lookup); + if (holder_lookup == CallOptimization::kHolderNotFound) { + lookup_map = + optimization.LookupHolderOfExpectedType( + object, + interceptor_holder, + Handle(lookup->holder()), + &holder_lookup); + } } // Invoke function. - if (can_do_fast_api_call) { - GenerateFastApiCall(masm, optimization, arguments_.immediate()); + if (holder_lookup != CallOptimization::kHolderNotFound) { + int argc = arguments_.immediate(); + GenerateFastApiCall(masm, + optimization, + argc, + lookup_map, + holder_lookup); } else { Handle fun = optimization.constant_function(); stub_compiler_->GenerateJumpFunction(object, fun); } - // Deferred code for fast API call case---clean preallocated space. - if (can_do_fast_api_call) { - __ bind(&miss_cleanup); - FreeSpaceForFastApiCall(masm, scratch1); - __ jmp(miss_label); - } - // Invoke a regular function. __ bind(®ular_invoke); - if (can_do_fast_api_call) { - FreeSpaceForFastApiCall(masm, scratch1); - } } void CompileRegular(MacroAssembler* masm, @@ -1120,7 +1075,6 @@ Register StubCompiler::CheckPrototypes(Handle type, Register scratch1, Register scratch2, Handle name, - int save_at_depth, Label* miss, PrototypeCheckType check) { Handle receiver_map(IC::TypeToMap(*type, isolate())); @@ -1139,15 +1093,6 @@ Register StubCompiler::CheckPrototypes(Handle type, Register reg = object_reg; int depth = 0; - StackArgumentsAccessor args(rsp, kFastApiCallArguments, - ARGUMENTS_DONT_CONTAIN_RECEIVER); - const int kHolderIndex = kFastApiCallArguments - 1 - - FunctionCallbackArguments::kHolderIndex; - - if (save_at_depth == depth) { - __ movp(args.GetArgumentOperand(kHolderIndex), object_reg); - } - Handle current = Handle::null(); if (type->IsConstant()) current = Handle::cast(type->AsConstant()); Handle prototype = Handle::null(); @@ -1213,10 +1158,6 @@ Register StubCompiler::CheckPrototypes(Handle type, } } - if (save_at_depth == depth) { - __ movp(args.GetArgumentOperand(kHolderIndex), reg); - } - // Go to the next object in the prototype chain. current = prototype; current_map = handle(current->map()); @@ -1606,43 +1547,35 @@ Handle CallStubCompiler::CompileFastApiCall( if (object->IsGlobalObject()) return Handle::null(); if (!cell.is_null()) return Handle::null(); if (!object->IsJSObject()) return Handle::null(); - int depth = optimization.GetPrototypeDepthOfExpectedType( - Handle::cast(object), holder); - if (depth == kInvalidProtoDepth) return Handle::null(); + Handle receiver = Handle::cast(object); + CallOptimization::HolderLookup holder_lookup = + CallOptimization::kHolderNotFound; + Handle lookup_map = optimization.LookupHolderOfExpectedType( + receiver, receiver, holder, &holder_lookup); + if (holder_lookup == CallOptimization::kHolderNotFound) { + return Handle::null(); + } - Label miss, miss_before_stack_reserved; - GenerateNameCheck(name, &miss_before_stack_reserved); + Label miss; + GenerateNameCheck(name, &miss); const int argc = arguments().immediate(); StackArgumentsAccessor args(rsp, argc); __ movp(rdx, args.GetReceiverOperand()); // Check that the receiver isn't a smi. - __ JumpIfSmi(rdx, &miss_before_stack_reserved); + __ JumpIfSmi(rdx, &miss); Counters* counters = isolate()->counters(); __ IncrementCounter(counters->call_const(), 1); - __ IncrementCounter(counters->call_const_fast_api(), 1); - - // Allocate space for v8::Arguments implicit values. Must be initialized - // before calling any runtime function. - __ subq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); // Check that the maps haven't changed and find a Holder as a side effect. CheckPrototypes(IC::CurrentTypeOf(object, isolate()), rdx, holder, - rbx, rax, rdi, name, depth, &miss); + rbx, rax, rdi, name, &miss); - // Move the return address on top of the stack. - __ movq(rax, - StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize)); - __ movq(StackOperandForReturnAddress(0), rax); + GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup); - GenerateFastApiCall(masm(), optimization, argc); - - __ bind(&miss); - __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); - - HandlerFrontendFooter(&miss_before_stack_reserved); + HandlerFrontendFooter(&miss); // Return the generated code. return GetCode(function);