Inline functions that use arguments object in f.apply(o, arguments) pattern.
Support arguments materialization after deoptimization in all frames (not only in topmost one). R=fschneider@chromium.org Review URL: https://chromiumcodereview.appspot.com/9643001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11008 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
03cfc4363b
commit
da03f56b1f
@ -1098,6 +1098,14 @@ LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
|
||||
LOperand* receiver = UseRegisterAtStart(instr->receiver());
|
||||
LOperand* function = UseRegisterAtStart(instr->function());
|
||||
LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
|
||||
return AssignEnvironment(DefineSameAsFirst(result));
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
|
||||
LOperand* function = UseFixed(instr->function(), r1);
|
||||
LOperand* receiver = UseFixed(instr->receiver(), r0);
|
||||
|
@ -178,7 +178,8 @@ class LCodeGen;
|
||||
V(ForInCacheArray) \
|
||||
V(CheckMapValue) \
|
||||
V(LoadFieldByIndex) \
|
||||
V(DateField)
|
||||
V(DateField) \
|
||||
V(WrapReceiver)
|
||||
|
||||
|
||||
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
|
||||
@ -468,6 +469,20 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> {
|
||||
};
|
||||
|
||||
|
||||
class LWrapReceiver: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LWrapReceiver(LOperand* receiver, LOperand* function) {
|
||||
inputs_[0] = receiver;
|
||||
inputs_[1] = function;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver")
|
||||
|
||||
LOperand* receiver() { return inputs_[0]; }
|
||||
LOperand* function() { return inputs_[1]; }
|
||||
};
|
||||
|
||||
|
||||
class LApplyArguments: public LTemplateInstruction<1, 4, 0> {
|
||||
public:
|
||||
LApplyArguments(LOperand* function,
|
||||
|
@ -2800,15 +2800,10 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
Register receiver = ToRegister(instr->receiver());
|
||||
Register function = ToRegister(instr->function());
|
||||
Register length = ToRegister(instr->length());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
Register scratch = scratch0();
|
||||
ASSERT(receiver.is(r0)); // Used for parameter count.
|
||||
ASSERT(function.is(r1)); // Required by InvokeFunction.
|
||||
ASSERT(ToRegister(instr->result()).is(r0));
|
||||
|
||||
// If the receiver is null or undefined, we have to pass the global
|
||||
// object as a receiver to normal functions. Values have to be
|
||||
@ -2849,6 +2844,18 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
__ ldr(receiver,
|
||||
FieldMemOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&receiver_ok);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
Register receiver = ToRegister(instr->receiver());
|
||||
Register function = ToRegister(instr->function());
|
||||
Register length = ToRegister(instr->length());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
Register scratch = scratch0();
|
||||
ASSERT(receiver.is(r0)); // Used for parameter count.
|
||||
ASSERT(function.is(r1)); // Required by InvokeFunction.
|
||||
ASSERT(ToRegister(instr->result()).is(r0));
|
||||
|
||||
// Copy the arguments to this function possibly from the
|
||||
// adaptor frame below it.
|
||||
|
@ -847,7 +847,6 @@ void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
|
||||
case Translation::ARGUMENTS_OBJECT: {
|
||||
// Use the arguments marker value as a sentinel and fill in the arguments
|
||||
// object after the deoptimized frame is built.
|
||||
ASSERT(frame_index == 0); // Only supported for first frame.
|
||||
if (FLAG_trace_deopt) {
|
||||
PrintF(" 0x%08" V8PRIxPTR ": [top + %d] <- ",
|
||||
output_[frame_index]->GetTop() + output_offset,
|
||||
|
@ -169,6 +169,7 @@ DEFINE_bool(trace_osr, false, "trace on-stack replacement")
|
||||
DEFINE_int(stress_runs, 0, "number of stress runs")
|
||||
DEFINE_bool(optimize_closures, true, "optimize closures")
|
||||
DEFINE_bool(inline_construct, false, "inline constructor calls")
|
||||
DEFINE_bool(inline_arguments, true, "inline functions with arguments object")
|
||||
DEFINE_int(loop_weight, 1, "loop weight for representation inference")
|
||||
|
||||
DEFINE_bool(optimize_for_in, true,
|
||||
|
@ -885,6 +885,15 @@ HValue* HChange::Canonicalize() {
|
||||
}
|
||||
|
||||
|
||||
HValue* HWrapReceiver::Canonicalize() {
|
||||
if (HasNoUses()) return NULL;
|
||||
if (receiver()->type().IsJSObject()) {
|
||||
return receiver();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
void HTypeof::PrintDataTo(StringStream* stream) {
|
||||
value()->PrintNameTo(stream);
|
||||
}
|
||||
|
@ -185,7 +185,8 @@ class LChunkBuilder;
|
||||
V(ForInCacheArray) \
|
||||
V(CheckMapValue) \
|
||||
V(LoadFieldByIndex) \
|
||||
V(DateField)
|
||||
V(DateField) \
|
||||
V(WrapReceiver)
|
||||
|
||||
#define GVN_FLAG_LIST(V) \
|
||||
V(Calls) \
|
||||
@ -2503,6 +2504,27 @@ class HBinaryOperation: public HTemplateInstruction<3> {
|
||||
};
|
||||
|
||||
|
||||
class HWrapReceiver: public HTemplateInstruction<2> {
|
||||
public:
|
||||
HWrapReceiver(HValue* receiver, HValue* function) {
|
||||
set_representation(Representation::Tagged());
|
||||
SetOperandAt(0, receiver);
|
||||
SetOperandAt(1, function);
|
||||
}
|
||||
|
||||
virtual Representation RequiredInputRepresentation(int index) {
|
||||
return Representation::Tagged();
|
||||
}
|
||||
|
||||
HValue* receiver() { return OperandAt(0); }
|
||||
HValue* function() { return OperandAt(1); }
|
||||
|
||||
virtual HValue* Canonicalize();
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(WrapReceiver)
|
||||
};
|
||||
|
||||
|
||||
class HApplyArguments: public HTemplateInstruction<4> {
|
||||
public:
|
||||
HApplyArguments(HValue* function,
|
||||
|
103
src/hydrogen.cc
103
src/hydrogen.cc
@ -2639,10 +2639,14 @@ void HGraphBuilder::SetUpScope(Scope* scope) {
|
||||
if (!scope->arguments()->IsStackAllocated()) {
|
||||
return Bailout("context-allocated arguments");
|
||||
}
|
||||
HArgumentsObject* object = new(zone()) HArgumentsObject;
|
||||
AddInstruction(object);
|
||||
graph()->SetArgumentsObject(object);
|
||||
environment()->Bind(scope->arguments(), object);
|
||||
|
||||
if (!graph()->HasArgumentsObject()) {
|
||||
HArgumentsObject* object = new(zone()) HArgumentsObject;
|
||||
AddInstruction(object);
|
||||
graph()->SetArgumentsObject(object);
|
||||
}
|
||||
environment()->Bind(scope->arguments(),
|
||||
graph()->GetArgumentsObject());
|
||||
}
|
||||
}
|
||||
|
||||
@ -5226,10 +5230,21 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't inline functions that uses the arguments object.
|
||||
// If the function uses the arguments object check that inlining of functions
|
||||
// with arguments object is enabled and the arguments-variable is
|
||||
// stack allocated.
|
||||
if (function->scope()->arguments() != NULL) {
|
||||
TraceInline(target, caller, "target requires special argument handling");
|
||||
return false;
|
||||
if (!FLAG_inline_arguments) {
|
||||
TraceInline(target, caller, "target uses arguments object");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function->scope()->arguments()->IsStackAllocated()) {
|
||||
TraceInline(target,
|
||||
caller,
|
||||
"target uses non-stackallocated arguments object");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// All declarations must be inlineable.
|
||||
@ -5307,6 +5322,17 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
|
||||
function,
|
||||
call_kind,
|
||||
function_state()->is_construct()));
|
||||
// If the function uses arguments object create and bind one.
|
||||
if (function->scope()->arguments() != NULL) {
|
||||
ASSERT(function->scope()->arguments()->IsStackAllocated());
|
||||
if (!graph()->HasArgumentsObject()) {
|
||||
HArgumentsObject* object = new(zone()) HArgumentsObject;
|
||||
AddInstruction(object);
|
||||
graph()->SetArgumentsObject(object);
|
||||
}
|
||||
environment()->Bind(function->scope()->arguments(),
|
||||
graph()->GetArgumentsObject());
|
||||
}
|
||||
VisitDeclarations(target_info.scope()->declarations());
|
||||
VisitStatements(function->body());
|
||||
if (HasStackOverflow()) {
|
||||
@ -5645,13 +5671,6 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
|
||||
HValue* arg_two_value = environment()->Lookup(arg_two->var());
|
||||
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
|
||||
|
||||
// Our implementation of arguments (based on this stack frame or an
|
||||
// adapter below it) does not work for inlined functions.
|
||||
if (function_state()->outer() != NULL) {
|
||||
Bailout("Function.prototype.apply optimization in inlined function");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Found pattern f.apply(receiver, arguments).
|
||||
VisitForValue(prop->obj());
|
||||
if (HasStackOverflow() || current_block() == NULL) return true;
|
||||
@ -5662,13 +5681,55 @@ bool HGraphBuilder::TryCallApply(Call* expr) {
|
||||
VisitForValue(args->at(0));
|
||||
if (HasStackOverflow() || current_block() == NULL) return true;
|
||||
HValue* receiver = Pop();
|
||||
HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
|
||||
HInstruction* length = AddInstruction(new(zone()) HArgumentsLength(elements));
|
||||
HInstruction* result =
|
||||
new(zone()) HApplyArguments(function, receiver, length, elements);
|
||||
result->set_position(expr->position());
|
||||
ast_context()->ReturnInstruction(result, expr->id());
|
||||
return true;
|
||||
|
||||
if (function_state()->outer() == NULL) {
|
||||
HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
|
||||
HInstruction* length =
|
||||
AddInstruction(new(zone()) HArgumentsLength(elements));
|
||||
HValue* wrapped_receiver =
|
||||
AddInstruction(new(zone()) HWrapReceiver(receiver, function));
|
||||
HInstruction* result =
|
||||
new(zone()) HApplyArguments(function,
|
||||
wrapped_receiver,
|
||||
length,
|
||||
elements);
|
||||
result->set_position(expr->position());
|
||||
ast_context()->ReturnInstruction(result, expr->id());
|
||||
return true;
|
||||
} else {
|
||||
// We are inside inlined function and we know exactly what is inside
|
||||
// arguments object.
|
||||
HValue* context = environment()->LookupContext();
|
||||
|
||||
HValue* wrapped_receiver =
|
||||
AddInstruction(new(zone()) HWrapReceiver(receiver, function));
|
||||
PushAndAdd(new(zone()) HPushArgument(wrapped_receiver));
|
||||
|
||||
int parameter_count = environment()->parameter_count();
|
||||
for (int i = 1; i < environment()->parameter_count(); i++) {
|
||||
PushAndAdd(new(zone()) HPushArgument(environment()->Lookup(i)));
|
||||
}
|
||||
|
||||
if (environment()->outer()->frame_type() == ARGUMENTS_ADAPTOR) {
|
||||
HEnvironment* adaptor = environment()->outer();
|
||||
parameter_count = adaptor->parameter_count();
|
||||
|
||||
for (int i = environment()->parameter_count();
|
||||
i < adaptor->parameter_count();
|
||||
i++) {
|
||||
PushAndAdd(new(zone()) HPushArgument(adaptor->Lookup(i)));
|
||||
}
|
||||
}
|
||||
|
||||
HInvokeFunction* call = new(zone()) HInvokeFunction(
|
||||
context,
|
||||
function,
|
||||
parameter_count);
|
||||
Drop(parameter_count);
|
||||
call->set_position(expr->position());
|
||||
ast_context()->ReturnInstruction(call, expr->id());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -2625,15 +2625,10 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
Register receiver = ToRegister(instr->receiver());
|
||||
Register function = ToRegister(instr->function());
|
||||
Register length = ToRegister(instr->length());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
Register scratch = ToRegister(instr->TempAt(0));
|
||||
ASSERT(receiver.is(eax)); // Used for parameter count.
|
||||
ASSERT(function.is(edi)); // Required by InvokeFunction.
|
||||
ASSERT(ToRegister(instr->result()).is(eax));
|
||||
|
||||
// If the receiver is null or undefined, we have to pass the global
|
||||
// object as a receiver to normal functions. Values have to be
|
||||
@ -2675,6 +2670,17 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
__ mov(receiver,
|
||||
FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&receiver_ok);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
Register receiver = ToRegister(instr->receiver());
|
||||
Register function = ToRegister(instr->function());
|
||||
Register length = ToRegister(instr->length());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
ASSERT(receiver.is(eax)); // Used for parameter count.
|
||||
ASSERT(function.is(edi)); // Required by InvokeFunction.
|
||||
ASSERT(ToRegister(instr->result()).is(eax));
|
||||
|
||||
// Copy the arguments to this function possibly from the
|
||||
// adaptor frame below it.
|
||||
|
@ -1111,17 +1111,25 @@ LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
|
||||
LOperand* receiver = UseRegister(instr->receiver());
|
||||
LOperand* function = UseRegisterAtStart(instr->function());
|
||||
LOperand* temp = TempRegister();
|
||||
LWrapReceiver* result =
|
||||
new(zone()) LWrapReceiver(receiver, function, temp);
|
||||
return AssignEnvironment(DefineSameAsFirst(result));
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
|
||||
LOperand* function = UseFixed(instr->function(), edi);
|
||||
LOperand* receiver = UseFixed(instr->receiver(), eax);
|
||||
LOperand* length = UseFixed(instr->length(), ebx);
|
||||
LOperand* elements = UseFixed(instr->elements(), ecx);
|
||||
LOperand* temp = FixedTemp(edx);
|
||||
LApplyArguments* result = new(zone()) LApplyArguments(function,
|
||||
receiver,
|
||||
length,
|
||||
elements,
|
||||
temp);
|
||||
elements);
|
||||
return MarkAsCall(DefineFixed(result, eax), instr, CAN_DEOPTIMIZE_EAGERLY);
|
||||
}
|
||||
|
||||
|
@ -173,7 +173,8 @@ class LCodeGen;
|
||||
V(ForInCacheArray) \
|
||||
V(CheckMapValue) \
|
||||
V(LoadFieldByIndex) \
|
||||
V(DateField)
|
||||
V(DateField) \
|
||||
V(WrapReceiver)
|
||||
|
||||
|
||||
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
|
||||
@ -456,18 +457,33 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> {
|
||||
};
|
||||
|
||||
|
||||
class LApplyArguments: public LTemplateInstruction<1, 4, 1> {
|
||||
class LWrapReceiver: public LTemplateInstruction<1, 2, 1> {
|
||||
public:
|
||||
LWrapReceiver(LOperand* receiver,
|
||||
LOperand* function,
|
||||
LOperand* temp) {
|
||||
inputs_[0] = receiver;
|
||||
inputs_[1] = function;
|
||||
temps_[0] = temp;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver")
|
||||
|
||||
LOperand* receiver() { return inputs_[0]; }
|
||||
LOperand* function() { return inputs_[1]; }
|
||||
};
|
||||
|
||||
|
||||
class LApplyArguments: public LTemplateInstruction<1, 4, 0> {
|
||||
public:
|
||||
LApplyArguments(LOperand* function,
|
||||
LOperand* receiver,
|
||||
LOperand* length,
|
||||
LOperand* elements,
|
||||
LOperand* temp) {
|
||||
LOperand* elements) {
|
||||
inputs_[0] = function;
|
||||
inputs_[1] = receiver;
|
||||
inputs_[2] = length;
|
||||
inputs_[3] = elements;
|
||||
temps_[0] = temp;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments")
|
||||
|
@ -8112,25 +8112,8 @@ class ActivationsFinder : public ThreadVisitor {
|
||||
};
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
RUNTIME_ASSERT(args[0]->IsSmi());
|
||||
Deoptimizer::BailoutType type =
|
||||
static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
|
||||
Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
|
||||
ASSERT(isolate->heap()->IsAllocationAllowed());
|
||||
int jsframes = deoptimizer->jsframe_count();
|
||||
|
||||
deoptimizer->MaterializeHeapNumbers();
|
||||
delete deoptimizer;
|
||||
|
||||
JavaScriptFrameIterator it(isolate);
|
||||
JavaScriptFrame* frame = NULL;
|
||||
for (int i = 0; i < jsframes - 1; i++) it.Advance();
|
||||
frame = it.frame();
|
||||
|
||||
RUNTIME_ASSERT(frame->function()->IsJSFunction());
|
||||
static void MaterializeArgumentsObjectInFrame(Isolate* isolate,
|
||||
JavaScriptFrame* frame) {
|
||||
Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
|
||||
Handle<Object> arguments;
|
||||
for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
|
||||
@ -8147,6 +8130,32 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
|
||||
frame->SetExpression(i, *arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
|
||||
HandleScope scope(isolate);
|
||||
ASSERT(args.length() == 1);
|
||||
RUNTIME_ASSERT(args[0]->IsSmi());
|
||||
Deoptimizer::BailoutType type =
|
||||
static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
|
||||
Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
|
||||
ASSERT(isolate->heap()->IsAllocationAllowed());
|
||||
int jsframes = deoptimizer->jsframe_count();
|
||||
|
||||
deoptimizer->MaterializeHeapNumbers();
|
||||
delete deoptimizer;
|
||||
|
||||
JavaScriptFrameIterator it(isolate);
|
||||
for (int i = 0; i < jsframes - 1; i++) {
|
||||
MaterializeArgumentsObjectInFrame(isolate, it.frame());
|
||||
it.Advance();
|
||||
}
|
||||
|
||||
JavaScriptFrame* frame = it.frame();
|
||||
RUNTIME_ASSERT(frame->function()->IsJSFunction());
|
||||
Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
|
||||
MaterializeArgumentsObjectInFrame(isolate, frame);
|
||||
|
||||
if (type == Deoptimizer::EAGER) {
|
||||
RUNTIME_ASSERT(function->IsOptimized());
|
||||
|
@ -2544,14 +2544,9 @@ void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
|
||||
Register receiver = ToRegister(instr->receiver());
|
||||
Register function = ToRegister(instr->function());
|
||||
Register length = ToRegister(instr->length());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
ASSERT(receiver.is(rax)); // Used for parameter count.
|
||||
ASSERT(function.is(rdi)); // Required by InvokeFunction.
|
||||
ASSERT(ToRegister(instr->result()).is(rax));
|
||||
|
||||
// If the receiver is null or undefined, we have to pass the global
|
||||
// object as a receiver to normal functions. Values have to be
|
||||
@ -2594,6 +2589,17 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
__ movq(receiver,
|
||||
FieldOperand(receiver, JSGlobalObject::kGlobalReceiverOffset));
|
||||
__ bind(&receiver_ok);
|
||||
}
|
||||
|
||||
|
||||
void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
||||
Register receiver = ToRegister(instr->receiver());
|
||||
Register function = ToRegister(instr->function());
|
||||
Register length = ToRegister(instr->length());
|
||||
Register elements = ToRegister(instr->elements());
|
||||
ASSERT(receiver.is(rax)); // Used for parameter count.
|
||||
ASSERT(function.is(rdi)); // Required by InvokeFunction.
|
||||
ASSERT(ToRegister(instr->result()).is(rax));
|
||||
|
||||
// Copy the arguments to this function possibly from the
|
||||
// adaptor frame below it.
|
||||
|
@ -1092,6 +1092,14 @@ LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
|
||||
LOperand* receiver = UseRegister(instr->receiver());
|
||||
LOperand* function = UseRegisterAtStart(instr->function());
|
||||
LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
|
||||
return AssignEnvironment(DefineSameAsFirst(result));
|
||||
}
|
||||
|
||||
|
||||
LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
|
||||
LOperand* function = UseFixed(instr->function(), rdi);
|
||||
LOperand* receiver = UseFixed(instr->receiver(), rax);
|
||||
|
@ -178,7 +178,8 @@ class LCodeGen;
|
||||
V(ForInCacheArray) \
|
||||
V(CheckMapValue) \
|
||||
V(LoadFieldByIndex) \
|
||||
V(DateField)
|
||||
V(DateField) \
|
||||
V(WrapReceiver)
|
||||
|
||||
|
||||
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
|
||||
@ -469,6 +470,20 @@ class LControlInstruction: public LTemplateInstruction<0, I, T> {
|
||||
};
|
||||
|
||||
|
||||
class LWrapReceiver: public LTemplateInstruction<1, 2, 0> {
|
||||
public:
|
||||
LWrapReceiver(LOperand* receiver, LOperand* function) {
|
||||
inputs_[0] = receiver;
|
||||
inputs_[1] = function;
|
||||
}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver")
|
||||
|
||||
LOperand* receiver() { return inputs_[0]; }
|
||||
LOperand* function() { return inputs_[1]; }
|
||||
};
|
||||
|
||||
|
||||
class LApplyArguments: public LTemplateInstruction<1, 4, 0> {
|
||||
public:
|
||||
LApplyArguments(LOperand* function,
|
||||
|
@ -27,11 +27,30 @@
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
// Test inlining functions that use arguments.
|
||||
function f() { return g(1, 2, 3); }
|
||||
function A() {
|
||||
}
|
||||
|
||||
function g(x, y, z) { return %_ArgumentsLength(); }
|
||||
A.prototype.X = function (a, b, c) {
|
||||
assertTrue(this instanceof A);
|
||||
assertEquals(1, a);
|
||||
assertEquals(2, b);
|
||||
assertEquals(3, c);
|
||||
};
|
||||
|
||||
for (var i = 0; i < 5; ++i) f();
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
assertEquals(3, f());
|
||||
A.prototype.Y = function () {
|
||||
this.X.apply(this, arguments);
|
||||
};
|
||||
|
||||
A.prototype.Z = function () {
|
||||
this.Y(1,2,3);
|
||||
};
|
||||
|
||||
var a = new A();
|
||||
a.Z(4,5,6);
|
||||
a.Z(4,5,6);
|
||||
%OptimizeFunctionOnNextCall(a.Z);
|
||||
a.Z(4,5,6);
|
||||
A.prototype.X.apply = function (receiver, args) {
|
||||
return Function.prototype.apply.call(this, receiver, args);
|
||||
};
|
||||
a.Z(4,5,6);
|
||||
|
Loading…
Reference in New Issue
Block a user