Index: src/x64/code-stubs-x64.cc |
diff --git a/src/x64/code-stubs-x64.cc b/src/x64/code-stubs-x64.cc |
index 03a5170bae744491a17a054054c3da2c98cf9461..da9ce220df1547f97304ed395837f12b078ed073 100644 |
--- a/src/x64/code-stubs-x64.cc |
+++ b/src/x64/code-stubs-x64.cc |
@@ -3582,24 +3582,47 @@ void StackCheckStub::Generate(MacroAssembler* masm) { |
} |
-void CallFunctionStub::FinishCode(Handle<Code> code) { |
- code->set_has_function_cache(false); |
-} |
- |
- |
-void CallFunctionStub::Clear(Heap* heap, Address address) { |
- UNREACHABLE(); |
-} |
+static void GenerateRecordCallTarget(MacroAssembler* masm) { |
+ // Cache the called function in a global property cell. Cache states |
+ // are uninitialized, monomorphic (indicated by a JSFunction), and |
+ // megamorphic. |
+ // rbx : cache cell for call target |
+ // rdi : the function to call |
+ Isolate* isolate = masm->isolate(); |
+ Label initialize, done; |
+ |
+ // Load the cache state into rcx. |
+ __ movq(rcx, FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset)); |
+ |
+ // A monomorphic cache hit or an already megamorphic state: invoke the |
+ // function without changing the state. |
+ __ cmpq(rcx, rdi); |
+ __ j(equal, &done, Label::kNear); |
+ __ Cmp(rcx, TypeFeedbackCells::MegamorphicSentinel(isolate)); |
+ __ j(equal, &done, Label::kNear); |
+ |
+ // A monomorphic miss (i.e, here the cache is not uninitialized) goes |
+ // megamorphic. |
+ __ Cmp(rcx, TypeFeedbackCells::UninitializedSentinel(isolate)); |
+ __ j(equal, &initialize, Label::kNear); |
+ // MegamorphicSentinel is an immortal immovable object (undefined) so no |
+ // write-barrier is needed. |
+ __ Move(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), |
+ TypeFeedbackCells::MegamorphicSentinel(isolate)); |
+ __ jmp(&done, Label::kNear); |
+ // An uninitialized cache is patched with the function. |
+ __ bind(&initialize); |
+ __ movq(FieldOperand(rbx, JSGlobalPropertyCell::kValueOffset), rdi); |
+ // No need for a write barrier here - cells are rescanned. |
-Object* CallFunctionStub::GetCachedValue(Address address) { |
- UNREACHABLE(); |
- return NULL; |
+ __ bind(&done); |
} |
void CallFunctionStub::Generate(MacroAssembler* masm) { |
// rdi : the function to call |
+ // rbx : cache cell for call target |
Label slow, non_function; |
// The receiver might implicitly be the global object. This is |
@@ -3678,6 +3701,49 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { |
} |
+void CallConstructStub::Generate(MacroAssembler* masm) { |
+ // rax : number of arguments |
+ // rbx : cache cell for call target |
+ // rdi : constructor function |
+ Label slow, non_function_call; |
+ |
+ // Check that function is not a smi. |
+ __ JumpIfSmi(rdi, &non_function_call); |
+ // Check that function is a JSFunction. |
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
+ __ j(not_equal, &slow); |
+ |
+ if (RecordCallTarget()) { |
+ GenerateRecordCallTarget(masm); |
+ } |
+ |
+ // Jump to the function-specific construct stub. |
+ __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
+ __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset)); |
+ __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize)); |
+ __ jmp(rbx); |
+ |
+ // rdi: called object |
+ // rax: number of arguments |
+ // rcx: object map |
+ Label do_call; |
+ __ bind(&slow); |
+ __ CmpInstanceType(rcx, JS_FUNCTION_PROXY_TYPE); |
+ __ j(not_equal, &non_function_call); |
+ __ GetBuiltinEntry(rdx, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); |
+ __ jmp(&do_call); |
+ |
+ __ bind(&non_function_call); |
+ __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
+ __ bind(&do_call); |
+ // Set expected number of arguments to zero (not changing rax). |
+ __ Set(rbx, 0); |
+ __ SetCallKind(rcx, CALL_AS_METHOD); |
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
+ RelocInfo::CODE_TARGET); |
+} |
+ |
+ |
bool CEntryStub::NeedsImmovableCode() { |
return false; |
} |