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);
}
......
This diff is collapsed.
......@@ -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);
}
......
This diff is collapsed.
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