Index: src/arm/code-stubs-arm.cc |
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc |
index ff1f29dacf2d52494ee53869736f70dda9d03880..d69c17de0cc476cf4b2f088211046f99822209f7 100644 |
--- a/src/arm/code-stubs-arm.cc |
+++ b/src/arm/code-stubs-arm.cc |
@@ -5124,24 +5124,49 @@ void RegExpConstructResultStub::Generate(MacroAssembler* masm) { |
} |
-void CallFunctionStub::FinishCode(Handle<Code> code) { |
- code->set_has_function_cache(false); |
-} |
+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. |
+ // r1 : the function to call |
+ // r2 : cache cell for call target |
+ Isolate* isolate = masm->isolate(); |
+ Label done; |
+ ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(isolate), |
+ isolate->heap()->undefined_value()); |
+ ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(isolate), |
+ isolate->heap()->the_hole_value()); |
-void CallFunctionStub::Clear(Heap* heap, Address address) { |
- UNREACHABLE(); |
-} |
+ // Load the cache state into r3. |
+ __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset)); |
+ // A monomorphic cache hit or an already megamorphic state: invoke the |
+ // function without changing the state. |
+ __ cmp(r3, r1); |
+ __ b(eq, &done); |
+ __ CompareRoot(r3, Heap::kUndefinedValueRootIndex); |
+ __ b(eq, &done); |
+ |
+ // A monomorphic miss (i.e, here the cache is not uninitialized) goes |
+ // megamorphic. |
+ __ CompareRoot(r3, Heap::kTheHoleValueRootIndex); |
+ // MegamorphicSentinel is an immortal immovable object (undefined) so no |
+ // write-barrier is needed. |
+ __ LoadRoot(ip, Heap::kUndefinedValueRootIndex, ne); |
+ __ str(ip, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset), ne); |
+ |
+ // An uninitialized cache is patched with the function. |
+ __ str(r1, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset), eq); |
+ // 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) { |
// r1 : the function to call |
+ // r2 : cache cell for call target |
Label slow, non_function; |
// The receiver might implicitly be the global object. This is |
@@ -5219,6 +5244,48 @@ void CallFunctionStub::Generate(MacroAssembler* masm) { |
} |
+void CallConstructStub::Generate(MacroAssembler* masm) { |
+ // r0 : number of arguments |
+ // r1 : the function to call |
+ // r2 : cache cell for call target |
+ Label slow, non_function_call; |
+ |
+ // Check that the function is not a smi. |
+ __ JumpIfSmi(r1, &non_function_call); |
+ // Check that the function is a JSFunction. |
+ __ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE); |
+ __ b(ne, &slow); |
+ |
+ if (RecordCallTarget()) { |
+ GenerateRecordCallTarget(masm); |
+ } |
+ |
+ // Jump to the function-specific construct stub. |
+ __ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); |
+ __ ldr(r2, FieldMemOperand(r2, SharedFunctionInfo::kConstructStubOffset)); |
+ __ add(pc, r2, Operand(Code::kHeaderSize - kHeapObjectTag)); |
+ |
+ // r0: number of arguments |
+ // r1: called object |
+ // r3: object type |
+ Label do_call; |
+ __ bind(&slow); |
+ __ cmp(r3, Operand(JS_FUNCTION_PROXY_TYPE)); |
+ __ b(ne, &non_function_call); |
+ __ GetBuiltinEntry(r3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR); |
+ __ jmp(&do_call); |
+ |
+ __ bind(&non_function_call); |
+ __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
+ __ bind(&do_call); |
+ // Set expected number of arguments to zero (not changing r0). |
+ __ mov(r2, Operand(0, RelocInfo::NONE)); |
+ __ SetCallKind(r5, CALL_AS_METHOD); |
+ __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), |
+ RelocInfo::CODE_TARGET); |
+} |
+ |
+ |
// Unfortunately you have to run without snapshots to see most of these |
// names in the profile since most compare stubs end up in the snapshot. |
void CompareStub::PrintName(StringStream* stream) { |