Revision: 10546
Author:   [email protected]
Date:     Mon Jan 30 02:58:22 2012
Log:      MIPS: Implement target cache for constructor calls.

Port r10531 (d61db240).

Original commit message:

This caches call targets of constructor calls by associating one element
caches with call sites. The type feedback oracle can use the recorded
valued to gather type information for monomorphic constructor call sites.

BUG=
TEST=

Review URL: https://chromiumcodereview.appspot.com/9298014
Patch from Daniel Kalmar <[email protected]>.
http://code.google.com/p/v8/source/detail?r=10546

Modified:
 /branches/bleeding_edge/src/mips/builtins-mips.cc
 /branches/bleeding_edge/src/mips/code-stubs-mips.cc
 /branches/bleeding_edge/src/mips/debug-mips.cc
 /branches/bleeding_edge/src/mips/full-codegen-mips.cc
 /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc

=======================================
--- /branches/bleeding_edge/src/mips/builtins-mips.cc Fri Jan 27 06:40:42 2012 +++ /branches/bleeding_edge/src/mips/builtins-mips.cc Mon Jan 30 02:58:22 2012
@@ -678,7 +678,9 @@
 }


-void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+                                           bool is_api_function,
+                                           bool count_constructions) {
   // ----------- S t a t e -------------
   //  -- a0     : number of arguments
   //  -- a1     : constructor function
@@ -686,45 +688,6 @@
   //  -- sp[...]: constructor arguments
   // -----------------------------------

-  Label slow, non_function_call;
-  // Check that the function is not a smi.
-  __ JumpIfSmi(a1, &non_function_call);
-  // Check that the function is a JSFunction.
-  __ GetObjectType(a1, a2, a2);
-  __ Branch(&slow, ne, a2, Operand(JS_FUNCTION_TYPE));
-
-  // Jump to the function-specific construct stub.
-  __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
-  __ lw(a2, FieldMemOperand(a2, SharedFunctionInfo::kConstructStubOffset));
-  __ Addu(t9, a2, Operand(Code::kHeaderSize - kHeapObjectTag));
-  __ Jump(t9);
-
-  // a0: number of arguments
-  // a1: called object
-  // a2: object type
-  Label do_call;
-  __ bind(&slow);
-  __ Branch(&non_function_call, ne, a2, Operand(JS_FUNCTION_PROXY_TYPE));
-  __ GetBuiltinEntry(a3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
-  __ jmp(&do_call);
-
-  __ bind(&non_function_call);
-  __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
-  __ bind(&do_call);
-  // CALL_NON_FUNCTION expects the non-function constructor as receiver
-  // (instead of the original receiver from the call site). The receiver is
-  // stack element argc.
-  // Set expected number of arguments to zero (not changing a0).
-  __ mov(a2, zero_reg);
-  __ SetCallKind(t1, CALL_AS_METHOD);
-  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
-          RelocInfo::CODE_TARGET);
-}
-
-
-static void Generate_JSConstructStubHelper(MacroAssembler* masm,
-                                           bool is_api_function,
-                                           bool count_constructions) {
   // Should never count constructions for api objects.
   ASSERT(!is_api_function || !count_constructions);

@@ -1147,7 +1110,8 @@
     // Invoke the code and pass argc as a0.
     __ mov(a0, a3);
     if (is_construct) {
-      __ Call(masm->isolate()->builtins()->JSConstructCall());
+      CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
+      __ CallStub(&stub);
     } else {
       ParameterCount actual(a0);
       __ InvokeFunction(a1, actual, CALL_FUNCTION,
=======================================
--- /branches/bleeding_edge/src/mips/code-stubs-mips.cc Fri Jan 20 04:50:39 2012 +++ /branches/bleeding_edge/src/mips/code-stubs-mips.cc Mon Jan 30 02:58:22 2012
@@ -5341,24 +5341,49 @@
 }


-void CallFunctionStub::FinishCode(Handle<Code> code) {
-  code->set_has_function_cache(false);
-}
-
-
-void CallFunctionStub::Clear(Heap* heap, Address address) {
-  UNREACHABLE();
-}
-
-
-Object* CallFunctionStub::GetCachedValue(Address address) {
-  UNREACHABLE();
-  return NULL;
+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.
+  // a1 : the function to call
+  // a2 : cache cell for call target
+  Label done;
+
+  ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
+            masm->isolate()->heap()->undefined_value());
+  ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
+            masm->isolate()->heap()->the_hole_value());
+
+  // Load the cache state into a3.
+  __ lw(a3, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+
+  // A monomorphic cache hit or an already megamorphic state: invoke the
+  // function without changing the state.
+  __ Branch(&done, eq, a3, Operand(a1));
+  __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+  __ Branch(&done, eq, a3, Operand(at));
+
+  // A monomorphic miss (i.e, here the cache is not uninitialized) goes
+  // megamorphic.
+  __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
+  __ Branch(&done, eq, a3, Operand(at));
+  // MegamorphicSentinel is an immortal immovable object (undefined) so no
+  // write-barrier is needed.
+  __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
+  __ sw(at, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+  __ Branch(&done);
+
+  // An uninitialized cache is patched with the function.
+  __ sw(a1, FieldMemOperand(a2, JSGlobalPropertyCell::kValueOffset));
+  // No need for a write barrier here - cells are rescanned.
+
+  __ bind(&done);
 }


 void CallFunctionStub::Generate(MacroAssembler* masm) {
   // a1 : the function to call
+  // a2 : cache cell for call target
   Label slow, non_function;

   // The receiver might implicitly be the global object. This is
@@ -5433,6 +5458,48 @@
   __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
           RelocInfo::CODE_TARGET);
 }
+
+
+void CallConstructStub::Generate(MacroAssembler* masm) {
+  // a0 : number of arguments
+  // a1 : the function to call
+  // a2 : cache cell for call target
+  Label slow, non_function_call;
+
+  // Check that the function is not a smi.
+  __ JumpIfSmi(a1, &non_function_call);
+  // Check that the function is a JSFunction.
+  __ GetObjectType(a1, a3, a3);
+  __ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE));
+
+  if (RecordCallTarget()) {
+    GenerateRecordCallTarget(masm);
+  }
+
+  // Jump to the function-specific construct stub.
+  __ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+  __ lw(a2, FieldMemOperand(a2, SharedFunctionInfo::kConstructStubOffset));
+  __ Addu(at, a2, Operand(Code::kHeaderSize - kHeapObjectTag));
+  __ Jump(at);
+
+  // a0: number of arguments
+  // a1: called object
+  // a3: object type
+  Label do_call;
+  __ bind(&slow);
+  __ Branch(&non_function_call, ne, a3, Operand(JS_FUNCTION_PROXY_TYPE));
+  __ GetBuiltinEntry(a3, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
+  __ jmp(&do_call);
+
+  __ bind(&non_function_call);
+  __ GetBuiltinEntry(a3, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
+  __ bind(&do_call);
+  // Set expected number of arguments to zero (not changing r0).
+  __ li(a2, Operand(0, RelocInfo::NONE));
+  __ SetCallKind(t1, CALL_AS_METHOD);
+  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+          RelocInfo::CODE_TARGET);
+}


 // Unfortunately you have to run without snapshots to see most of these
