Commit 1142dcc8 authored by palfia@homejinni.com's avatar palfia@homejinni.com

MIPS: Remove CallICs

Port r19001 (4b5aa649)

BUG=
R=plind44@gmail.com

Review URL: https://codereview.chromium.org/151903003

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19009 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 40fb3bb0
......@@ -166,19 +166,6 @@ void KeyedLoadFieldStub::InitializeInterfaceDescriptor(
}
void KeyedArrayCallStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
static Register registers[] = { a2 };
descriptor->register_param_count_ = 1;
descriptor->register_params_ = registers;
descriptor->continuation_type_ = TAIL_CALL_CONTINUATION;
descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
descriptor->deoptimization_handler_ =
FUNCTION_ADDR(KeyedCallIC_MissFromStubFailure);
}
void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) {
......@@ -3247,58 +3234,103 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
void CallFunctionStub::Generate(MacroAssembler* masm) {
// a1 : the function to call
// a2 : cache cell for call target
Label slow, non_function;
Label slow, non_function, wrap, cont;
// Check that the function is really a JavaScript function.
// a1: pushed function (to be verified)
__ JumpIfSmi(a1, &non_function);
if (NeedsChecks()) {
// Check that the function is really a JavaScript function.
// a1: pushed function (to be verified)
__ JumpIfSmi(a1, &non_function);
// Goto slow case if we do not have a function.
__ GetObjectType(a1, a3, a3);
__ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE));
// Goto slow case if we do not have a function.
__ GetObjectType(a1, a3, a3);
__ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm);
if (RecordCallTarget()) {
GenerateRecordCallTarget(masm);
}
}
// Fast-case: Invoke the function now.
// a1: pushed function
ParameterCount actual(argc_);
__ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
if (CallAsMethod()) {
if (NeedsChecks()) {
// Do not transform the receiver for strict mode functions and natives.
__ lw(a2, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ lw(a3, FieldMemOperand(a2, SharedFunctionInfo::kCompilerHintsOffset));
int32_t strict_mode_function_mask =
1 << (SharedFunctionInfo::kStrictModeFunction + kSmiTagSize);
int32_t native_mask = 1 << (SharedFunctionInfo::kNative + kSmiTagSize);
__ And(at, a3, Operand(strict_mode_function_mask | native_mask));
__ Branch(&cont, ne, at, Operand(zero_reg));
}
// Slow-case: Non-function called.
__ bind(&slow);
if (RecordCallTarget()) {
// If there is a call target cache, mark it megamorphic in the
// non-function case. MegamorphicSentinel is an immortal immovable
// object (undefined) so no write barrier is needed.
ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
masm->isolate()->heap()->undefined_value());
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ sw(at, FieldMemOperand(a2, Cell::kValueOffset));
// Compute the receiver in non-strict mode.
__ lw(a2, MemOperand(sp, argc_ * kPointerSize));
if (NeedsChecks()) {
// a0: actual number of arguments
// a1: function
// a2: first argument
__ JumpIfSmi(a2, &wrap);
__ GetObjectType(a2, a3, a3);
__ Branch(&wrap, lt, a3, Operand(FIRST_SPEC_OBJECT_TYPE));
} else {
__ jmp(&wrap);
}
__ bind(&cont);
}
// Check for function proxy.
__ Branch(&non_function, ne, a3, Operand(JS_FUNCTION_PROXY_TYPE));
__ push(a1); // Put proxy as additional argument.
__ li(a0, Operand(argc_ + 1, RelocInfo::NONE32));
__ li(a2, Operand(0, RelocInfo::NONE32));
__ GetBuiltinFunction(a1, Builtins::CALL_FUNCTION_PROXY);
{
Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
__ Jump(adaptor, RelocInfo::CODE_TARGET);
__ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
if (NeedsChecks()) {
// Slow-case: Non-function called.
__ bind(&slow);
if (RecordCallTarget()) {
// If there is a call target cache, mark it megamorphic in the
// non-function case. MegamorphicSentinel is an immortal immovable
// object (undefined) so no write barrier is needed.
ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()),
masm->isolate()->heap()->undefined_value());
__ LoadRoot(at, Heap::kUndefinedValueRootIndex);
__ sw(at, FieldMemOperand(a2, Cell::kValueOffset));
}
// Check for function proxy.
__ Branch(&non_function, ne, a3, Operand(JS_FUNCTION_PROXY_TYPE));
__ push(a1); // Put proxy as additional argument.
__ li(a0, Operand(argc_ + 1, RelocInfo::NONE32));
__ li(a2, Operand(0, RelocInfo::NONE32));
__ GetBuiltinFunction(a1, Builtins::CALL_FUNCTION_PROXY);
{
Handle<Code> adaptor =
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
__ Jump(adaptor, RelocInfo::CODE_TARGET);
}
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
__ bind(&non_function);
__ sw(a1, MemOperand(sp, argc_ * kPointerSize));
__ li(a0, Operand(argc_)); // Set up the number of arguments.
__ li(a2, Operand(0, RelocInfo::NONE32));
__ GetBuiltinFunction(a1, Builtins::CALL_NON_FUNCTION);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
}
// CALL_NON_FUNCTION expects the non-function callee as receiver (instead
// of the original receiver from the call site).
__ bind(&non_function);
__ sw(a1, MemOperand(sp, argc_ * kPointerSize));
__ li(a0, Operand(argc_)); // Set up the number of arguments.
__ mov(a2, zero_reg);
__ GetBuiltinFunction(a1, Builtins::CALL_NON_FUNCTION);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
RelocInfo::CODE_TARGET);
if (CallAsMethod()) {
__ bind(&wrap);
// Wrap the receiver and patch it back onto the stack.
{ FrameScope frame_scope(masm, StackFrame::INTERNAL);
__ Push(a1, a2);
__ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ pop(a1);
}
__ mov(a0, v0);
__ sw(a0, MemOperand(sp, argc_ * kPointerSize));
__ jmp(&cont);
}
}
......@@ -5194,23 +5226,6 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
}
void StubFailureTailCallTrampolineStub::Generate(MacroAssembler* masm) {
CEntryStub ces(1, fp_registers_ ? kSaveFPRegs : kDontSaveFPRegs);
__ Call(ces.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
__ mov(a1, v0);
int parameter_count_offset =
StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
__ lw(a0, MemOperand(fp, parameter_count_offset));
// The parameter count above includes the receiver for the arguments passed to
// the deoptimization handler. Subtract the receiver for the parameter count
// for the call.
__ Subu(a0, a0, 1);
masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
ParameterCount argument_count(a0);
__ InvokeFunction(a1, argument_count, JUMP_FUNCTION, NullCallWrapper());
}
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
if (masm->isolate()->function_entry_hook() != NULL) {
ProfileEntryHookStub stub;
......
......@@ -2066,9 +2066,9 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
__ bind(&l_catch);
__ mov(a0, v0);
handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
__ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw"
__ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
__ Push(a3, a0); // iter, exception
__ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw"
__ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
__ Push(a2, a3, a0); // "throw", iter, except
__ jmp(&l_call);
// try { received = %yield result }
......@@ -2096,23 +2096,32 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
kRAHasBeenSaved, kDontSaveFPRegs);
__ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ pop(v0); // result
__ pop(v0); // result
EmitReturnSequence();
__ mov(a0, v0);
__ bind(&l_resume); // received in a0
__ bind(&l_resume); // received in a0
__ PopTryHandler();
// receiver = iter; f = 'next'; arg = received;
__ bind(&l_next);
__ LoadRoot(a2, Heap::knext_stringRootIndex); // "next"
__ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
__ Push(a3, a0); // iter, received
__ LoadRoot(a2, Heap::knext_stringRootIndex); // "next"
__ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
__ Push(a2, a3, a0); // "next", iter, received
// result = receiver[f](arg);
__ bind(&l_call);
Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1);
CallIC(ic);
__ lw(a1, MemOperand(sp, kPointerSize));
__ lw(a0, MemOperand(sp, 2 * kPointerSize));
Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
CallIC(ic, NOT_CONTEXTUAL, TypeFeedbackId::None());
__ mov(a0, v0);
__ mov(a1, a0);
__ sw(a1, MemOperand(sp, 2 * kPointerSize));
CallFunctionStub stub(1, CALL_AS_METHOD);
__ CallStub(&stub);
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ Drop(1); // The function is still on the stack; drop it.
// if (!result.done) goto l_try;
__ bind(&l_loop);
......@@ -2635,63 +2644,95 @@ void FullCodeGenerator::CallIC(Handle<Code> code,
}
void FullCodeGenerator::EmitCallWithIC(Call* expr,
Handle<Object> name,
ContextualMode mode) {
// Code common for calls using the IC.
// Code common for calls using the IC.
void FullCodeGenerator::EmitCallWithIC(Call* expr) {
Expression* callee = expr->expression();
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
CallFunctionFlags flags;
// Get the target function.
if (callee->IsVariableProxy()) {
{ StackValueContext context(this);
EmitVariableLoad(callee->AsVariableProxy());
PrepareForBailout(callee, NO_REGISTERS);
}
// Push undefined as receiver. This is patched in the method prologue if it
// is a classic mode method.
__ Push(isolate()->factory()->undefined_value());
flags = NO_CALL_FUNCTION_FLAGS;
} else {
// Load the function from the receiver.
ASSERT(callee->IsProperty());
__ lw(v0, MemOperand(sp, 0));
EmitNamedPropertyLoad(callee->AsProperty());
PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
// Push the target function under the receiver.
__ lw(at, MemOperand(sp, 0));
__ push(at);
__ sw(v0, MemOperand(sp, kPointerSize));
flags = CALL_AS_METHOD;
}
// Load the arguments.
{ PreservePositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
__ li(a2, Operand(name));
}
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count);
TypeFeedbackId ast_id = mode == CONTEXTUAL
? TypeFeedbackId::None()
: expr->CallFeedbackId();
CallIC(ic, mode, ast_id);
CallFunctionStub stub(arg_count, flags);
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->Plug(v0);
context()->DropAndPlug(1, v0);
}
// Code common for calls using the IC.
void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Expression* key) {
// Load the key.
VisitForAccumulatorValue(key);
// Swap the name of the function and the receiver on the stack to follow
// the calling convention for call ICs.
__ pop(a1);
__ push(v0);
__ push(a1);
// Code common for calls using the IC.
Expression* callee = expr->expression();
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
// Load the function from the receiver.
ASSERT(callee->IsProperty());
__ lw(a1, MemOperand(sp, 0));
EmitKeyedPropertyLoad(callee->AsProperty());
PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
// Push the target function under the receiver.
__ lw(at, MemOperand(sp, 0));
__ push(at);
__ sw(v0, MemOperand(sp, kPointerSize));
{ PreservePositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
}
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
Handle<Code> ic =
isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
__ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
CallIC(ic, NOT_CONTEXTUAL, expr->CallFeedbackId());
CallFunctionStub stub(arg_count, CALL_AS_METHOD);
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
RecordJSReturnSite(expr);
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, v0); // Drop the key still on the stack.
context()->DropAndPlug(1, v0);
}
......@@ -2798,11 +2839,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, v0);
} else if (call_type == Call::GLOBAL_CALL) {
// Push global object as receiver for the call IC.
__ lw(a0, GlobalObjectOperand());
__ push(a0);
VariableProxy* proxy = callee->AsVariableProxy();
EmitCallWithIC(expr, proxy->name(), CONTEXTUAL);
EmitCallWithIC(expr);
} else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy();
......@@ -2848,9 +2885,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
VisitForStackValue(property->obj());
}
if (property->key()->IsPropertyName()) {
EmitCallWithIC(expr,
property->key()->AsLiteral()->value(),
NOT_CONTEXTUAL);
EmitCallWithIC(expr);
} else {
EmitKeyedCallWithIC(expr, property->key());
}
......@@ -4160,32 +4195,48 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Comment cmnt(masm_, "[ CallRuntime");
ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
if (expr->is_jsruntime()) {
// Prepare for calling JS runtime function.
// Push the builtins object as the receiver.
__ lw(a0, GlobalObjectOperand());
__ lw(a0, FieldMemOperand(a0, GlobalObject::kBuiltinsOffset));
__ push(a0);
}
// Load the function from the receiver.
__ li(a2, Operand(expr->name()));
CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
// Push the arguments ("left-to-right").
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Push the target function under the receiver.
__ lw(at, MemOperand(sp, 0));
__ push(at);
__ sw(v0, MemOperand(sp, kPointerSize));
// Push the arguments ("left-to-right").
int arg_count = args->length();
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Record source position of the IC call.
SetSourcePosition(expr->position());
CallFunctionStub stub(arg_count, NO_CALL_FUNCTION_FLAGS);
__ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
__ CallStub(&stub);
if (expr->is_jsruntime()) {
// Call the JS runtime function.
__ li(a2, Operand(expr->name()));
Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count);
CallIC(ic, NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
// Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, v0);
} else {
// Push the arguments ("left-to-right").
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Call the C runtime function.
__ CallRuntime(expr->function(), arg_count);
context()->Plug(v0);
}
context()->Plug(v0);
}
......
......@@ -100,7 +100,7 @@ static void GenerateNameDictionaryReceiverCheck(MacroAssembler* masm,
}
// Helper function used from LoadIC/CallIC GenerateNormal.
// Helper function used from LoadIC GenerateNormal.
//
// elements: Property dictionary. It is not clobbered if a jump to the miss
// label is done.
......@@ -338,307 +338,8 @@ static void GenerateKeyNameCheck(MacroAssembler* masm,
}
// Defined in ic.cc.
Object* CallIC_Miss(Arguments args);
// The generated code does not accept smi keys.
// The generated code falls through if both probes miss.
void CallICBase::GenerateMonomorphicCacheProbe(MacroAssembler* masm,
int argc,
Code::Kind kind,
ExtraICState extra_state) {
// ----------- S t a t e -------------
// -- a1 : receiver
// -- a2 : name
// -----------------------------------
Label number, non_number, non_string, boolean, probe, miss;
// Probe the stub cache.
Code::Flags flags = Code::ComputeFlags(kind,
MONOMORPHIC,
extra_state,
Code::NORMAL,
argc);
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, a1, a2, a3, t0, t1, t2);
// If the stub cache probing failed, the receiver might be a value.
// For value objects, we use the map of the prototype objects for
// the corresponding JSValue for the cache and that is what we need
// to probe.
//
// Check for number.
__ JumpIfSmi(a1, &number, t1);
__ GetObjectType(a1, a3, a3);
__ Branch(&non_number, ne, a3, Operand(HEAP_NUMBER_TYPE));
__ bind(&number);
StubCompiler::GenerateLoadGlobalFunctionPrototype(
masm, Context::NUMBER_FUNCTION_INDEX, a1);
__ Branch(&probe);
// Check for string.
__ bind(&non_number);
__ Branch(&non_string, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
StubCompiler::GenerateLoadGlobalFunctionPrototype(
masm, Context::STRING_FUNCTION_INDEX, a1);
__ Branch(&probe);
// Check for boolean.
__ bind(&non_string);
__ LoadRoot(t0, Heap::kTrueValueRootIndex);
__ Branch(&boolean, eq, a1, Operand(t0));
__ LoadRoot(t1, Heap::kFalseValueRootIndex);
__ Branch(&miss, ne, a1, Operand(t1));
__ bind(&boolean);
StubCompiler::GenerateLoadGlobalFunctionPrototype(
masm, Context::BOOLEAN_FUNCTION_INDEX, a1);
// Probe the stub cache for the value object.
__ bind(&probe);
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, a1, a2, a3, t0, t1, t2);
__ bind(&miss);
}
static void GenerateFunctionTailCall(MacroAssembler* masm,
int argc,
Label* miss,
Register scratch) {
// a1: function
// Check that the value isn't a smi.
__ JumpIfSmi(a1, miss);
// Check that the value is a JSFunction.
__ GetObjectType(a1, scratch, scratch);
__ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
// Invoke the function.
ParameterCount actual(argc);
__ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
}
void CallICBase::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -----------------------------------
Label miss;
// Get the receiver of the function from the stack into a1.
__ lw(a1, MemOperand(sp, argc * kPointerSize));
GenerateNameDictionaryReceiverCheck(masm, a1, a0, a3, t0, &miss);
// a0: elements
// Search the dictionary - put result in register a1.
GenerateDictionaryLoad(masm, &miss, a0, a2, a1, a3, t0);
GenerateFunctionTailCall(masm, argc, &miss, t0);
// Cache miss: Jump to runtime.
__ bind(&miss);
}
void CallICBase::GenerateMiss(MacroAssembler* masm,
int argc,
IC::UtilityId id,
ExtraICState extra_state) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -----------------------------------
Isolate* isolate = masm->isolate();
if (id == IC::kCallIC_Miss) {
__ IncrementCounter(isolate->counters()->call_miss(), 1, a3, t0);
} else {
__ IncrementCounter(isolate->counters()->keyed_call_miss(), 1, a3, t0);
}
// Get the receiver of the function from the stack.
__ lw(a3, MemOperand(sp, argc*kPointerSize));
{
FrameScope scope(masm, StackFrame::INTERNAL);
// Push the receiver and the name of the function.
__ Push(a3, a2);
// Call the entry.
__ PrepareCEntryArgs(2);
__ PrepareCEntryFunction(ExternalReference(IC_Utility(id), isolate));
CEntryStub stub(1);
__ CallStub(&stub);
// Move result to a1 and leave the internal frame.
__ mov(a1, v0);
}
// Check if the receiver is a global object of some sort.
// This can happen only for regular CallIC but not KeyedCallIC.
if (id == IC::kCallIC_Miss) {
Label invoke, global;
__ lw(a2, MemOperand(sp, argc * kPointerSize));
__ JumpIfSmi(a2, &invoke);
__ GetObjectType(a2, a3, a3);
__ Branch(&global, eq, a3, Operand(JS_GLOBAL_OBJECT_TYPE));
__ Branch(&invoke, ne, a3, Operand(JS_BUILTINS_OBJECT_TYPE));
// Patch the receiver on the stack.
__ bind(&global);
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ sw(a2, MemOperand(sp, argc * kPointerSize));
__ bind(&invoke);
}
// Invoke the function.
ParameterCount actual(argc);
__ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
}
void CallIC::GenerateMegamorphic(MacroAssembler* masm,
int argc,
ExtraICState extra_ic_state) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -----------------------------------
// Get the receiver of the function from the stack into a1.
__ lw(a1, MemOperand(sp, argc * kPointerSize));
GenerateMonomorphicCacheProbe(masm, argc, Code::CALL_IC, extra_ic_state);
GenerateMiss(masm, argc, extra_ic_state);
}
void KeyedCallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -----------------------------------
// Get the receiver of the function from the stack into a1.
__ lw(a1, MemOperand(sp, argc * kPointerSize));
Label do_call, slow_call, slow_load, slow_reload_receiver;
Label check_number_dictionary, check_name, lookup_monomorphic_cache;
Label index_smi, index_name;
// Check that the key is a smi.
__ JumpIfNotSmi(a2, &check_name);
__ bind(&index_smi);
// Now the key is known to be a smi. This place is also jumped to from below
// where a numeric string is converted to a smi.
GenerateKeyedLoadReceiverCheck(
masm, a1, a0, a3, Map::kHasIndexedInterceptor, &slow_call);
GenerateFastArrayLoad(
masm, a1, a2, t0, a3, a0, a1, &check_number_dictionary, &slow_load);
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->keyed_call_generic_smi_fast(), 1, a0, a3);
__ bind(&do_call);
// receiver in a1 is not used after this point.
// a2: key
// a1: function
GenerateFunctionTailCall(masm, argc, &slow_call, a0);
__ bind(&check_number_dictionary);
// a2: key
// a3: elements map
// t0: elements pointer
// Check whether the elements is a number dictionary.
__ LoadRoot(at, Heap::kHashTableMapRootIndex);
__ Branch(&slow_load, ne, a3, Operand(at));
__ sra(a0, a2, kSmiTagSize);
// a0: untagged index
__ LoadFromNumberDictionary(&slow_load, t0, a2, a1, a0, a3, t1);
__ IncrementCounter(counters->keyed_call_generic_smi_dict(), 1, a0, a3);
__ jmp(&do_call);
__ bind(&slow_load);
// This branch is taken when calling KeyedCallIC_Miss is neither required
// nor beneficial.
__ IncrementCounter(counters->keyed_call_generic_slow_load(), 1, a0, a3);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(a2, a1, a2); // Save the key and pass the receiver and the key.
__ CallRuntime(Runtime::kKeyedGetProperty, 2);
__ pop(a2); // Restore the key.
}
__ mov(a1, v0);
__ jmp(&do_call);
__ bind(&check_name);
GenerateKeyNameCheck(masm, a2, a0, a3, &index_name, &slow_call);
// The key is known to be a unique name.
// If the receiver is a regular JS object with slow properties then do
// a quick inline probe of the receiver's dictionary.
// Otherwise do the monomorphic cache probe.
GenerateKeyedLoadReceiverCheck(
masm, a1, a0, a3, Map::kHasNamedInterceptor, &lookup_monomorphic_cache);
__ lw(a0, FieldMemOperand(a1, JSObject::kPropertiesOffset));
__ lw(a3, FieldMemOperand(a0, HeapObject::kMapOffset));
__ LoadRoot(at, Heap::kHashTableMapRootIndex);
__ Branch(&lookup_monomorphic_cache, ne, a3, Operand(at));
GenerateDictionaryLoad(masm, &slow_load, a0, a2, a1, a3, t0);
__ IncrementCounter(counters->keyed_call_generic_lookup_dict(), 1, a0, a3);
__ jmp(&do_call);
__ bind(&lookup_monomorphic_cache);
__ IncrementCounter(counters->keyed_call_generic_lookup_cache(), 1, a0, a3);
GenerateMonomorphicCacheProbe(masm,
argc,
Code::KEYED_CALL_IC,
kNoExtraICState);
// Fall through on miss.
__ bind(&slow_call);
// This branch is taken if:
// - the receiver requires boxing or access check,
// - the key is neither smi nor a unique name,
// - the value loaded is not a function,
// - there is hope that the runtime will create a monomorphic call stub,
// that will get fetched next time.
__ IncrementCounter(counters->keyed_call_generic_slow(), 1, a0, a3);
GenerateMiss(masm, argc);
__ bind(&index_name);
__ IndexFromHash(a3, a2);
// Now jump to the place where smi keys are handled.
__ jmp(&index_smi);
}
void KeyedCallIC::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -----------------------------------
// Check if the name is really a name.
Label miss;
__ JumpIfSmi(a2, &miss);
__ IsObjectNameType(a2, a0, &miss);
CallICBase::GenerateNormal(masm, argc);
__ bind(&miss);
GenerateMiss(masm, argc);
}
void LoadIC::GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode) {
void LoadIC::GenerateMegamorphic(MacroAssembler* masm,
ExtraICState extra_state) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
......@@ -646,9 +347,8 @@ void LoadIC::GenerateMegamorphic(MacroAssembler* masm, ContextualMode mode) {
// -----------------------------------
// Probe the stub cache.
ExtraICState extra_ic_state = LoadIC::ComputeExtraICState(mode);
Code::Flags flags = Code::ComputeFlags(
Code::HANDLER, MONOMORPHIC, extra_ic_state,
Code::HANDLER, MONOMORPHIC, extra_state,
Code::NORMAL, Code::LOAD_IC);
masm->isolate()->stub_cache()->GenerateProbe(
masm, flags, a0, a2, a3, t0, t1, t2);
......@@ -858,32 +558,6 @@ void KeyedStoreIC::GenerateNonStrictArguments(MacroAssembler* masm) {
}
void KeyedCallIC::GenerateNonStrictArguments(MacroAssembler* masm,
int argc) {
// ----------- S t a t e -------------
// -- a2 : name
// -- lr : return address
// -----------------------------------
Label slow, notin;
// Load receiver.
__ lw(a1, MemOperand(sp, argc * kPointerSize));
MemOperand mapped_location =
GenerateMappedArgumentsLookup(masm, a1, a2, a3, t0, t1, &notin, &slow);
__ lw(a1, mapped_location);
GenerateFunctionTailCall(masm, argc, &slow, a3);
__ bind(&notin);
// The unmapped lookup expects that the parameter map is in a3.
MemOperand unmapped_location =
GenerateUnmappedArgumentsLookup(masm, a2, a3, t0, &slow);
__ lw(a1, unmapped_location);
__ LoadRoot(a3, Heap::kTheHoleValueRootIndex);
__ Branch(&slow, eq, a1, Operand(a3));
GenerateFunctionTailCall(masm, argc, &slow, a3);
__ bind(&slow);
GenerateMiss(masm, argc);
}
void KeyedLoadIC::GenerateMiss(MacroAssembler* masm) {
// ---------- S t a t e --------------
// -- ra : return address
......
......@@ -3863,13 +3863,8 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
ASSERT(ToRegister(instr->result()).is(v0));
int arity = instr->arity();
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS);
if (instr->hydrogen()->IsTailCall()) {
if (NeedsEagerFrame()) __ mov(sp, fp);
__ Jump(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
} else {
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
}
CallFunctionStub stub(arity, instr->hydrogen()->function_flags());
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
}
......
......@@ -1189,9 +1189,7 @@ LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), a1);
LCallFunction* call = new(zone()) LCallFunction(context, function);
LInstruction* result = DefineFixed(call, v0);
if (instr->IsTailCall()) return result;
return MarkAsCall(result, instr);
return MarkAsCall(DefineFixed(call, v0), instr);
}
......
......@@ -846,146 +846,6 @@ static void GenerateFastApiCall(MacroAssembler* masm,
}
class CallInterceptorCompiler BASE_EMBEDDED {
public:
CallInterceptorCompiler(CallStubCompiler* stub_compiler,
Register name)
: stub_compiler_(stub_compiler),
name_(name) {}
void Compile(MacroAssembler* masm,
Handle<JSObject> object,
Handle<JSObject> holder,
Handle<Name> name,
LookupResult* lookup,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
Label* miss) {
ASSERT(holder->HasNamedInterceptor());
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
// Check that the receiver isn't a smi.
__ JumpIfSmi(receiver, miss);
CallOptimization optimization(lookup);
if (optimization.is_constant_call()) {
CompileCacheable(masm, object, receiver, scratch1, scratch2, scratch3,
holder, lookup, name, optimization, miss);
} else {
CompileRegular(masm, object, receiver, scratch1, scratch2, scratch3,
name, holder, miss);
}
}
private:
void CompileCacheable(MacroAssembler* masm,
Handle<JSObject> object,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
Handle<JSObject> interceptor_holder,
LookupResult* lookup,
Handle<Name> name,
const CallOptimization& optimization,
Label* miss_label) {
ASSERT(optimization.is_constant_call());
ASSERT(!lookup->holder()->IsGlobalObject());
Counters* counters = masm->isolate()->counters();
__ IncrementCounter(counters->call_const_interceptor(), 1,
scratch1, scratch2);
// Check that the maps from receiver to interceptor's holder
// haven't changed and thus we can invoke interceptor.
Label miss_cleanup;
Register holder =
stub_compiler_->CheckPrototypes(
IC::CurrentTypeOf(object, masm->isolate()), receiver,
interceptor_holder, scratch1, scratch2, scratch3,
name, miss_label);
// Invoke an interceptor and if it provides a value,
// branch to |regular_invoke|.
Label regular_invoke;
LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
&regular_invoke);
// Interceptor returned nothing for this property. Try to use cached
// constant function.
// Check that the maps from interceptor's holder to constant function's
// holder haven't changed and thus we can use cached constant function.
if (*interceptor_holder != lookup->holder()) {
stub_compiler_->CheckPrototypes(
IC::CurrentTypeOf(interceptor_holder, masm->isolate()), holder,
handle(lookup->holder()), scratch1, scratch2, scratch3,
name, miss_label);
}
Handle<JSFunction> function = optimization.constant_function();
__ Move(a0, receiver);
stub_compiler_->GenerateJumpFunction(object, function);
// Invoke a regular function.
__ bind(&regular_invoke);
}
void CompileRegular(MacroAssembler* masm,
Handle<JSObject> object,
Register receiver,
Register scratch1,
Register scratch2,
Register scratch3,
Handle<Name> name,
Handle<JSObject> interceptor_holder,
Label* miss_label) {
Register holder =
stub_compiler_->CheckPrototypes(
IC::CurrentTypeOf(object, masm->isolate()), receiver,
interceptor_holder, scratch1, scratch2, scratch3, name, miss_label);
// Call a runtime function to load the interceptor property.
FrameScope scope(masm, StackFrame::INTERNAL);
// Save the name_ register across the call.
__ push(name_);
CompileCallLoadPropertyWithInterceptor(
masm, receiver, holder, name_, interceptor_holder,
IC::kLoadPropertyWithInterceptorForCall);
// Restore the name_ register.
__ pop(name_);
// Leave the internal frame.
}
void LoadWithInterceptor(MacroAssembler* masm,
Register receiver,
Register holder,
Handle<JSObject> holder_obj,
Register scratch,
Label* interceptor_succeeded) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ Push(receiver, holder, name_);
CompileCallLoadPropertyWithInterceptor(
masm, receiver, holder, name_, holder_obj,
IC::kLoadPropertyWithInterceptorOnly);
__ pop(name_);
__ pop(holder);
__ pop(receiver);
}
// If interceptor returns no-result sentinel, call the constant function.
__ LoadRoot(scratch, Heap::kNoInterceptorResultSentinelRootIndex);
__ Branch(interceptor_succeeded, ne, v0, Operand(scratch));
}
CallStubCompiler* stub_compiler_;
Register name_;
};
void StubCompiler::GenerateTailCall(MacroAssembler* masm, Handle<Code> code) {
__ Jump(code, RelocInfo::CODE_TARGET);
}
......@@ -1343,77 +1203,6 @@ void LoadStubCompiler::GenerateLoadInterceptor(
}
void CallStubCompiler::GenerateNameCheck(Handle<Name> name, Label* miss) {
if (kind_ == Code::KEYED_CALL_IC) {
__ Branch(miss, ne, a2, Operand(name));
}
}
void CallStubCompiler::GenerateFunctionCheck(Register function,
Register scratch,
Label* miss) {
__ JumpIfSmi(function, miss);
__ GetObjectType(function, scratch, scratch);
__ Branch(miss, ne, scratch, Operand(JS_FUNCTION_TYPE));
}
void CallStubCompiler::GenerateLoadFunctionFromCell(
Handle<Cell> cell,
Handle<JSFunction> function,
Label* miss) {
// Get the value from the cell.
__ li(a3, Operand(cell));
__ lw(a1, FieldMemOperand(a3, Cell::kValueOffset));
// Check that the cell contains the same function.
if (heap()->InNewSpace(*function)) {
// We can't embed a pointer to a function in new space so we have
// to verify that the shared function info is unchanged. This has
// the nice side effect that multiple closures based on the same
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
GenerateFunctionCheck(a1, a3, miss);
// Check the shared function info. Make sure it hasn't changed.
__ li(a3, Handle<SharedFunctionInfo>(function->shared()));
__ lw(t0, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
__ Branch(miss, ne, t0, Operand(a3));
} else {
__ Branch(miss, ne, a1, Operand(function));
}
}
void CallStubCompiler::GenerateMissBranch() {
Handle<Code> code =
isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(),
kind_,
extra_state());
__ Jump(code, RelocInfo::CODE_TARGET);
}
Handle<Code> CallStubCompiler::CompileCallField(Handle<JSObject> object,
Handle<JSObject> holder,
PropertyIndex index,
Handle<Name> name) {
Label miss;
Register reg = HandlerFrontendHeader(
object, holder, name, RECEIVER_MAP_CHECK, &miss);
GenerateFastPropertyLoad(masm(), a1, reg, index.is_inobject(holder),
index.translate(holder), Representation::Tagged());
GenerateJumpFunction(object, a1, &miss);
HandlerFrontendFooter(&miss);
// Return the generated code.
return GetCode(Code::FAST, name);
}
void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
Label success;
// Check that the object is a boolean.
......@@ -1425,170 +1214,6 @@ void StubCompiler::GenerateBooleanCheck(Register object, Label* miss) {
}
void CallStubCompiler::PatchImplicitReceiver(Handle<Object> object) {
if (object->IsGlobalObject()) {
const int argc = arguments().immediate();
const int receiver_offset = argc * kPointerSize;
__ LoadRoot(a3, Heap::kUndefinedValueRootIndex);
__ sw(a3, MemOperand(sp, receiver_offset));
}
}
Register CallStubCompiler::HandlerFrontendHeader(Handle<Object> object,
Handle<JSObject> holder,
Handle<Name> name,
CheckType check,
Label* miss) {
// ----------- S t a t e -------------
// -- a2 : name
// -- ra : return address
// -----------------------------------
GenerateNameCheck(name, miss);
Register reg = a0;
// Get the receiver from the stack.
const int argc = arguments().immediate();
const int receiver_offset = argc * kPointerSize;
__ lw(a0, MemOperand(sp, receiver_offset));
// Check that the receiver isn't a smi.
if (check != NUMBER_CHECK) {
__ JumpIfSmi(a0, miss);
}
// Make sure that it's okay not to patch the on stack receiver
// unless we're doing a receiver map check.
ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK);
switch (check) {
case RECEIVER_MAP_CHECK:
__ IncrementCounter(isolate()->counters()->call_const(), 1, a1, a3);
// Check that the maps haven't changed.
reg = CheckPrototypes(
IC::CurrentTypeOf(object, isolate()),
reg, holder, a1, a3, t0, name, miss);
break;
case STRING_CHECK: {
// Check that the object is a string.
__ GetObjectType(reg, a3, a3);
__ Branch(miss, Ugreater_equal, a3, Operand(FIRST_NONSTRING_TYPE));
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::STRING_FUNCTION_INDEX, a1, miss);
break;
}
case SYMBOL_CHECK: {
// Check that the object is a symbol.
__ GetObjectType(reg, a1, a3);
__ Branch(miss, ne, a3, Operand(SYMBOL_TYPE));
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::SYMBOL_FUNCTION_INDEX, a1, miss);
break;
}
case NUMBER_CHECK: {
Label fast;
// Check that the object is a smi or a heap number.
__ JumpIfSmi(reg, &fast);
__ GetObjectType(reg, a3, a3);
__ Branch(miss, ne, a3, Operand(HEAP_NUMBER_TYPE));
__ bind(&fast);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::NUMBER_FUNCTION_INDEX, a1, miss);
break;
}
case BOOLEAN_CHECK: {
GenerateBooleanCheck(reg, miss);
// Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::BOOLEAN_FUNCTION_INDEX, a1, miss);
break;
}
}
if (check != RECEIVER_MAP_CHECK) {
Handle<Object> prototype(object->GetPrototype(isolate()), isolate());
reg = CheckPrototypes(
IC::CurrentTypeOf(prototype, isolate()),
a1, holder, a1, a3, t0, name, miss);
}
return reg;
}
void CallStubCompiler::GenerateJumpFunction(Handle<Object> object,
Register function,
Label* miss) {
ASSERT(function.is(a1));
// Check that the function really is a function.
GenerateFunctionCheck(function, a3, miss);
PatchImplicitReceiver(object);
// Invoke the function.
__ InvokeFunction(a1, arguments(), JUMP_FUNCTION, NullCallWrapper());
}
Handle<Code> CallStubCompiler::CompileCallInterceptor(Handle<JSObject> object,
Handle<JSObject> holder,
Handle<Name> name) {
Label miss;
GenerateNameCheck(name, &miss);
// Get the number of arguments.
const int argc = arguments().immediate();
LookupResult lookup(isolate());
LookupPostInterceptor(holder, name, &lookup);
// Get the receiver from the stack.
__ lw(a1, MemOperand(sp, argc * kPointerSize));
CallInterceptorCompiler compiler(this, a2);
compiler.Compile(masm(), object, holder, name, &lookup, a1, a3, t0, a0,
&miss);
// Move returned value, the function to call, to a1.
__ mov(a1, v0);
// Restore receiver.
__ lw(a0, MemOperand(sp, argc * kPointerSize));
GenerateJumpFunction(object, a1, &miss);
HandlerFrontendFooter(&miss);
// Return the generated code.
return GetCode(Code::FAST, name);
}
Handle<Code> CallStubCompiler::CompileCallGlobal(
Handle<JSObject> object,
Handle<GlobalObject> holder,
Handle<PropertyCell> cell,
Handle<JSFunction> function,
Handle<Name> name) {
Label miss;
HandlerFrontendHeader(object, holder, name, RECEIVER_MAP_CHECK, &miss);
// Potentially loads a closure that matches the shared function info of the
// function, rather than function.
GenerateLoadFunctionFromCell(cell, function, &miss);
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->call_global_inline(), 1, a3, t0);
GenerateJumpFunction(object, a1, function);
HandlerFrontendFooter(&miss);
// Return the generated code.
return GetCode(Code::NORMAL, name);
}
Handle<Code> StoreStubCompiler::CompileStoreCallback(
Handle<JSObject> object,
Handle<JSObject> holder,
......@@ -1817,13 +1442,13 @@ Handle<Code> LoadStubCompiler::CompileLoadGlobal(
__ Branch(&miss, eq, t0, Operand(at));
}
HandlerFrontendFooter(name, &miss);
Counters* counters = isolate()->counters();
__ IncrementCounter(counters->named_load_global_stub(), 1, a1, a3);
__ Ret(USE_DELAY_SLOT);
__ mov(v0, t0);
HandlerFrontendFooter(name, &miss);
// Return the generated code.
return GetCode(kind(), Code::NORMAL, name);
}
......
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