| 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) {
|
|
|