=======================================
--- /branches/bleeding_edge/src/mips/debug-mips.cc      Wed Nov  9 04:19:26 2011
+++ /branches/bleeding_edge/src/mips/debug-mips.cc      Mon Jan 30 02:58:22 2012
@@ -247,7 +247,8 @@
   // Calling convention for construct call (from builtins-mips.cc).
   //  -- a0     : number of arguments (not smi)
   //  -- a1     : constructor function
-  Generate_DebugBreakCallHelper(masm, a1.bit(), a0.bit());
+  //  -- a2     : cache cell for call target
+  Generate_DebugBreakCallHelper(masm, a1.bit() | a2.bit(), a0.bit());
 }


@@ -260,6 +261,7 @@


 void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
+  // Register state for CallFunctionStub (from code-stubs-mips.cc).
   // ----------- S t a t e -------------
   //  -- a1 : function
   // -----------------------------------
=======================================
--- /branches/bleeding_edge/src/mips/full-codegen-mips.cc Mon Jan 16 04:38:59 2012 +++ /branches/bleeding_edge/src/mips/full-codegen-mips.cc Mon Jan 30 02:58:22 2012
@@ -2403,9 +2403,22 @@
   __ li(a0, Operand(arg_count));
   __ lw(a1, MemOperand(sp, arg_count * kPointerSize));

-  Handle<Code> construct_builtin =
-      isolate()->builtins()->JSConstructCall();
-  __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
+  // Record call targets in unoptimized code, but not in the snapshot.
+  CallFunctionFlags flags;
+  if (!Serializer::enabled()) {
+    flags = RECORD_CALL_TARGET;
+    Handle<Object> uninitialized =
+       TypeFeedbackCells::UninitializedSentinel(isolate());
+    Handle<JSGlobalPropertyCell> cell =
+        isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
+    RecordTypeFeedbackCell(expr->id(), cell);
+    __ li(a2, Operand(cell));
+  } else {
+    flags = NO_CALL_FUNCTION_FLAGS;
+  }
+
+  CallConstructStub stub(flags);
+  __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
   context()->Plug(v0);
 }

=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Thu Jan 26 03:26:45 2012 +++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Mon Jan 30 02:58:22 2012
@@ -3277,9 +3277,9 @@
   ASSERT(ToRegister(instr->InputAt(0)).is(a1));
   ASSERT(ToRegister(instr->result()).is(v0));

-  Handle<Code> builtin = isolate()->builtins()->JSConstructCall();
+  CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
   __ li(a0, Operand(instr->arity()));
-  CallCode(builtin, RelocInfo::CONSTRUCT_CALL, instr);
+  CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
 }


--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to