Index: src/x64/stub-cache-x64.cc |
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc |
index ad39b51e961e3d3ea1963d09cd1e56a03458629a..192f7bad79cbea7d0e7599e99ee0be8580ea1fc2 100644 |
--- a/src/x64/stub-cache-x64.cc |
+++ b/src/x64/stub-cache-x64.cc |
@@ -637,7 +637,7 @@ static void GenerateFastApiCallBody(MacroAssembler* masm, |
class CallInterceptorCompiler BASE_EMBEDDED { |
public: |
- CallInterceptorCompiler(CallStubCompiler* stub_compiler, |
+ CallInterceptorCompiler(StubCompiler* stub_compiler, |
const ParameterCount& arguments, |
Register name, |
ExtraICState extra_ic_state) |
@@ -748,8 +748,13 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
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(); |
- stub_compiler_->GenerateJumpFunction(object, fun); |
+ ParameterCount expected(fun); |
+ __ InvokeFunction(fun, expected, arguments_, |
+ JUMP_FUNCTION, NullCallWrapper(), call_kind); |
} |
// Deferred code for fast API call case---clean preallocated space. |
@@ -817,7 +822,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
__ j(not_equal, interceptor_succeeded); |
} |
- CallStubCompiler* stub_compiler_; |
+ StubCompiler* stub_compiler_; |
const ParameterCount& arguments_; |
Register name_; |
ExtraICState extra_ic_state_; |
@@ -1532,15 +1537,6 @@ void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) { |
} |
-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, |
@@ -1556,7 +1552,9 @@ void CallStubCompiler::GenerateLoadFunctionFromCell( |
// 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. |
- GenerateFunctionCheck(rdi, rax, miss); |
+ __ JumpIfSmi(rdi, miss); |
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax); |
+ __ j(not_equal, miss); |
// Check the shared function info. Make sure it hasn't changed. |
__ Move(rax, Handle<SharedFunctionInfo>(function->shared())); |
@@ -1588,7 +1586,20 @@ Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object, |
GenerateFastPropertyLoad(masm(), rdi, reg, index.is_inobject(holder), |
index.translate(holder), Representation::Tagged()); |
- GenerateJumpFunction(object, rdi, &miss); |
+ |
+ // 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); |
HandlerFrontendFooter(&miss); |
@@ -2003,7 +2014,8 @@ Handle<Code> CallStubCompiler::CompileStringCharCodeAtCall( |
__ bind(&miss); |
// Restore function name in rcx. |
__ Move(rcx, name); |
- HandlerFrontendFooter(&name_miss); |
+ __ bind(&name_miss); |
+ GenerateMissBranch(); |
// Return the generated code. |
return GetCode(type, name); |
@@ -2068,7 +2080,8 @@ Handle<Code> CallStubCompiler::CompileStringCharAtCall( |
__ bind(&miss); |
// Restore function name in rcx. |
__ Move(rcx, name); |
- HandlerFrontendFooter(&name_miss); |
+ __ bind(&name_miss); |
+ GenerateMissBranch(); |
// Return the generated code. |
return GetCode(type, name); |
@@ -2114,10 +2127,15 @@ Handle<Code> CallStubCompiler::CompileStringFromCharCodeCall( |
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); |
- // We do not have to patch the receiver because the function makes no use of |
- // it. |
- GenerateJumpFunctionIgnoreReceiver(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); |
HandlerFrontendFooter(&miss); |
@@ -2220,10 +2238,12 @@ Handle<Code> CallStubCompiler::CompileMathFloorCall( |
__ 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); |
- // We do not have to patch the receiver because the function makes no use of |
- // it. |
- GenerateJumpFunctionIgnoreReceiver(function); |
+ ParameterCount expected(function); |
+ __ InvokeFunction(function, expected, arguments(), |
+ JUMP_FUNCTION, NullCallWrapper(), CALL_AS_METHOD); |
HandlerFrontendFooter(&miss); |
@@ -2304,10 +2324,15 @@ Handle<Code> CallStubCompiler::CompileMathAbsCall( |
__ 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); |
- // We do not have to patch the receiver because the function makes no use of |
- // it. |
- GenerateJumpFunctionIgnoreReceiver(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); |
HandlerFrontendFooter(&miss); |
@@ -2365,7 +2390,8 @@ Handle<Code> CallStubCompiler::CompileFastApiCall( |
__ bind(&miss); |
__ addq(rsp, Immediate(kFastApiCallArguments * kPointerSize)); |
- HandlerFrontendFooter(&miss_before_stack_reserved); |
+ __ bind(&miss_before_stack_reserved); |
+ GenerateMissBranch(); |
// Return the generated code. |
return GetCode(function); |
@@ -2384,7 +2410,7 @@ void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) { |
void CallStubCompiler::PatchGlobalProxy(Handle<Object> object) { |
- if (!object.is_null() && object->IsGlobalObject()) { |
+ if (object->IsGlobalObject()) { |
StackArgumentsAccessor args(rsp, arguments()); |
__ movq(rdx, FieldOperand(rdx, GlobalObject::kGlobalReceiverOffset)); |
__ movq(args.GetReceiverOperand(), rdx); |
@@ -2473,18 +2499,39 @@ Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object, |
} |
-void CallStubCompiler::GenerateJumpFunction(Handle<Object> object, |
- Register function, |
- Label* miss) { |
- // Check that the function really is a function. |
- GenerateFunctionCheck(function, rbx, miss); |
+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); |
+} |
+ |
- if (!function.is(rdi)) __ movq(rdi, function); |
+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; |
+ } |
+ |
+ Label miss; |
+ HandlerFrontendHeader(object, holder, name, check, &miss); |
PatchGlobalProxy(object); |
+ CompileHandlerBackend(function); |
+ HandlerFrontendFooter(&miss); |
- // Invoke the function. |
- __ InvokeFunction(rdi, arguments(), JUMP_FUNCTION, |
- NullCallWrapper(), call_kind()); |
+ // Return the generated code. |
+ return GetCode(function); |
} |
@@ -2508,9 +2555,29 @@ Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object, |
// Restore receiver. |
__ movq(rdx, args.GetReceiverOperand()); |
- GenerateJumpFunction(object, rax, &miss); |
+ // Check that the function really is a function. |
+ __ JumpIfSmi(rax, &miss); |
+ __ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx); |
+ __ j(not_equal, &miss); |
- HandlerFrontendFooter(&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(); |
// Return the generated code. |
return GetCode(Code::FAST, name); |
@@ -2533,12 +2600,26 @@ Handle<Code> CallStubCompiler::CompileCallGlobal( |
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); |
- GenerateJumpFunction(object, rdi, function); |
+ 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); |
+ |
HandlerFrontendFooter(&miss); |
// Return the generated code. |