Skip to content

Commit

Permalink
Inline functions that use arguments object in f.apply(o, arguments) p…
Browse files Browse the repository at this point in the history
…attern.

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: https://v8.googlecode.com/svn/branches/bleeding_edge@11008 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
  • Loading branch information
vegorov@chromium.org committed Mar 12, 2012
1 parent 0b87632 commit f7a04e6
Show file tree
Hide file tree
Showing 16 changed files with 284 additions and 75 deletions.
8 changes: 8 additions & 0 deletions src/arm/lithium-arm.cc
Expand Up @@ -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);
Expand Down
17 changes: 16 additions & 1 deletion src/arm/lithium-arm.h
Expand Up @@ -178,7 +178,8 @@ class LCodeGen;
V(ForInCacheArray) \
V(CheckMapValue) \
V(LoadFieldByIndex) \
V(DateField)
V(DateField) \
V(WrapReceiver)


#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
Expand Down Expand Up @@ -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,
Expand Down
19 changes: 13 additions & 6 deletions src/arm/lithium-codegen-arm.cc
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
1 change: 0 additions & 1 deletion src/deoptimizer.cc
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/flag-definitions.h
Expand Up @@ -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,
Expand Down
9 changes: 9 additions & 0 deletions src/hydrogen-instructions.cc
Expand Up @@ -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);
}
Expand Down
24 changes: 23 additions & 1 deletion src/hydrogen-instructions.h
Expand Up @@ -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) \
Expand Down Expand Up @@ -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,
Expand Down
103 changes: 82 additions & 21 deletions src/hydrogen.cc
Expand Up @@ -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());
}
}

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
}


Expand Down
18 changes: 12 additions & 6 deletions src/ia32/lithium-codegen-ia32.cc
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
14 changes: 11 additions & 3 deletions src/ia32/lithium-ia32.cc
Expand Up @@ -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);
}

Expand Down

0 comments on commit f7a04e6

Please sign in to comment.