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
This commit is contained in:
parent
95c37ecbc9
commit
9ece818b56
@ -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;
|
||||
|
||||
ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
|
||||
masm->isolate()->heap()->undefined_value());
|
||||
ASSERT_EQ(*TypeFeedbackCells::UninitializedSentinel(masm->isolate()),
|
||||
masm->isolate()->heap()->the_hole_value());
|
||||
|
||||
void CallFunctionStub::Clear(Heap* heap, Address address) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
// 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));
|
||||
|
||||
Object* CallFunctionStub::GetCachedValue(Address address) {
|
||||
UNREACHABLE();
|
||||
return NULL;
|
||||
// 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
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user