From 796a244bea473bbde0c8a1f472e5b1f4fb7c729b Mon Sep 17 00:00:00 2001 From: "mvstanton@chromium.org" Date: Tue, 21 Jan 2014 17:04:17 +0000 Subject: [PATCH] Revert "Unify calling to GenerateFastApiCallBody before stubbing it" This reverts commit r18714 for breaking webkit tests with an assert. TBR=dcarney@chromium.org Review URL: https://codereview.chromium.org/144143002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18720 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/stub-cache-arm.cc | 280 +++++++++++++++++++---------------------- src/ia32/stub-cache-ia32.cc | 282 +++++++++++++++++++++++++----------------- src/stub-cache.cc | 45 ++----- src/stub-cache.h | 31 +++-- src/x64/stub-cache-x64.cc | 295 +++++++++++++++++++++++++++----------------- 5 files changed, 505 insertions(+), 428 deletions(-) diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 987437b..8625ed6 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -779,72 +779,64 @@ 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); + } +} + -static void GenerateFastApiCallBody(MacroAssembler* masm, - const CallOptimization& optimization, - int argc, - Register holder, - Register scratch1, - Register scratch2, - Register scratch3, - bool restore_context) { +// 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) { // ----------- S t a t e ------------- - // -- sp[0] : last JS argument + // -- sp[0] - sp[24] : FunctionCallbackInfo, incl. + // : holder (set by CheckPrototypes) + // -- sp[28] : last JS argument // -- ... - // -- sp[(argc - 1) * 4] : first JS argument - // -- sp[argc * 4] : receiver + // -- sp[(argc + 6) * 4] : first JS argument + // -- sp[(argc + 7) * 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. - __ push(cp); + __ str(cp, MemOperand(sp, FCA::kContextSaveIndex * kPointerSize)); // Get the function and setup the context. Handle function = optimization.constant_function(); - __ Move(scratch1, function); - __ ldr(cp, FieldMemOperand(scratch1, JSFunction::kContextOffset)); - __ push(scratch1); + __ Move(r5, function); + __ ldr(cp, FieldMemOperand(r5, JSFunction::kContextOffset)); + __ str(r5, MemOperand(sp, FCA::kCalleeIndex * kPointerSize)); // 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(scratch1, api_call_info); - __ ldr(scratch1, FieldMemOperand(scratch1, CallHandlerInfo::kDataOffset)); - } else if (call_data->IsUndefined()) { - call_data_undefined = true; - __ LoadRoot(scratch3, Heap::kUndefinedValueRootIndex); + __ Move(r0, api_call_info); + __ ldr(r6, FieldMemOperand(r0, CallHandlerInfo::kDataOffset)); } else { - __ Move(scratch1, call_data); + __ Move(r6, call_data); } // Store call data. - __ push(scratch1); - if (!call_data_undefined) { - __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); - } - // Store ReturnValue default and ReturnValue. - __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex); - __ push(scratch1); - __ push(scratch1); + __ str(r6, MemOperand(sp, FCA::kDataIndex * kPointerSize)); // Store isolate. - __ mov(scratch1, - Operand(ExternalReference::isolate_address(masm->isolate()))); - __ push(scratch1); - // holder - __ push(holder); + __ mov(r5, Operand(ExternalReference::isolate_address(masm->isolate()))); + __ str(r5, MemOperand(sp, FCA::kIsolateIndex * kPointerSize)); + // Store ReturnValue default and ReturnValue. + __ LoadRoot(r5, Heap::kUndefinedValueRootIndex); + __ str(r5, MemOperand(sp, FCA::kReturnValueOffset * kPointerSize)); + __ str(r5, MemOperand(sp, FCA::kReturnValueDefaultValueIndex * kPointerSize)); // Prepare arguments. __ mov(r2, sp); @@ -901,50 +893,6 @@ static void GenerateFastApiCallBody(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, @@ -952,31 +900,26 @@ static void GenerateFastApiCall(MacroAssembler* masm, Register scratch, int argc, Register* values) { + ASSERT(optimization.is_simple_api_call()); ASSERT(!receiver.is(scratch)); - __ push(receiver); + + 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)); // Write the arguments to stack frame. for (int i = 0; i < argc; i++) { - Register arg = values[argc-1-i]; - ASSERT(!receiver.is(arg)); - ASSERT(!scratch.is(arg)); - __ push(arg); - } - Register scratch1 = r0; - Register scratch2 = r1; - Register scratch3 = r2; - if (!r3.is(receiver)) { - __ mov(r3, receiver); - receiver = r3; + ASSERT(!receiver.is(values[i])); + ASSERT(!scratch.is(values[i])); + __ str(values[i], MemOperand(sp, index-- * kPointerSize)); } - // Stack now matches JSFunction abi. - GenerateFastApiCallBody(masm, - optimization, - argc, - receiver, - scratch1, - scratch2, - scratch3, - true); + + GenerateFastApiDirectCall(masm, optimization, argc, true); } @@ -1029,17 +972,39 @@ 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, miss_label); + name, depth1, miss); // Invoke an interceptor and if it provides a value, // branch to |regular_invoke|. @@ -1056,42 +1021,37 @@ class CallInterceptorCompiler BASE_EMBEDDED { stub_compiler_->CheckPrototypes( IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, handle(lookup->holder()), scratch1, scratch2, scratch3, - 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); - } + 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); } // Invoke function. - if (holder_lookup != CallOptimization::kHolderNotFound) { - int argc = arguments_.immediate(); - GenerateFastApiCall(masm, - optimization, - argc, - lookup_map, - holder_lookup); + if (can_do_fast_api_call) { + GenerateFastApiDirectCall( + masm, optimization, arguments_.immediate(), false); } 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, @@ -1167,6 +1127,7 @@ 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())); @@ -1183,6 +1144,11 @@ 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(); @@ -1248,6 +1214,10 @@ 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()); @@ -1616,36 +1586,36 @@ Handle CallStubCompiler::CompileFastApiCall( if (object->IsGlobalObject()) return Handle::null(); if (!cell.is_null()) return Handle::null(); if (!object->IsJSObject()) 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(); - } + int depth = optimization.GetPrototypeDepthOfExpectedType( + Handle::cast(object), holder); + if (depth == kInvalidProtoDepth) return Handle::null(); - Label miss; - GenerateNameCheck(name, &miss); + Label miss, miss_before_stack_reserved; + GenerateNameCheck(name, &miss_before_stack_reserved); // 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); + __ JumpIfSmi(r1, &miss_before_stack_reserved); __ 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, &miss); + r1, holder, r0, r3, r4, name, depth, &miss); - GenerateFastApiCall( - masm(), optimization, argc, lookup_map, holder_lookup); + GenerateFastApiDirectCall(masm(), optimization, argc, false); - HandlerFrontendFooter(&miss); + __ bind(&miss); + FreeSpaceForFastApiCall(masm()); + + HandlerFrontendFooter(&miss_before_stack_reserved); // Return the generated code. return GetCode(function); diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index e76bfb5..0a0e0f9 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -418,55 +418,82 @@ 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, - Handle map_to_holder, - CallOptimization::HolderLookup holder_lookup) { - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->call_const_fast_api(), 1); + int argc) { + typedef FunctionCallbackArguments FCA; + // Save calling context. + __ mov(Operand(esp, (1 + FCA::kContextSaveIndex) * kPointerSize), esi); - // 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(); + // 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)); } - GenerateFastApiCallBody(masm, - optimization, - argc, - holder_reg, - ebx, - ecx, - edx, - false); + __ 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); } @@ -482,10 +509,14 @@ 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]; @@ -495,34 +526,6 @@ 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; @@ -535,9 +538,6 @@ static void GenerateFastApiCallBody(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 GenerateFastApiCallBody(MacroAssembler* masm, // isolate __ push(Immediate(reinterpret_cast(isolate))); // holder - __ push(holder); + __ push(receiver); // store receiver address for GenerateFastApiCallBody ASSERT(!scratch1.is(eax)); @@ -575,6 +575,28 @@ static void GenerateFastApiCallBody(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 @@ -585,6 +607,8 @@ 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); @@ -669,16 +693,38 @@ 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, miss_label); + name, depth1, miss); // Invoke an interceptor and if it provides a value, // branch to |regular_invoke|. @@ -695,41 +741,35 @@ class CallInterceptorCompiler BASE_EMBEDDED { stub_compiler_->CheckPrototypes( IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, handle(lookup->holder()), scratch1, scratch2, scratch3, - 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); - } + 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); } // Invoke function. - if (holder_lookup != CallOptimization::kHolderNotFound) { - int argc = arguments_.immediate(); - GenerateFastApiCall(masm, - optimization, - argc, - lookup_map, - holder_lookup); + if (can_do_fast_api_call) { + GenerateFastApiCall(masm, optimization, arguments_.immediate()); } 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, @@ -1150,6 +1190,7 @@ 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())); @@ -1166,6 +1207,11 @@ 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(); @@ -1233,6 +1279,10 @@ 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()); @@ -1629,35 +1679,45 @@ Handle CallStubCompiler::CompileFastApiCall( if (object->IsGlobalObject()) return Handle::null(); if (!cell.is_null()) return Handle::null(); if (!object->IsJSObject()) 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(); - } + int depth = optimization.GetPrototypeDepthOfExpectedType( + Handle::cast(object), holder); + if (depth == kInvalidProtoDepth) return Handle::null(); - Label miss; - GenerateNameCheck(name, &miss); + Label miss, miss_before_stack_reserved; + + GenerateNameCheck(name, &miss_before_stack_reserved); // 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); + __ JumpIfSmi(edx, &miss_before_stack_reserved); 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, &miss); + ebx, eax, edi, name, depth, &miss); - GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup); + // Move the return address on top of the stack. + __ mov(eax, Operand(esp, kFastApiCallArguments * kPointerSize)); + __ mov(Operand(esp, 0 * kPointerSize), eax); - HandlerFrontendFooter(&miss); + // 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); // Return the generated code. return GetCode(function); diff --git a/src/stub-cache.cc b/src/stub-cache.cc index aa54d81..e2558e8 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -1994,45 +1994,20 @@ CallOptimization::CallOptimization(Handle function) { } -Handle CallOptimization::LookupHolderOfExpectedType( - Handle receiver, +int CallOptimization::GetPrototypeDepthOfExpectedType( Handle object, - Handle holder, - HolderLookup* holder_lookup) const { + Handle holder) const { ASSERT(is_simple_api_call()); - 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; - } - // 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())); - ASSERT(!expected_receiver_type_->IsTemplateFor(*map_to_holder)); - } - // start looking for the holder + if (expected_receiver_type_.is_null()) return 0; + int depth = 0; 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; + if (expected_receiver_type_->IsTemplateFor(object->map())) return depth; + object = Handle(JSObject::cast(object->GetPrototype())); + if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth; + ++depth; } - *holder_lookup = kHolderNotFound; - return Handle::null(); + if (expected_receiver_type_->IsTemplateFor(holder->map())) return depth; + return kInvalidProtoDepth; } diff --git a/src/stub-cache.h b/src/stub-cache.h index f544ec4..737b069 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -483,6 +483,20 @@ 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); @@ -1014,19 +1028,10 @@ class CallOptimization BASE_EMBEDDED { return api_call_info_; } - 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; + // 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; 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 dbfd419..392c96b 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -392,57 +392,92 @@ 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, - Handle map_to_holder, - CallOptimization::HolderLookup holder_lookup) { - Counters* counters = masm->isolate()->counters(); - __ IncrementCounter(counters->call_const_fast_api(), 1); + int argc) { + typedef FunctionCallbackArguments FCA; + StackArgumentsAccessor args(rsp, argc + kFastApiCallArguments); - // 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(); + // 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); } - GenerateFastApiCallBody(masm, - optimization, - argc, - holder_reg, - rbx, - rcx, - rdx, - false); + __ 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); } @@ -458,9 +493,13 @@ 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]; @@ -470,35 +509,6 @@ 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; @@ -511,9 +521,6 @@ static void GenerateFastApiCallBody(MacroAssembler* masm, STATIC_ASSERT(FCA::kContextSaveIndex == 6); STATIC_ASSERT(FCA::kArgsLength == 7); - __ PopReturnAddressTo(scratch1); - - ASSERT(!holder.is(rsi)); // context save __ push(rsi); @@ -550,13 +557,36 @@ static void GenerateFastApiCallBody(MacroAssembler* masm, ExternalReference::isolate_address(masm->isolate())); __ push(scratch3); // holder - __ push(holder); + __ push(receiver); 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()); @@ -652,17 +682,38 @@ 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, miss_label); + name, depth1, miss); // Invoke an interceptor and if it provides a value, // branch to |regular_invoke|. @@ -679,41 +730,35 @@ class CallInterceptorCompiler BASE_EMBEDDED { stub_compiler_->CheckPrototypes( IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder, handle(lookup->holder()), scratch1, scratch2, scratch3, - 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); - } + 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); } // Invoke function. - if (holder_lookup != CallOptimization::kHolderNotFound) { - int argc = arguments_.immediate(); - GenerateFastApiCall(masm, - optimization, - argc, - lookup_map, - holder_lookup); + if (can_do_fast_api_call) { + GenerateFastApiCall(masm, optimization, arguments_.immediate()); } 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, @@ -1075,6 +1120,7 @@ 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())); @@ -1093,6 +1139,15 @@ 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(); @@ -1158,6 +1213,10 @@ 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()); @@ -1547,35 +1606,43 @@ Handle CallStubCompiler::CompileFastApiCall( if (object->IsGlobalObject()) return Handle::null(); if (!cell.is_null()) return Handle::null(); if (!object->IsJSObject()) 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(); - } + int depth = optimization.GetPrototypeDepthOfExpectedType( + Handle::cast(object), holder); + if (depth == kInvalidProtoDepth) return Handle::null(); - Label miss; - GenerateNameCheck(name, &miss); + Label miss, miss_before_stack_reserved; + GenerateNameCheck(name, &miss_before_stack_reserved); const int argc = arguments().immediate(); StackArgumentsAccessor args(rsp, argc); __ movp(rdx, args.GetReceiverOperand()); // Check that the receiver isn't a smi. - __ JumpIfSmi(rdx, &miss); + __ JumpIfSmi(rdx, &miss_before_stack_reserved); 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, &miss); + rbx, rax, rdi, name, depth, &miss); - GenerateFastApiCall(masm(), optimization, argc, lookup_map, holder_lookup); + // Move the return address on top of the stack. + __ movq(rax, + StackOperandForReturnAddress(kFastApiCallArguments * kPointerSize)); + __ movq(StackOperandForReturnAddress(0), rax); - HandlerFrontendFooter(&miss); + GenerateFastApiCall(masm(), optimization, argc); + + __ bind(&miss); + __ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); + + HandlerFrontendFooter(&miss_before_stack_reserved); // Return the generated code. return GetCode(function); -- 2.7.4