From 58b04396bfa1010fa3f45a86dbadd46a1541c1f6 Mon Sep 17 00:00:00 2001 From: "whesse@chromium.org" Date: Mon, 15 Feb 2010 12:26:07 +0000 Subject: [PATCH] Change CallIC interface on ARM. Remove name from the stack, and pass it in register r2. Review URL: http://codereview.chromium.org/598065 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3856 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/builtins-arm.cc | 63 ++++++++++++++++++------------------- src/arm/codegen-arm.cc | 29 +++++------------ src/arm/full-codegen-arm.cc | 27 ++++++---------- src/arm/ic-arm.cc | 27 +++++++--------- src/arm/stub-cache-arm.cc | 60 +++++++++++++++++------------------ 5 files changed, 90 insertions(+), 116 deletions(-) diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc index ae7dae3b08..e4a1a33abe 100644 --- a/src/arm/builtins-arm.cc +++ b/src/arm/builtins-arm.cc @@ -915,7 +915,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { } // 2. Get the function to call from the stack. - // r0: actual number of argument + // r0: actual number of arguments { Label done, non_function, function; __ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2)); __ tst(r1, Operand(kSmiTagMask)); @@ -997,13 +997,27 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ bind(&done); } - // 4. Shift stuff one slot down the stack + // 4. Handle non-functions. // r0: actual number of arguments (including call() receiver) // r1: function + { Label done; + __ tst(r1, r1); + __ b(ne, &done); + __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION + // Transfer the receiver from the first argument to the top of the + // caller's expression stack simply by decrementing argc. + __ sub(r0, r0, Operand(1)); + __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); + __ Jump(Handle(builtin(ArgumentsAdaptorTrampoline)), + RelocInfo::CODE_TARGET); + __ bind(&done); + } + + // 5. Shift arguments one slot toward the bottom of the + // stack, overwriting the receiver. { Label loop; // Calculate the copy start address (destination). Copy end address is sp. __ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2)); - __ add(r2, r2, Operand(kPointerSize)); // copy receiver too __ bind(&loop); __ ldr(ip, MemOperand(r2, -kPointerSize)); @@ -1011,43 +1025,28 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) { __ sub(r2, r2, Operand(kPointerSize)); __ cmp(r2, sp); __ b(ne, &loop); + // Adjust the actual number of arguments and remove the top element. + __ sub(r0, r0, Operand(1)); + __ pop(); } - // 5. Adjust the actual number of arguments and remove the top element. - // r0: actual number of arguments (including call() receiver) - // r1: function - __ sub(r0, r0, Operand(1)); - __ add(sp, sp, Operand(kPointerSize)); - // 6. Get the code for the function or the non-function builtin. // If number of expected arguments matches, then call. Otherwise restart // the arguments adaptor stub. // r0: actual number of arguments // r1: function - { Label invoke; - __ tst(r1, r1); - __ b(ne, &invoke); - __ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION - __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION); - __ Jump(Handle(builtin(ArgumentsAdaptorTrampoline)), - RelocInfo::CODE_TARGET); + __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); + __ ldr(r2, + FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset)); + __ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset)); + __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); + __ cmp(r2, r0); // Check formal and actual parameter counts. + __ Jump(Handle(builtin(ArgumentsAdaptorTrampoline)), + RelocInfo::CODE_TARGET, ne); - __ bind(&invoke); - __ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); - __ ldr(r2, - FieldMemOperand(r3, - SharedFunctionInfo::kFormalParameterCountOffset)); - __ ldr(r3, - MemOperand(r3, SharedFunctionInfo::kCodeOffset - kHeapObjectTag)); - __ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag)); - __ cmp(r2, r0); // Check formal and actual parameter counts. - __ Jump(Handle(builtin(ArgumentsAdaptorTrampoline)), - RelocInfo::CODE_TARGET, ne); - - // 7. Jump to the code in r3 without checking arguments. - ParameterCount expected(0); - __ InvokeCode(r3, expected, expected, JUMP_FUNCTION); - } + // 7. Jump (tail-call) to the code in r3 without checking arguments. + ParameterCount expected(0); + __ InvokeCode(r3, expected, expected, JUMP_FUNCTION); } diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index ef2e27deca..35dc7fe91a 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -3023,11 +3023,6 @@ void CodeGenerator::VisitCall(Call* node) { // ---------------------------------- // JavaScript example: 'foo(1, 2, 3)' // foo is global // ---------------------------------- - - // Push the name of the function and the receiver onto the stack. - __ mov(r0, Operand(var->name())); - frame_->EmitPush(r0); - // Pass the global object as the receiver and let the IC stub // patch the stack to use the global proxy as 'this' in the // invoked function. @@ -3039,15 +3034,14 @@ void CodeGenerator::VisitCall(Call* node) { LoadAndSpill(args->at(i)); } - // Setup the receiver register and call the IC initialization code. + // Setup the name register and call the IC initialization code. + __ mov(r2, Operand(var->name())); InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; Handle stub = ComputeCallInitialize(arg_count, in_loop); CodeForSourcePosition(node->position()); frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT, arg_count + 1); __ ldr(cp, frame_->Context()); - // Remove the function from the stack. - frame_->Drop(); frame_->EmitPush(r0); } else if (var != NULL && var->slot() != NULL && @@ -3080,28 +3074,21 @@ void CodeGenerator::VisitCall(Call* node) { // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' // ------------------------------------------------------------------ - // Push the name of the function and the receiver onto the stack. - __ mov(r0, Operand(literal->handle())); - frame_->EmitPush(r0); - LoadAndSpill(property->obj()); - + LoadAndSpill(property->obj()); // Receiver. // Load the arguments. int arg_count = args->length(); for (int i = 0; i < arg_count; i++) { LoadAndSpill(args->at(i)); } - // Set the receiver register and call the IC initialization code. + // Set the name register and call the IC initialization code. + __ mov(r2, Operand(literal->handle())); InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; Handle stub = ComputeCallInitialize(arg_count, in_loop); CodeForSourcePosition(node->position()); frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); __ ldr(cp, frame_->Context()); - - // Remove the function from the stack. - frame_->Drop(); - - frame_->EmitPush(r0); // push after get rid of function from the stack + frame_->EmitPush(r0); } else { // ------------------------------------------- @@ -3636,8 +3623,6 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) { if (function == NULL) { // Prepare stack for calling JS runtime function. - __ mov(r0, Operand(node->name())); - frame_->EmitPush(r0); // Push the builtins object found in the current global object. __ ldr(r1, GlobalObject()); __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset)); @@ -3652,11 +3637,11 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) { if (function == NULL) { // Call the JS runtime function. + __ mov(r2, Operand(node->name())); InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; Handle stub = ComputeCallInitialize(arg_count, in_loop); frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1); __ ldr(cp, frame_->Context()); - frame_->Drop(); frame_->EmitPush(r0); } else { // Call the C runtime function. diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc index 96549f8d10..55aac6d170 100644 --- a/src/arm/full-codegen-arm.cc +++ b/src/arm/full-codegen-arm.cc @@ -1090,7 +1090,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) { } void FullCodeGenerator::EmitCallWithIC(Call* expr, - Handle ignored, + Handle name, RelocInfo::Mode mode) { // Code common for calls using the IC. ZoneList* args = expr->arguments(); @@ -1098,16 +1098,16 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr, for (int i = 0; i < arg_count; i++) { VisitForValue(args->at(i), kStack); } + __ mov(r2, Operand(name)); // Record source position for debugger. SetSourcePosition(expr->position()); // Call the IC initialization code. - Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, - NOT_IN_LOOP); + InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; + Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop); __ Call(ic, mode); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - // Discard the function left on TOS. - DropAndApply(1, context_, r0); + Apply(context_, r0); } @@ -1124,7 +1124,6 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) { __ CallStub(&stub); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - // Discard the function left on TOS. DropAndApply(1, context_, r0); } @@ -1138,11 +1137,9 @@ void FullCodeGenerator::VisitCall(Call* expr) { // Call to the identifier 'eval'. UNREACHABLE(); } else if (var != NULL && !var->is_this() && var->is_global()) { - // Call to a global variable. - __ mov(r1, Operand(var->name())); - // Push global object as receiver for the call IC lookup. + // Push global object as receiver for the call IC. __ ldr(r0, CodeGenerator::GlobalObject()); - __ stm(db_w, sp, r1.bit() | r0.bit()); + __ push(r0); EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); } else if (var != NULL && var->slot() != NULL && var->slot()->type() == Slot::LOOKUP) { @@ -1154,8 +1151,6 @@ void FullCodeGenerator::VisitCall(Call* expr) { Literal* key = prop->key()->AsLiteral(); if (key != NULL && key->handle()->IsSymbol()) { // Call to a named property, use call IC. - __ mov(r0, Operand(key->handle())); - __ push(r0); VisitForValue(prop->obj(), kStack); EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); } else { @@ -1241,10 +1236,9 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { if (expr->is_jsruntime()) { // Prepare for calling JS runtime function. - __ mov(r1, Operand(expr->name())); __ ldr(r0, CodeGenerator::GlobalObject()); __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset)); - __ stm(db_w, sp, r1.bit() | r0.bit()); + __ push(r0); } // Push the arguments ("left-to-right"). @@ -1255,18 +1249,17 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { if (expr->is_jsruntime()) { // Call the JS runtime function. + __ mov(r2, Operand(expr->name())); Handle ic = CodeGenerator::ComputeCallInitialize(arg_count, NOT_IN_LOOP); __ Call(ic, RelocInfo::CODE_TARGET); // Restore context register. __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); - // Discard the function left on TOS. - DropAndApply(1, context_, r0); } else { // Call the C runtime function. __ CallRuntime(expr->function(), arg_count); - Apply(context_, r0); } + Apply(context_, r0); } diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc index 8fce7fd136..d16a950e8b 100644 --- a/src/arm/ic-arm.cc +++ b/src/arm/ic-arm.cc @@ -59,7 +59,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm, // r3 - used as temporary and to hold the capacity of the property // dictionary. // - // r2 - holds the name of the property and is unchanges. + // r2 - holds the name of the property and is unchanged. Label done; @@ -219,14 +219,13 @@ Object* CallIC_Miss(Arguments args); void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- - // -- lr: return address + // -- r2 : name + // -- lr : return address // ----------------------------------- Label number, non_number, non_string, boolean, probe, miss; // Get the receiver of the function from the stack into r1. __ ldr(r1, MemOperand(sp, argc * kPointerSize)); - // Get the name of the function from the stack; 1 ~ receiver. - __ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize)); // Probe the stub cache. Code::Flags flags = @@ -301,9 +300,9 @@ static void GenerateNormalHelper(MacroAssembler* masm, // Patch the receiver with the global proxy if necessary. if (is_global_object) { - __ ldr(r2, MemOperand(sp, argc * kPointerSize)); - __ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset)); - __ str(r2, MemOperand(sp, argc * kPointerSize)); + __ ldr(r0, MemOperand(sp, argc * kPointerSize)); + __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset)); + __ str(r0, MemOperand(sp, argc * kPointerSize)); } // Invoke the function. @@ -314,14 +313,13 @@ static void GenerateNormalHelper(MacroAssembler* masm, void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- - // -- lr: return address + // -- r2 : name + // -- lr : return address // ----------------------------------- Label miss, global_object, non_global_object; // Get the receiver of the function from the stack into r1. __ ldr(r1, MemOperand(sp, argc * kPointerSize)); - // Get the name of the function from the stack; 1 ~ receiver. - __ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize)); // Check that the receiver isn't a smi. __ tst(r1, Operand(kSmiTagMask)); @@ -374,18 +372,17 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) { void CallIC::GenerateMiss(MacroAssembler* masm, int argc) { // ----------- S t a t e ------------- - // -- lr: return address + // -- r2 : name + // -- lr : return address // ----------------------------------- // Get the receiver of the function from the stack. - __ ldr(r2, MemOperand(sp, argc * kPointerSize)); - // Get the name of the function to call from the stack. - __ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize)); + __ ldr(r3, MemOperand(sp, argc * kPointerSize)); __ EnterInternalFrame(); // Push the receiver and the name of the function. - __ stm(db_w, sp, r1.bit() | r2.bit()); + __ stm(db_w, sp, r2.bit() | r3.bit()); // Call the entry. __ mov(r0, Operand(2)); diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 0fc14da2f4..1ae3ae31e2 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -376,7 +376,7 @@ static void GenerateCallFunction(MacroAssembler* masm, // Check that the function really is a function. __ BranchOnSmi(r1, miss); - __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); + __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); __ b(ne, miss); // Patch the receiver on the stack with the global proxy if @@ -803,7 +803,8 @@ Object* CallStubCompiler::CompileCallField(Object* object, int index, String* name) { // ----------- S t a t e ------------- - // -- lr: return address + // -- r2 : name + // -- lr : return address // ----------------------------------- Label miss; @@ -817,7 +818,7 @@ Object* CallStubCompiler::CompileCallField(Object* object, // Do the right check and compute the holder register. Register reg = - CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss); + CheckPrototypes(JSObject::cast(object), r0, holder, r1, r3, name, &miss); GenerateFastPropertyLoad(masm(), r1, reg, holder, index); GenerateCallFunction(masm(), object, arguments(), &miss); @@ -838,7 +839,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, String* name, CheckType check) { // ----------- S t a t e ------------- - // -- lr: return address + // -- r2 : name + // -- lr : return address // ----------------------------------- Label miss; @@ -859,7 +861,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, switch (check) { case RECEIVER_MAP_CHECK: // Check that the maps haven't changed. - CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss); + CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss); // Patch the receiver on the stack with the global proxy if // necessary. @@ -875,13 +877,13 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ jmp(&miss); } else { // Check that the object is a two-byte string or a symbol. - __ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE); + __ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE); __ b(hs, &miss); // Check that the maps starting from the prototype haven't changed. GenerateLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - r2); - CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3, + r0); + CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, r1, name, &miss); } break; @@ -895,14 +897,14 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, // Check that the object is a smi or a heap number. __ tst(r1, Operand(kSmiTagMask)); __ b(eq, &fast); - __ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE); + __ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE); __ b(ne, &miss); __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateLoadGlobalFunctionPrototype(masm(), Context::NUMBER_FUNCTION_INDEX, - r2); - CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3, + r0); + CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, r1, name, &miss); } break; @@ -925,22 +927,22 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, // Check that the maps starting from the prototype haven't changed. GenerateLoadGlobalFunctionPrototype(masm(), Context::BOOLEAN_FUNCTION_INDEX, - r2); - CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3, + r0); + CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, r1, name, &miss); } break; } case JSARRAY_HAS_FAST_ELEMENTS_CHECK: - CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss); + CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss); // Make sure object->HasFastElements(). // Get the elements array of the object. __ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset)); // Check that the object is in fast mode (not dictionary). - __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); + __ ldr(r0, FieldMemOperand(r3, HeapObject::kMapOffset)); __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); - __ cmp(r2, ip); + __ cmp(r0, ip); __ b(ne, &miss); break; @@ -968,15 +970,16 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, JSObject* holder, String* name) { // ----------- S t a t e ------------- - // -- lr: return address + // -- r2 : name + // -- lr : return address // ----------------------------------- ASSERT(holder->HasNamedInterceptor()); ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); Label miss; const Register receiver = r0; - const Register name_reg = r1; - const Register holder_reg = r2; + const Register holder_reg = r1; + const Register name_reg = r2; const Register scratch = r3; // Get the number of arguments. @@ -985,10 +988,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, LookupResult lookup; LookupPostInterceptor(holder, name, &lookup); - // Load the receiver from the stack. - __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); - // Load the name from the stack. - __ ldr(name_reg, MemOperand(sp, (argc + 1) * kPointerSize)); + // Get the receiver from the stack into r0. + __ ldr(r0, MemOperand(sp, argc * kPointerSize)); // Check that the receiver isn't a smi. __ BranchOnSmi(receiver, &miss); @@ -1061,9 +1062,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, __ LeaveInternalFrame(); } - // Move returned value, the function to call, to r1. - // Neither receiver nor name contain their original value at this point. __ mov(r1, r0); // Restore receiver. __ ldr(receiver, MemOperand(sp, argc * kPointerSize)); @@ -1086,7 +1085,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, JSFunction* function, String* name) { // ----------- S t a t e ------------- - // -- lr: return address + // -- r2 : name + // -- lr : return address // ----------------------------------- Label miss; @@ -1105,7 +1105,7 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, } // Check that the maps haven't changed. - CheckPrototypes(object, r0, holder, r3, r2, name, &miss); + CheckPrototypes(object, r0, holder, r3, r1, name, &miss); // Get the value from the cell. __ mov(r3, Operand(Handle(cell))); @@ -1125,8 +1125,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, // Check the shared function info. Make sure it hasn't changed. __ mov(r3, Operand(Handle(function->shared()))); - __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); - __ cmp(r2, r3); + __ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); + __ cmp(r4, r3); __ b(ne, &miss); } else { __ cmp(r1, Operand(Handle(function))); @@ -1144,7 +1144,7 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object, __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); // Jump to the cached code (tail call). - __ IncrementCounter(&Counters::call_global_inline, 1, r2, r3); + __ IncrementCounter(&Counters::call_global_inline, 1, r1, r3); ASSERT(function->is_compiled()); Handle code(function->code()); ParameterCount expected(function->shared()->formal_parameter_count());