}
+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);
V(ForInCacheArray) \
V(CheckMapValue) \
V(LoadFieldByIndex) \
- V(DateField)
+ V(DateField) \
+ V(WrapReceiver)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
};
+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,
}
-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
__ 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.
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,
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,
}
+HValue* HWrapReceiver::Canonicalize() {
+ if (HasNoUses()) return NULL;
+ if (receiver()->type().IsJSObject()) {
+ return receiver();
+ }
+ return this;
+}
+
+
void HTypeof::PrintDataTo(StringStream* stream) {
value()->PrintNameTo(stream);
}
V(ForInCacheArray) \
V(CheckMapValue) \
V(LoadFieldByIndex) \
- V(DateField)
+ V(DateField) \
+ V(WrapReceiver)
#define GVN_FLAG_LIST(V) \
V(Calls) \
};
+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,
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());
}
}
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.
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()) {
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;
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;
+ }
}
}
-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
__ 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.
}
+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);
}
V(ForInCacheArray) \
V(CheckMapValue) \
V(LoadFieldByIndex) \
- V(DateField)
+ V(DateField) \
+ V(WrapReceiver)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
};
-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")
};
+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) {
+ if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
+ if (arguments.is_null()) {
+ // FunctionGetArguments can't throw an exception, so cast away the
+ // doubt with an assert.
+ arguments = Handle<Object>(
+ Accessors::FunctionGetArguments(*function,
+ NULL)->ToObjectUnchecked());
+ ASSERT(*arguments != isolate->heap()->null_value());
+ ASSERT(*arguments != isolate->heap()->undefined_value());
+ }
+ frame->SetExpression(i, *arguments);
+ }
+ }
+}
+
+
RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
HandleScope scope(isolate);
ASSERT(args.length() == 1);
delete deoptimizer;
JavaScriptFrameIterator it(isolate);
- JavaScriptFrame* frame = NULL;
- for (int i = 0; i < jsframes - 1; i++) it.Advance();
- frame = it.frame();
+ 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);
- Handle<Object> arguments;
- for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
- if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
- if (arguments.is_null()) {
- // FunctionGetArguments can't throw an exception, so cast away the
- // doubt with an assert.
- arguments = Handle<Object>(
- Accessors::FunctionGetArguments(*function,
- NULL)->ToObjectUnchecked());
- ASSERT(*arguments != isolate->heap()->null_value());
- ASSERT(*arguments != isolate->heap()->undefined_value());
- }
- frame->SetExpression(i, *arguments);
- }
- }
+ MaterializeArgumentsObjectInFrame(isolate, frame);
if (type == Deoptimizer::EAGER) {
RUNTIME_ASSERT(function->IsOptimized());
}
-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
__ 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.
}
+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);
V(ForInCacheArray) \
V(CheckMapValue) \
V(LoadFieldByIndex) \
- V(DateField)
+ V(DateField) \
+ V(WrapReceiver)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
};
+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,
// 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);