}
-void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+void MacroAssembler::InvokeFunction(Register function,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
// You can't call a function without a valid frame.
ASSERT(flag == JUMP_FUNCTION || has_frame());
+ // Contract with called JS functions requires that function is passed in r1.
+ ASSERT(function.is(r1));
+
// Get the function and setup the context.
- Move(r1, function);
ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
// We call indirectly through the code field in the function to
}
+void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper,
+ CallKind call_kind) {
+ Move(r1, function);
+ InvokeFunction(r1, expected, actual, flag, call_wrapper, call_kind);
+}
+
+
void MacroAssembler::IsObjectJSObjectType(Register heap_object,
Register map,
Register scratch,
const CallWrapper& call_wrapper,
CallKind call_kind);
+ void InvokeFunction(Register function,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper,
+ CallKind call_kind);
+
void InvokeFunction(Handle<JSFunction> function,
const ParameterCount& expected,
const ParameterCount& actual,
}
-static void GenerateCallFunction(MacroAssembler* masm,
- Handle<Object> object,
- const ParameterCount& arguments,
- Label* miss,
- ExtraICState extra_ic_state) {
- // ----------- S t a t e -------------
- // -- r0: receiver
- // -- r1: function to call
- // -----------------------------------
-
- // Check that the function really is a function.
- __ JumpIfSmi(r1, miss);
- __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
- __ b(ne, miss);
-
- if (object->IsGlobalObject()) {
- const int argc = arguments.immediate();
- const int receiver_offset = argc * kPointerSize;
- __ ldr(r3, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
- __ str(r3, MemOperand(sp, receiver_offset));
- }
-
- // Invoke the function.
- CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- __ InvokeFunction(r1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
-}
-
-
static void PushInterceptorArguments(MacroAssembler* masm,
Register receiver,
Register holder,
class CallInterceptorCompiler BASE_EMBEDDED {
public:
- CallInterceptorCompiler(StubCompiler* stub_compiler,
+ CallInterceptorCompiler(CallStubCompiler* stub_compiler,
const ParameterCount& arguments,
Register name,
ExtraICState extra_ic_state)
GenerateFastApiDirectCall(
masm, optimization, arguments_.immediate(), false);
} else {
- CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
Handle<JSFunction> function = optimization.constant_function();
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments_,
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
+ stub_compiler_->GenerateJumpFunctionIgnoreReceiver(function);
}
// Deferred code for fast API call case---clean preallocated space.
__ b(ne, interceptor_succeeded);
}
- StubCompiler* stub_compiler_;
+ CallStubCompiler* stub_compiler_;
const ParameterCount& arguments_;
Register name_;
ExtraICState extra_ic_state_;
}
+void CallStubCompiler::GenerateFunctionCheck(Register function,
+ Register scratch,
+ Label* miss) {
+ __ JumpIfSmi(function, miss);
+ __ CompareObjectType(function, scratch, scratch, JS_FUNCTION_TYPE);
+ __ b(ne, miss);
+}
+
+
void CallStubCompiler::GenerateLoadFunctionFromCell(
Handle<Cell> cell,
Handle<JSFunction> function,
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
- __ JumpIfSmi(r1, miss);
- __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
- __ b(ne, miss);
+ GenerateFunctionCheck(r1, r3, miss);
// Check the shared function info. Make sure it hasn't changed.
__ Move(r3, Handle<SharedFunctionInfo>(function->shared()));
object, holder, name, RECEIVER_MAP_CHECK, &miss);
GenerateFastPropertyLoad(masm(), r1, reg, index.is_inobject(holder),
index.translate(holder), Representation::Tagged());
-
- GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
+ GenerateJumpFunction(object, r1, &miss);
HandlerFrontendFooter(&miss);
__ bind(&miss);
// Restore function name in r2.
__ Move(r2, name);
- __ bind(&name_miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&name_miss);
// Return the generated code.
return GetCode(type, name);
__ bind(&miss);
// Restore function name in r2.
__ Move(r2, name);
- __ bind(&name_miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&name_miss);
// Return the generated code.
return GetCode(type, name);
StubRuntimeCallHelper call_helper;
generator.GenerateSlow(masm(), call_helper);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ Ret();
__ bind(&slow);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ Drop(argc + 1);
__ Ret();
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ bind(&miss);
FreeSpaceForFastApiCall(masm());
- __ bind(&miss_before_stack_reserved);
- GenerateMissBranch();
+ HandlerFrontendFooter(&miss_before_stack_reserved);
// Return the generated code.
return GetCode(function);
}
-void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
-}
-
-
-Handle<Code> CallStubCompiler::CompileCallConstant(
- Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Name> name,
- CheckType check,
- Handle<JSFunction> function) {
- if (HasCustomCallGenerator(function)) {
- Handle<Code> code = CompileCustomCall(object, holder,
- Handle<Cell>::null(),
- function, Handle<String>::cast(name),
- Code::FAST);
- // A null handle means bail out to the regular compiler code below.
- if (!code.is_null()) return code;
- }
-
- Label miss;
- HandlerFrontendHeader(object, holder, name, check, &miss);
+void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
+ Register function,
+ Label* miss) {
+ ASSERT(function.is(r1));
+ // Check that the function really is a function.
+ GenerateFunctionCheck(function, r3, miss);
PatchGlobalProxy(object);
- CompileHandlerBackend(function);
- HandlerFrontendFooter(&miss);
- // Return the generated code.
- return GetCode(function);
+ // Invoke the function.
+ __ InvokeFunction(r1, arguments(), JUMP_FUNCTION,
+ NullCallWrapper(), call_kind());
}
// Restore receiver.
__ ldr(r0, MemOperand(sp, argc * kPointerSize));
- GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
+ GenerateJumpFunction(object, r1, &miss);
- // Handle call cache miss.
- __ bind(&miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&miss);
// Return the generated code.
return GetCode(Code::FAST, name);
Label miss;
HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
+ // Potentially loads a closure that matches the shared function info of the
+ // function, rather than function.
GenerateLoadFunctionFromCell(cell, function, &miss);
- PatchGlobalProxy(object);
- // Set up the context (function already in r1).
- __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
-
- // Jump to the cached code (tail call).
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->call_global_inline(), 1, r3, r4);
- ParameterCount expected(function->shared()->formal_parameter_count());
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- // We call indirectly through the code field in the function to
- // allow recompilation to take effect without changing any of the
- // call sites.
- __ ldr(r3, FieldMemOperand(r1, JSFunction::kCodeEntryOffset));
- __ InvokeCode(r3, expected, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
-
+ GenerateJumpFunction(object, r1, function);
HandlerFrontendFooter(&miss);
// Return the generated code.
}
-void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+void MacroAssembler::InvokeFunction(Register fun,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
// You can't call a function without a valid frame.
ASSERT(flag == JUMP_FUNCTION || has_frame());
- // Get the function and setup the context.
- LoadHeapObject(edi, function);
+ ASSERT(fun.is(edi));
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
- // We call indirectly through the code field in the function to
- // allow recompilation to take effect without changing any of the
- // call sites.
InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
expected, actual, flag, call_wrapper, call_kind);
}
+void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper,
+ CallKind call_kind) {
+ LoadHeapObject(edi, function);
+ InvokeFunction(edi, expected, actual, flag, call_wrapper, call_kind);
+}
+
+
void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
const CallWrapper& call_wrapper) {
const CallWrapper& call_wrapper,
CallKind call_kind);
+ void InvokeFunction(Register function,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper,
+ CallKind call_kind);
+
void InvokeFunction(Handle<JSFunction> function,
const ParameterCount& expected,
const ParameterCount& actual,
class CallInterceptorCompiler BASE_EMBEDDED {
public:
- CallInterceptorCompiler(StubCompiler* stub_compiler,
+ CallInterceptorCompiler(CallStubCompiler* stub_compiler,
const ParameterCount& arguments,
Register name,
ExtraICState extra_state)
if (can_do_fast_api_call) {
GenerateFastApiCall(masm, optimization, arguments_.immediate());
} else {
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- Handle<JSFunction> function = optimization.constant_function();
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments_,
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
+ Handle<JSFunction> fun = optimization.constant_function();
+ stub_compiler_->GenerateJumpFunctionIgnoreReceiver(fun);
}
// Deferred code for fast API call case---clean preallocated space.
__ j(not_equal, interceptor_succeeded);
}
- StubCompiler* stub_compiler_;
+ CallStubCompiler* stub_compiler_;
const ParameterCount& arguments_;
Register name_;
ExtraICState extra_state_;
}
+void CallStubCompiler::GenerateFunctionCheck(Register function,
+ Register scratch,
+ Label* miss) {
+ __ JumpIfSmi(function, miss);
+ __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
+ __ j(not_equal, miss);
+}
+
+
void CallStubCompiler::GenerateLoadFunctionFromCell(
Handle<Cell> cell,
Handle<JSFunction> function,
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
- __ JumpIfSmi(edi, miss);
- __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
- __ j(not_equal, miss);
+ GenerateFunctionCheck(edi, ebx, miss);
// Check the shared function info. Make sure it hasn't changed.
__ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset),
GenerateFastPropertyLoad(
masm(), edi, reg, index.is_inobject(holder),
index.translate(holder), Representation::Tagged());
-
- // Check that the function really is a function.
- __ JumpIfSmi(edi, &miss);
- __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx);
- __ j(not_equal, &miss);
-
- PatchGlobalProxy(object);
-
- // Invoke the function.
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
+ GenerateJumpFunction(object, edi, &miss);
HandlerFrontendFooter(&miss);
__ bind(&miss);
// Restore function name in ecx.
__ Set(ecx, Immediate(name));
- __ bind(&name_miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&name_miss);
// Return the generated code.
return GetCode(type, name);
__ bind(&miss);
// Restore function name in ecx.
__ Set(ecx, Immediate(name));
- __ bind(&name_miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&name_miss);
// Return the generated code.
return GetCode(type, name);
StubRuntimeCallHelper call_helper;
generator.GenerateSlow(masm(), call_helper);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ mov(eax, Operand(esp, 1 * kPointerSize));
__ ret(2 * kPointerSize);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ mov(FieldOperand(eax, HeapNumber::kMantissaOffset), ecx);
__ ret(2 * kPointerSize);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ bind(&miss);
__ add(esp, Immediate(kFastApiCallArguments * kPointerSize));
- __ bind(&miss_before_stack_reserved);
- GenerateMissBranch();
+ HandlerFrontendFooter(&miss_before_stack_reserved);
// Return the generated code.
return GetCode(function);
}
-void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
-}
-
-
-Handle<Code> CallStubCompiler::CompileCallConstant(
- Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Name> name,
- CheckType check,
- Handle<JSFunction> function) {
-
- if (HasCustomCallGenerator(function)) {
- Handle<Code> code = CompileCustomCall(object, holder,
- Handle<Cell>::null(),
- function, Handle<String>::cast(name),
- Code::FAST);
- // A null handle means bail out to the regular compiler code below.
- if (!code.is_null()) return code;
- }
+void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
+ Register function,
+ Label* miss) {
+ // Check that the function really is a function.
+ GenerateFunctionCheck(function, ebx, miss);
- Label miss;
- HandlerFrontendHeader(object, holder, name, check, &miss);
+ if (!function.is(edi)) __ mov(edi, function);
PatchGlobalProxy(object);
- CompileHandlerBackend(function);
- HandlerFrontendFooter(&miss);
- // Return the generated code.
- return GetCode(function);
+ // Invoke the function.
+ __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
+ NullCallWrapper(), call_kind());
}
// Restore receiver.
__ mov(edx, Operand(esp, (argc + 1) * kPointerSize));
- // Check that the function really is a function.
- __ JumpIfSmi(eax, &miss);
- __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
- __ j(not_equal, &miss);
-
- // Patch the receiver on the stack with the global proxy if
- // necessary.
- if (object->IsGlobalObject()) {
- __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset));
- __ mov(Operand(esp, (argc + 1) * kPointerSize), edx);
- }
-
- // Invoke the function.
- __ mov(edi, eax);
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- __ InvokeFunction(edi, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
+ GenerateJumpFunction(object, eax, &miss);
- // Handle load cache miss.
- __ bind(&miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&miss);
// Return the generated code.
return GetCode(Code::FAST, name);
Label miss;
HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
+ // Potentially loads a closure that matches the shared function info of the
+ // function, rather than function.
GenerateLoadFunctionFromCell(cell, function, &miss);
- PatchGlobalProxy(object);
-
- // Set up the context (function already in edi).
- __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
-
- // Jump to the cached code (tail call).
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->call_global_inline(), 1);
- ParameterCount expected(function->shared()->formal_parameter_count());
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- // We call indirectly through the code field in the function to
- // allow recompilation to take effect without changing any of the
- // call sites.
- __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset),
- expected, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
+ GenerateJumpFunction(object, edi, function);
HandlerFrontendFooter(&miss);
}
-void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+void MacroAssembler::InvokeFunction(Register function,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
// You can't call a function without a valid frame.
ASSERT(flag == JUMP_FUNCTION || has_frame());
+ // Contract with called JS functions requires that function is passed in a1.
+ ASSERT(function.is(a1));
+
// Get the function and setup the context.
- li(a1, function);
lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
// We call indirectly through the code field in the function to
}
+void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper,
+ CallKind call_kind) {
+ li(a1, function);
+ InvokeFunction(a1, expected, actual, flag, call_wrapper, call_kind);
+}
+
+
void MacroAssembler::IsObjectJSObjectType(Register heap_object,
Register map,
Register scratch,
const CallWrapper& call_wrapper,
CallKind call_kind);
+ void InvokeFunction(Register function,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper,
+ CallKind call_kind);
+
void InvokeFunction(Handle<JSFunction> function,
const ParameterCount& expected,
const ParameterCount& actual,
}
-static void GenerateCallFunction(MacroAssembler* masm,
- Handle<Object> object,
- const ParameterCount& arguments,
- Label* miss,
- ExtraICState extra_ic_state) {
- // ----------- S t a t e -------------
- // -- a0: receiver
- // -- a1: function to call
- // -----------------------------------
- // Check that the function really is a function.
- __ JumpIfSmi(a1, miss);
- __ GetObjectType(a1, a3, a3);
- __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
-
- if (object->IsGlobalObject()) {
- const int argc = arguments.immediate();
- const int receiver_offset = argc * kPointerSize;
- __ lw(a3, FieldMemOperand(a0, GlobalObject::kGlobalReceiverOffset));
- __ sw(a3, MemOperand(sp, receiver_offset));
- }
-
- // Invoke the function.
- CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- __ InvokeFunction(a1, arguments, JUMP_FUNCTION, NullCallWrapper(), call_kind);
-}
-
-
static void PushInterceptorArguments(MacroAssembler* masm,
Register receiver,
Register holder,
class CallInterceptorCompiler BASE_EMBEDDED {
public:
- CallInterceptorCompiler(StubCompiler* stub_compiler,
+ CallInterceptorCompiler(CallStubCompiler* stub_compiler,
const ParameterCount& arguments,
Register name,
ExtraICState extra_ic_state)
GenerateFastApiDirectCall(
masm, optimization, arguments_.immediate(), false);
} else {
- CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
Handle<JSFunction> function = optimization.constant_function();
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments_,
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
+ stub_compiler_->GenerateJumpFunctionIgnoreReceiver(function);
}
// Deferred code for fast API call case---clean preallocated space.
__ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
}
- StubCompiler* stub_compiler_;
+ CallStubCompiler* stub_compiler_;
const ParameterCount& arguments_;
Register name_;
ExtraICState extra_ic_state_;
}
+void CallStubCompiler::GenerateFunctionCheck(Register function,
+ Register scratch,
+ Label* miss) {
+ __ JumpIfSmi(function, miss);
+ __ GetObjectType(function, scratch, scratch);
+ __ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
+}
+
+
void CallStubCompiler::GenerateLoadFunctionFromCell(
Handle<Cell> cell,
Handle<JSFunction> function,
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
- __ JumpIfSmi(a1, miss);
- __ GetObjectType(a1, a3, a3);
- __ Branch(miss, ne, a3, Operand(JS_FUNCTION_TYPE));
+ GenerateFunctionCheck(a1, a3, miss);
// Check the shared function info. Make sure it hasn't changed.
__ li(a3, Handle<SharedFunctionInfo>(function->shared()));
object, holder, name, RECEIVER_MAP_CHECK, &miss);
GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
index.translate(holder), Representation::Tagged());
-
- GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
+ GenerateJumpFunction(object, a1, &miss);
HandlerFrontendFooter(&miss);
__ bind(&miss);
// Restore function name in a2.
__ li(a2, name);
- __ bind(&name_miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&name_miss);
// Return the generated code.
return GetCode(type, name);
__ bind(&miss);
// Restore function name in a2.
__ li(a2, name);
- __ bind(&name_miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&name_miss);
// Return the generated code.
return GetCode(type, name);
StubRuntimeCallHelper call_helper;
generator.GenerateSlow(masm(), call_helper);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ ctc1(a3, FCSR);
__ bind(&slow);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ sw(a3, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
__ DropAndRet(argc + 1);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ bind(&miss);
FreeSpaceForFastApiCall(masm());
- __ bind(&miss_before_stack_reserved);
- GenerateMissBranch();
+ HandlerFrontendFooter(&miss_before_stack_reserved);
// Return the generated code.
return GetCode(function);
}
-void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
-}
-
-
-Handle<Code> CallStubCompiler::CompileCallConstant(
- Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Name> name,
- CheckType check,
- Handle<JSFunction> function) {
- if (HasCustomCallGenerator(function)) {
- Handle<Code> code = CompileCustomCall(object, holder,
- Handle<Cell>::null(),
- function, Handle<String>::cast(name),
- Code::FAST);
- // A null handle means bail out to the regular compiler code below.
- if (!code.is_null()) return code;
- }
-
- Label miss;
- HandlerFrontendHeader(object, holder, name, check, &miss);
+void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
+ Register function,
+ Label* miss) {
+ ASSERT(function.is(a1));
+ // Check that the function really is a function.
+ GenerateFunctionCheck(function, a3, miss);
PatchGlobalProxy(object);
- CompileHandlerBackend(function);
- HandlerFrontendFooter(&miss);
-
- // Return the generated code.
- return GetCode(function);
+ // Invoke the function.
+ __ InvokeFunction(a1, arguments(), JUMP_FUNCTION,
+ NullCallWrapper(), call_kind());
}
// Restore receiver.
__ lw(a0, MemOperand(sp, argc * kPointerSize));
- GenerateCallFunction(masm(), object, arguments(), &miss, extra_state_);
+ GenerateJumpFunction(object, a1, &miss);
- // Handle call cache miss.
- __ bind(&miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&miss);
// Return the generated code.
return GetCode(Code::FAST, name);
Label miss;
HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
+ // Potentially loads a closure that matches the shared function info of the
+ // function, rather than function.
GenerateLoadFunctionFromCell(cell, function, &miss);
- PatchGlobalProxy(object);
-
- // Set up the context (function already in r1).
- __ lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
-
- // Jump to the cached code (tail call).
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
- ParameterCount expected(function->shared()->formal_parameter_count());
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- // We call indirectly through the code field in the function to
- // allow recompilation to take effect without changing any of the
- // call sites.
- __ lw(a3, FieldMemOperand(a1, JSFunction::kCodeEntryOffset));
- __ InvokeCode(a3, expected, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
-
+ GenerateJumpFunction(object, a1, function);
HandlerFrontendFooter(&miss);
// Return the generated code.
#define __ ACCESS_MASM(masm())
+CallKind CallStubCompiler::call_kind() {
+ return CallICBase::Contextual::decode(extra_state_)
+ ? CALL_AS_FUNCTION
+ : CALL_AS_METHOD;
+}
+
+
void CallStubCompiler::HandlerFrontendFooter(Label* miss) {
__ bind(miss);
GenerateMissBranch();
}
+void CallStubCompiler::GenerateJumpFunctionIgnoreReceiver(
+ Handle<JSFunction> function) {
+ ParameterCount expected(function);
+ __ InvokeFunction(function, expected, arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), call_kind());
+}
+
+
+void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
+ Handle<JSFunction> function) {
+ PatchGlobalProxy(object);
+ GenerateJumpFunctionIgnoreReceiver(function);
+}
+
+
+void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
+ Register actual_closure,
+ Handle<JSFunction> function) {
+ PatchGlobalProxy(object);
+ ParameterCount expected(function);
+ __ InvokeFunction(actual_closure, expected, arguments(),
+ JUMP_FUNCTION, NullCallWrapper(), call_kind());
+}
+
+
+Handle<Code> CallStubCompiler::CompileCallConstant(
+ Handle<Object> object,
+ Handle<JSObject> holder,
+ Handle<Name> name,
+ CheckType check,
+ Handle<JSFunction> function) {
+ if (HasCustomCallGenerator(function)) {
+ Handle<Code> code = CompileCustomCall(object, holder,
+ Handle<Cell>::null(),
+ function, Handle<String>::cast(name),
+ Code::FAST);
+ // A null handle means bail out to the regular compiler code below.
+ if (!code.is_null()) return code;
+ }
+
+ Label miss;
+ HandlerFrontendHeader(object, holder, name, check, &miss);
+ GenerateJumpFunction(object, function);
+ HandlerFrontendFooter(&miss);
+
+ // Return the generated code.
+ return GetCode(function);
+}
+
+
Register LoadStubCompiler::HandlerFrontendHeader(
Handle<Type> type,
Register object_reg,
Label* miss);
void HandlerFrontendFooter(Label* miss);
- void CompileHandlerBackend(Handle<JSFunction> function);
+ void GenerateJumpFunctionIgnoreReceiver(Handle<JSFunction> function);
+ void GenerateJumpFunction(Handle<Object> object,
+ Handle<JSFunction> function);
+ void GenerateJumpFunction(Handle<Object> object,
+ Register function,
+ Label* miss);
+ // Use to call |actual_closure|, a closure with the same shared function info
+ // as |function|.
+ void GenerateJumpFunction(Handle<Object> object,
+ Register actual_closure,
+ Handle<JSFunction> function);
Handle<Code> CompileCallConstant(Handle<Object> object,
Handle<JSObject> holder,
Handle<JSFunction> function,
Handle<String> name);
+ CallKind call_kind();
+
Handle<Code> GetCode(Code::StubType type, Handle<Name> name);
Handle<Code> GetCode(Handle<JSFunction> function);
Handle<JSFunction> function,
Label* miss);
+ void GenerateFunctionCheck(Register function, Register scratch, Label* miss);
+
// Generates a jump to CallIC miss stub.
void GenerateMissBranch();
}
-void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+void MacroAssembler::InvokeFunction(Register function,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag,
// You can't call a function without a valid frame.
ASSERT(flag == JUMP_FUNCTION || has_frame());
- // Get the function and setup the context.
- Move(rdi, function);
- movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
-
- // We call indirectly through the code field in the function to
- // allow recompilation to take effect without changing any of the
- // call sites.
+ ASSERT(function.is(rdi));
+ movq(rsi, FieldOperand(function, JSFunction::kContextOffset));
+ // Advances rdx to the end of the Code object header, to the start of
+ // the executable code.
movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
+
InvokeCode(rdx, expected, actual, flag, call_wrapper, call_kind);
}
+void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper,
+ CallKind call_kind) {
+ Move(rdi, function);
+ InvokeFunction(rdi, expected, actual, flag, call_wrapper, call_kind);
+}
+
+
void MacroAssembler::InvokePrologue(const ParameterCount& expected,
const ParameterCount& actual,
Handle<Code> code_constant,
const CallWrapper& call_wrapper,
CallKind call_kind);
+ void InvokeFunction(Register function,
+ const ParameterCount& expected,
+ const ParameterCount& actual,
+ InvokeFlag flag,
+ const CallWrapper& call_wrapper,
+ CallKind call_kind);
+
void InvokeFunction(Handle<JSFunction> function,
const ParameterCount& expected,
const ParameterCount& actual,
class CallInterceptorCompiler BASE_EMBEDDED {
public:
- CallInterceptorCompiler(StubCompiler* stub_compiler,
+ CallInterceptorCompiler(CallStubCompiler* stub_compiler,
const ParameterCount& arguments,
Register name,
ExtraICState extra_ic_state)
if (can_do_fast_api_call) {
GenerateFastApiCall(masm, optimization, arguments_.immediate());
} else {
- CallKind call_kind = CallICBase::Contextual::decode(extra_ic_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
Handle<JSFunction> fun = optimization.constant_function();
- ParameterCount expected(fun);
- __ InvokeFunction(fun, expected, arguments_,
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
+ stub_compiler_->GenerateJumpFunctionIgnoreReceiver(fun);
}
// Deferred code for fast API call case---clean preallocated space.
__ j(not_equal, interceptor_succeeded);
}
- StubCompiler* stub_compiler_;
+ CallStubCompiler* stub_compiler_;
const ParameterCount& arguments_;
Register name_;
ExtraICState extra_ic_state_;
}
+void CallStubCompiler::GenerateFunctionCheck(Register function,
+ Register scratch,
+ Label* miss) {
+ __ JumpIfSmi(function, miss);
+ __ CmpObjectType(function, JS_FUNCTION_TYPE, scratch);
+ __ j(not_equal, miss);
+}
+
+
void CallStubCompiler::GenerateLoadFunctionFromCell(
Handle<Cell> cell,
Handle<JSFunction> function,
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
- __ JumpIfSmi(rdi, miss);
- __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
- __ j(not_equal, miss);
+ GenerateFunctionCheck(rdi, rax, miss);
// Check the shared function info. Make sure it hasn't changed.
__ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
GenerateFastPropertyLoad(masm(), rdi, reg, index.is_inobject(holder),
index.translate(holder), Representation::Tagged());
-
- // Check that the function really is a function.
- __ JumpIfSmi(rdi, &miss);
- __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rbx);
- __ j(not_equal, &miss);
-
- PatchGlobalProxy(object);
-
- // Invoke the function.
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
+ GenerateJumpFunction(object, rdi, &miss);
HandlerFrontendFooter(&miss);
__ bind(&miss);
// Restore function name in rcx.
__ Move(rcx, name);
- __ bind(&name_miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&name_miss);
// Return the generated code.
return GetCode(type, name);
__ bind(&miss);
// Restore function name in rcx.
__ Move(rcx, name);
- __ bind(&name_miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&name_miss);
// Return the generated code.
return GetCode(type, name);
StubRuntimeCallHelper call_helper;
generator.GenerateSlow(masm(), call_helper);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ movq(rax, args.GetArgumentOperand(1));
__ ret(2 * kPointerSize);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ MoveDouble(FieldOperand(rax, HeapNumber::kValueOffset), rbx);
__ ret(2 * kPointerSize);
- // Tail call the full function. We do not have to patch the receiver
- // because the function makes no use of it.
__ bind(&slow);
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
+ // We do not have to patch the receiver because the function makes no use of
+ // it.
+ GenerateJumpFunctionIgnoreReceiver(function);
HandlerFrontendFooter(&miss);
__ bind(&miss);
__ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize));
- __ bind(&miss_before_stack_reserved);
- GenerateMissBranch();
+ HandlerFrontendFooter(&miss_before_stack_reserved);
// Return the generated code.
return GetCode(function);
}
-void CallStubCompiler::CompileHandlerBackend(Handle<JSFunction> function) {
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- ParameterCount expected(function);
- __ InvokeFunction(function, expected, arguments(),
- JUMP_FUNCTION, NullCallWrapper(), call_kind);
-}
-
-
-Handle<Code> CallStubCompiler::CompileCallConstant(
- Handle<Object> object,
- Handle<JSObject> holder,
- Handle<Name> name,
- CheckType check,
- Handle<JSFunction> function) {
- if (HasCustomCallGenerator(function)) {
- Handle<Code> code = CompileCustomCall(object, holder,
- Handle<PropertyCell>::null(),
- function, Handle<String>::cast(name),
- Code::FAST);
- // A null handle means bail out to the regular compiler code below.
- if (!code.is_null()) return code;
- }
+void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
+ Register function,
+ Label* miss) {
+ // Check that the function really is a function.
+ GenerateFunctionCheck(function, rbx, miss);
- Label miss;
- HandlerFrontendHeader(object, holder, name, check, &miss);
+ if (!function.is(rdi)) __ movq(rdi, function);
PatchGlobalProxy(object);
- CompileHandlerBackend(function);
- HandlerFrontendFooter(&miss);
- // Return the generated code.
- return GetCode(function);
+ // Invoke the function.
+ __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
+ NullCallWrapper(), call_kind());
}
// Restore receiver.
__ movq(rdx, args.GetReceiverOperand());
- // Check that the function really is a function.
- __ JumpIfSmi(rax, &miss);
- __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
- __ j(not_equal, &miss);
+ GenerateJumpFunction(object, rax, &miss);
- // Patch the receiver on the stack with the global proxy if
- // necessary.
- if (object->IsGlobalObject()) {
- __ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset));
- __ movq(args.GetReceiverOperand(), rdx);
- }
-
- // Invoke the function.
- __ movq(rdi, rax);
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
-
- // Handle load cache miss.
- __ bind(&miss);
- GenerateMissBranch();
+ HandlerFrontendFooter(&miss);
// Return the generated code.
return GetCode(Code::FAST, name);
Label miss;
HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
+ // Potentially loads a closure that matches the shared function info of the
+ // function, rather than function.
GenerateLoadFunctionFromCell(cell, function, &miss);
- PatchGlobalProxy(object);
-
- // Set up the context (function already in rdi).
- __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
-
- // Jump to the cached code (tail call).
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->call_global_inline(), 1);
- ParameterCount expected(function->shared()->formal_parameter_count());
- CallKind call_kind = CallICBase::Contextual::decode(extra_state_)
- ? CALL_AS_FUNCTION
- : CALL_AS_METHOD;
- // We call indirectly through the code field in the function to
- // allow recompilation to take effect without changing any of the
- // call sites.
- __ movq(rdx, FieldOperand(rdi, JSFunction::kCodeEntryOffset));
- __ InvokeCode(rdx, expected, arguments(), JUMP_FUNCTION,
- NullCallWrapper(), call_kind);
-
+ GenerateJumpFunction(object, rdi, function);
HandlerFrontendFooter(&miss);
// Return the generated code.