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 <kalmard@homejinni.com>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10546 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 95c37ecb
......@@ -678,7 +678,9 @@ void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
}
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 @@ void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
// -- 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 @@ static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
// 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,
......
......@@ -5341,24 +5341,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.
// a1 : the function to call
// a2 : cache cell for call target
Label done;
void CallFunctionStub::Clear(Heap* heap, Address address) {
UNREACHABLE();
}
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.
Object* CallFunctionStub::GetCachedValue(Address address) {
UNREACHABLE();
return NULL;
__ 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
......@@ -5435,6 +5460,48 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
}
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
// names in the profile since most compare stubs end up in the snapshot.
void CompareStub::PrintName(StringStream* stream) {
......
......@@ -247,7 +247,8 @@ void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
// 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::GenerateReturnDebugBreak(MacroAssembler* masm) {
void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
// Register state for CallFunctionStub (from code-stubs-mips.cc).
// ----------- S t a t e -------------
// -- a1 : function
// -----------------------------------
......
......@@ -2403,9 +2403,22 @@ void FullCodeGenerator::VisitCallNew(CallNew* expr) {
__ 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);
}
......
......@@ -3277,9 +3277,9 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment