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( ...@@ -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( void KeyedStoreFastElementStub::InitializeInterfaceDescriptor(
Isolate* isolate, Isolate* isolate,
CodeStubInterfaceDescriptor* descriptor) { CodeStubInterfaceDescriptor* descriptor) {
...@@ -3247,58 +3234,103 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) { ...@@ -3247,58 +3234,103 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
void CallFunctionStub::Generate(MacroAssembler* masm) { void CallFunctionStub::Generate(MacroAssembler* masm) {
// a1 : the function to call // a1 : the function to call
// a2 : cache cell for call target // 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. if (NeedsChecks()) {
// a1: pushed function (to be verified) // Check that the function is really a JavaScript function.
__ JumpIfSmi(a1, &non_function); // a1: pushed function (to be verified)
__ JumpIfSmi(a1, &non_function);
// Goto slow case if we do not have a function. // Goto slow case if we do not have a function.
__ GetObjectType(a1, a3, a3); __ GetObjectType(a1, a3, a3);
__ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE)); __ Branch(&slow, ne, a3, Operand(JS_FUNCTION_TYPE));
if (RecordCallTarget()) { if (RecordCallTarget()) {
GenerateRecordCallTarget(masm); GenerateRecordCallTarget(masm);
}
} }
// Fast-case: Invoke the function now. // Fast-case: Invoke the function now.
// a1: pushed function // a1: pushed function
ParameterCount actual(argc_); 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. // Compute the receiver in non-strict mode.
__ bind(&slow); __ lw(a2, MemOperand(sp, argc_ * kPointerSize));
if (RecordCallTarget()) {
// If there is a call target cache, mark it megamorphic in the if (NeedsChecks()) {
// non-function case. MegamorphicSentinel is an immortal immovable // a0: actual number of arguments
// object (undefined) so no write barrier is needed. // a1: function
ASSERT_EQ(*TypeFeedbackCells::MegamorphicSentinel(masm->isolate()), // a2: first argument
masm->isolate()->heap()->undefined_value()); __ JumpIfSmi(a2, &wrap);
__ LoadRoot(at, Heap::kUndefinedValueRootIndex); __ GetObjectType(a2, a3, a3);
__ sw(at, FieldMemOperand(a2, Cell::kValueOffset)); __ Branch(&wrap, lt, a3, Operand(FIRST_SPEC_OBJECT_TYPE));
} else {
__ jmp(&wrap);
}
__ bind(&cont);
} }
// Check for function proxy. __ InvokeFunction(a1, actual, JUMP_FUNCTION, NullCallWrapper());
__ Branch(&non_function, ne, a3, Operand(JS_FUNCTION_PROXY_TYPE));
__ push(a1); // Put proxy as additional argument. if (NeedsChecks()) {
__ li(a0, Operand(argc_ + 1, RelocInfo::NONE32)); // Slow-case: Non-function called.
__ li(a2, Operand(0, RelocInfo::NONE32)); __ bind(&slow);
__ GetBuiltinFunction(a1, Builtins::CALL_FUNCTION_PROXY); if (RecordCallTarget()) {
{ // If there is a call target cache, mark it megamorphic in the
Handle<Code> adaptor = // non-function case. MegamorphicSentinel is an immortal immovable
masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(); // object (undefined) so no write barrier is needed.
__ Jump(adaptor, RelocInfo::CODE_TARGET); 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 if (CallAsMethod()) {
// of the original receiver from the call site). __ bind(&wrap);
__ bind(&non_function); // Wrap the receiver and patch it back onto the stack.
__ sw(a1, MemOperand(sp, argc_ * kPointerSize)); { FrameScope frame_scope(masm, StackFrame::INTERNAL);
__ li(a0, Operand(argc_)); // Set up the number of arguments. __ Push(a1, a2);
__ mov(a2, zero_reg); __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
__ GetBuiltinFunction(a1, Builtins::CALL_NON_FUNCTION); __ pop(a1);
__ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(), }
RelocInfo::CODE_TARGET); __ mov(a0, v0);
__ sw(a0, MemOperand(sp, argc_ * kPointerSize));
__ jmp(&cont);
}
} }
...@@ -5194,23 +5226,6 @@ void StubFailureTrampolineStub::Generate(MacroAssembler* masm) { ...@@ -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) { void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
if (masm->isolate()->function_entry_hook() != NULL) { if (masm->isolate()->function_entry_hook() != NULL) {
ProfileEntryHookStub stub; ProfileEntryHookStub stub;
......
...@@ -2066,9 +2066,9 @@ void FullCodeGenerator::VisitYield(Yield* expr) { ...@@ -2066,9 +2066,9 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
__ bind(&l_catch); __ bind(&l_catch);
__ mov(a0, v0); __ mov(a0, v0);
handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos())); handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
__ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw" __ LoadRoot(a2, Heap::kthrow_stringRootIndex); // "throw"
__ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
__ Push(a3, a0); // iter, exception __ Push(a2, a3, a0); // "throw", iter, except
__ jmp(&l_call); __ jmp(&l_call);
// try { received = %yield result } // try { received = %yield result }
...@@ -2096,23 +2096,32 @@ void FullCodeGenerator::VisitYield(Yield* expr) { ...@@ -2096,23 +2096,32 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
kRAHasBeenSaved, kDontSaveFPRegs); kRAHasBeenSaved, kDontSaveFPRegs);
__ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1); __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ pop(v0); // result __ pop(v0); // result
EmitReturnSequence(); EmitReturnSequence();
__ mov(a0, v0); __ mov(a0, v0);
__ bind(&l_resume); // received in a0 __ bind(&l_resume); // received in a0
__ PopTryHandler(); __ PopTryHandler();
// receiver = iter; f = 'next'; arg = received; // receiver = iter; f = 'next'; arg = received;
__ bind(&l_next); __ bind(&l_next);
__ LoadRoot(a2, Heap::knext_stringRootIndex); // "next" __ LoadRoot(a2, Heap::knext_stringRootIndex); // "next"
__ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter __ lw(a3, MemOperand(sp, 1 * kPointerSize)); // iter
__ Push(a3, a0); // iter, received __ Push(a2, a3, a0); // "next", iter, received
// result = receiver[f](arg); // result = receiver[f](arg);
__ bind(&l_call); __ bind(&l_call);
Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1); __ lw(a1, MemOperand(sp, kPointerSize));
CallIC(ic); __ 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)); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ Drop(1); // The function is still on the stack; drop it.
// if (!result.done) goto l_try; // if (!result.done) goto l_try;
__ bind(&l_loop); __ bind(&l_loop);
...@@ -2635,63 +2644,95 @@ void FullCodeGenerator::CallIC(Handle<Code> code, ...@@ -2635,63 +2644,95 @@ void FullCodeGenerator::CallIC(Handle<Code> code,
} }
void FullCodeGenerator::EmitCallWithIC(Call* expr, // Code common for calls using the IC.
Handle<Object> name, void FullCodeGenerator::EmitCallWithIC(Call* expr) {
ContextualMode mode) { Expression* callee = expr->expression();
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length(); 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()); { PreservePositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) { for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i)); VisitForStackValue(args->at(i));
} }
__ li(a2, Operand(name));
} }
// Record source position for debugger. // Record source position for debugger.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
// Call the IC initialization code. CallFunctionStub stub(arg_count, flags);
Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arg_count); __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
TypeFeedbackId ast_id = mode == CONTEXTUAL __ CallStub(&stub);
? TypeFeedbackId::None()
: expr->CallFeedbackId();
CallIC(ic, mode, ast_id);
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ 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, void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
Expression* key) { Expression* key) {
// Load the key. // Load the key.
VisitForAccumulatorValue(key); VisitForAccumulatorValue(key);
// Swap the name of the function and the receiver on the stack to follow Expression* callee = expr->expression();
// the calling convention for call ICs.
__ pop(a1);
__ push(v0);
__ push(a1);
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length(); 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()); { PreservePositionScope scope(masm()->positions_recorder());
for (int i = 0; i < arg_count; i++) { for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i)); VisitForStackValue(args->at(i));
} }
} }
// Record source position for debugger. // Record source position for debugger.
SetSourcePosition(expr->position()); SetSourcePosition(expr->position());
// Call the IC initialization code. CallFunctionStub stub(arg_count, CALL_AS_METHOD);
Handle<Code> ic = __ lw(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count); __ CallStub(&stub);
__ lw(a2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
CallIC(ic, NOT_CONTEXTUAL, expr->CallFeedbackId());
RecordJSReturnSite(expr); RecordJSReturnSite(expr);
// Restore context register. // Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ 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) { ...@@ -2798,11 +2839,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, v0); context()->DropAndPlug(1, v0);
} else if (call_type == Call::GLOBAL_CALL) { } else if (call_type == Call::GLOBAL_CALL) {
// Push global object as receiver for the call IC. EmitCallWithIC(expr);
__ lw(a0, GlobalObjectOperand());
__ push(a0);
VariableProxy* proxy = callee->AsVariableProxy();
EmitCallWithIC(expr, proxy->name(), CONTEXTUAL);
} else if (call_type == Call::LOOKUP_SLOT_CALL) { } else if (call_type == Call::LOOKUP_SLOT_CALL) {
// Call to a lookup slot (dynamically introduced variable). // Call to a lookup slot (dynamically introduced variable).
VariableProxy* proxy = callee->AsVariableProxy(); VariableProxy* proxy = callee->AsVariableProxy();
...@@ -2848,9 +2885,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { ...@@ -2848,9 +2885,7 @@ void FullCodeGenerator::VisitCall(Call* expr) {
VisitForStackValue(property->obj()); VisitForStackValue(property->obj());
} }
if (property->key()->IsPropertyName()) { if (property->key()->IsPropertyName()) {
EmitCallWithIC(expr, EmitCallWithIC(expr);
property->key()->AsLiteral()->value(),
NOT_CONTEXTUAL);
} else { } else {
EmitKeyedCallWithIC(expr, property->key()); EmitKeyedCallWithIC(expr, property->key());
} }
...@@ -4160,32 +4195,48 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { ...@@ -4160,32 +4195,48 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
Comment cmnt(masm_, "[ CallRuntime"); Comment cmnt(masm_, "[ CallRuntime");
ZoneList<Expression*>* args = expr->arguments(); ZoneList<Expression*>* args = expr->arguments();
int arg_count = args->length();
if (expr->is_jsruntime()) { if (expr->is_jsruntime()) {
// Prepare for calling JS runtime function. // Push the builtins object as the receiver.
__ lw(a0, GlobalObjectOperand()); __ lw(a0, GlobalObjectOperand());
__ lw(a0, FieldMemOperand(a0, GlobalObject::kBuiltinsOffset)); __ lw(a0, FieldMemOperand(a0, GlobalObject::kBuiltinsOffset));
__ push(a0); __ push(a0);
} // Load the function from the receiver.
__ li(a2, Operand(expr->name()));
CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
// Push the arguments ("left-to-right"). // Push the target function under the receiver.
int arg_count = args->length(); __ lw(at, MemOperand(sp, 0));
for (int i = 0; i < arg_count; i++) { __ push(at);
VisitForStackValue(args->at(i)); __ 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. // Restore context register.
__ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); __ lw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
context()->DropAndPlug(1, v0);
} else { } else {
// Push the arguments ("left-to-right").
for (int i = 0; i < arg_count; i++) {
VisitForStackValue(args->at(i));
}
// Call the C runtime function. // Call the C runtime function.
__ CallRuntime(expr->function(), arg_count); __ CallRuntime(expr->function(), arg_count);
context()->Plug(v0);
} }
context()->Plug(v0);
} }
......
This diff is collapsed.
...@@ -3863,13 +3863,8 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) { ...@@ -3863,13 +3863,8 @@ void LCodeGen::DoCallFunction(LCallFunction* instr) {
ASSERT(ToRegister(instr->result()).is(v0)); ASSERT(ToRegister(instr->result()).is(v0));
int arity = instr->arity(); int arity = instr->arity();
CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); CallFunctionStub stub(arity, instr->hydrogen()->function_flags());
if (instr->hydrogen()->IsTailCall()) { CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
if (NeedsEagerFrame()) __ mov(sp, fp);
__ Jump(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
} else {
CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
}
} }
......
...@@ -1189,9 +1189,7 @@ LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) { ...@@ -1189,9 +1189,7 @@ LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp); LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), a1); LOperand* function = UseFixed(instr->function(), a1);
LCallFunction* call = new(zone()) LCallFunction(context, function); LCallFunction* call = new(zone()) LCallFunction(context, function);
LInstruction* result = DefineFixed(call, v0); return MarkAsCall(DefineFixed(call, v0), instr);
if (instr->IsTailCall()) return result;
return MarkAsCall(result, 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