Revision: 11274
Author: [email protected]
Date: Wed Apr 11 06:40:55 2012
Log: Reland arguments access support for inlined functions
(r11109,r11118).
When pushing arguments use correct initial values instead of fetching them
from the environment which can be modified.
[email protected]
TEST=test/mjsunit/compiler/inline-arguments.js
Review URL: https://chromiumcodereview.appspot.com/10033028
http://code.google.com/p/v8/source/detail?r=11274
Modified:
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.h
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/hydrogen-instructions.cc
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/hydrogen.h
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.h
/branches/bleeding_edge/src/mips/lithium-codegen-mips.cc
/branches/bleeding_edge/src/mips/lithium-mips.cc
/branches/bleeding_edge/src/mips/lithium-mips.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.h
/branches/bleeding_edge/test/mjsunit/compiler/inline-arguments.js
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Fri Mar 30 06:22:39 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Wed Apr 11 06:40:55 2012
@@ -2271,8 +2271,8 @@
undefined,
instr->call_kind(),
instr->is_construct());
- if (instr->arguments() != NULL) {
- inner->Bind(instr->arguments(), graph()->GetArgumentsObject());
+ if (instr->arguments_var() != NULL) {
+ inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
@@ -2281,10 +2281,21 @@
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+ LInstruction* pop = NULL;
+
+ HEnvironment* env = current_block_->last_environment();
+
+ if (instr->arguments_pushed()) {
+ int argument_count = env->arguments_environment()->parameter_count();
+ pop = new(zone()) LDrop(argument_count);
+ argument_count_ -= argument_count;
+ }
+
HEnvironment* outer = current_block_->last_environment()->
DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
- return NULL;
+
+ return pop;
}
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h Fri Mar 23 09:37:54 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.h Wed Apr 11 06:40:55 2012
@@ -179,7 +179,8 @@
V(CheckMapValue) \
V(LoadFieldByIndex) \
V(DateField) \
- V(WrapReceiver)
+ V(WrapReceiver) \
+ V(Drop)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
@@ -534,9 +535,8 @@
class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
public:
- LArgumentsElements() { }
-
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+ DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
};
@@ -1378,6 +1378,19 @@
};
+class LDrop: public LTemplateInstruction<0, 0, 0> {
+ public:
+ explicit LDrop(int count) : count_(count) { }
+
+ int count() const { return count_; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+ int count_;
+};
+
+
class LThisFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Thu Apr 5
08:36:31 2012
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Wed Apr 11
06:40:55 2012
@@ -2764,16 +2764,20 @@
Register scratch = scratch0();
Register result = ToRegister(instr->result());
- // Check if the calling frame is an arguments adaptor frame.
- Label done, adapted;
- __ ldr(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ ldr(result, MemOperand(scratch,
StandardFrameConstants::kContextOffset));
- __ cmp(result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
-
- // Result is the frame pointer for the frame if not adapted and for the
real
- // frame below the adaptor frame if adapted.
- __ mov(result, fp, LeaveCC, ne);
- __ mov(result, scratch, LeaveCC, eq);
+ if (instr->hydrogen()->from_inlined()) {
+ __ sub(result, sp, Operand(2 * kPointerSize));
+ } else {
+ // Check if the calling frame is an arguments adaptor frame.
+ Label done, adapted;
+ __ ldr(scratch, MemOperand(fp,
StandardFrameConstants::kCallerFPOffset));
+ __ ldr(result, MemOperand(scratch,
StandardFrameConstants::kContextOffset));
+ __ cmp(result, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+
+ // Result is the frame pointer for the frame if not adapted and for
the real
+ // frame below the adaptor frame if adapted.
+ __ mov(result, fp, LeaveCC, ne);
+ __ mov(result, scratch, LeaveCC, eq);
+ }
}
@@ -2905,6 +2909,11 @@
__ push(argument_reg);
}
}
+
+
+void LCodeGen::DoDrop(LDrop* instr) {
+ __ Drop(instr->count());
+}
void LCodeGen::DoThisFunction(LThisFunction* instr) {
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.cc Wed Apr 11
03:56:16 2012
+++ /branches/bleeding_edge/src/hydrogen-instructions.cc Wed Apr 11
06:40:55 2012
@@ -600,6 +600,9 @@
SetBlock(block);
previous->next_ = this;
if (next != NULL) next->previous_ = this;
+ if (block->last() == previous) {
+ block->set_last(this);
+ }
}
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Wed Apr 11 03:56:16
2012
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Wed Apr 11 06:40:55
2012
@@ -1381,13 +1381,15 @@
FunctionLiteral* function,
CallKind call_kind,
bool is_construct,
- Variable* arguments)
+ Variable* arguments_var,
+ ZoneList<HValue*>* arguments_values)
: closure_(closure),
arguments_count_(arguments_count),
function_(function),
call_kind_(call_kind),
is_construct_(is_construct),
- arguments_(arguments) {
+ arguments_var_(arguments_var),
+ arguments_values_(arguments_values) {
}
virtual void PrintDataTo(StringStream* stream);
@@ -1402,7 +1404,8 @@
return Representation::None();
}
- Variable* arguments() { return arguments_; }
+ Variable* arguments_var() { return arguments_var_; }
+ ZoneList<HValue*>* arguments_values() { return arguments_values_; }
DECLARE_CONCRETE_INSTRUCTION(EnterInlined)
@@ -1412,19 +1415,28 @@
FunctionLiteral* function_;
CallKind call_kind_;
bool is_construct_;
- Variable* arguments_;
+ Variable* arguments_var_;
+ ZoneList<HValue*>* arguments_values_;
};
class HLeaveInlined: public HTemplateInstruction<0> {
public:
- HLeaveInlined() {}
+ explicit HLeaveInlined(bool arguments_pushed)
+ : arguments_pushed_(arguments_pushed) { }
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
+
+ bool arguments_pushed() {
+ return arguments_pushed_;
+ }
DECLARE_CONCRETE_INSTRUCTION(LeaveInlined)
+
+ private:
+ bool arguments_pushed_;
};
@@ -2604,7 +2616,7 @@
class HArgumentsElements: public HTemplateInstruction<0> {
public:
- HArgumentsElements() {
+ explicit HArgumentsElements(bool from_inlined) :
from_inlined_(from_inlined) {
// The value produced by this instruction is a pointer into the stack
// that looks as if it was a smi because of alignment.
set_representation(Representation::Tagged());
@@ -2616,9 +2628,13 @@
virtual Representation RequiredInputRepresentation(int index) {
return Representation::None();
}
+
+ bool from_inlined() const { return from_inlined_; }
protected:
virtual bool DataEquals(HValue* other) { return true; }
+
+ bool from_inlined_;
};
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Wed Apr 11 03:56:16 2012
+++ /branches/bleeding_edge/src/hydrogen.cc Wed Apr 11 06:40:55 2012
@@ -113,7 +113,6 @@
first_ = last_ = entry;
}
instr->InsertAfter(last_);
- last_ = instr;
}
@@ -165,11 +164,15 @@
}
-void HBasicBlock::Goto(HBasicBlock* block, bool drop_extra) {
+void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) {
+ bool drop_extra = state != NULL && state->drop_extra();
+ bool arguments_pushed = state != NULL && state->arguments_pushed();
+
if (block->IsInlineReturnTarget()) {
- AddInstruction(new(zone()) HLeaveInlined);
+ AddInstruction(new(zone()) HLeaveInlined(arguments_pushed));
last_environment_ = last_environment()->DiscardInlined(drop_extra);
}
+
AddSimulate(AstNode::kNoNumber);
HGoto* instr = new(zone()) HGoto(block);
Finish(instr);
@@ -178,10 +181,13 @@
void HBasicBlock::AddLeaveInlined(HValue* return_value,
HBasicBlock* target,
- bool drop_extra) {
+ FunctionState* state) {
+ bool drop_extra = state != NULL && state->drop_extra();
+ bool arguments_pushed = state != NULL && state->arguments_pushed();
+
ASSERT(target->IsInlineReturnTarget());
ASSERT(return_value != NULL);
- AddInstruction(new(zone()) HLeaveInlined);
+ AddInstruction(new(zone()) HLeaveInlined(arguments_pushed));
last_environment_ = last_environment()->DiscardInlined(drop_extra);
last_environment()->Push(return_value);
AddSimulate(AstNode::kNoNumber);
@@ -2236,6 +2242,8 @@
return_handling_(return_handling),
function_return_(NULL),
test_context_(NULL),
+ entry_(NULL),
+ arguments_elements_(NULL),
outer_(owner->function_state()) {
if (outer_ != NULL) {
// State for an inline function.
@@ -2395,8 +2403,8 @@
instr->SetSuccessorAt(0, empty_true);
instr->SetSuccessorAt(1, empty_false);
owner()->current_block()->Finish(instr);
- empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
- empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
+ empty_true->Goto(if_true(), owner()->function_state());
+ empty_false->Goto(if_false(), owner()->function_state());
owner()->set_current_block(NULL);
}
@@ -2417,8 +2425,8 @@
HBranch* test = new(zone()) HBranch(value, empty_true, empty_false,
expected);
builder->current_block()->Finish(test);
- empty_true->Goto(if_true(), owner()->function_state()->drop_extra());
- empty_false->Goto(if_false(), owner()->function_state()->drop_extra());
+ empty_true->Goto(if_true(), owner()->function_state());
+ empty_false->Goto(if_false(), owner()->function_state());
builder->set_current_block(NULL);
}
@@ -2913,10 +2921,10 @@
if (context->IsTest()) {
TestContext* test = TestContext::cast(context);
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(test->if_true(),
function_state()->drop_extra());
+ current_block()->Goto(test->if_true(), function_state());
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(function_return(),
function_state()->drop_extra());
+ current_block()->Goto(function_return(), function_state());
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
@@ -2933,10 +2941,10 @@
current_block()->Finish(typecheck);
if_spec_object->AddLeaveInlined(return_value,
function_return(),
- function_state()->drop_extra());
+ function_state());
not_spec_object->AddLeaveInlined(receiver,
function_return(),
- function_state()->drop_extra());
+ function_state());
}
} else {
// Return from an inlined function, visit the subexpression in the
@@ -2948,14 +2956,14 @@
test->if_false());
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(function_return(),
function_state()->drop_extra());
+ current_block()->Goto(function_return(), function_state());
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
HValue* return_value = Pop();
current_block()->AddLeaveInlined(return_value,
function_return(),
- function_state()->drop_extra());
+ function_state());
}
}
set_current_block(NULL);
@@ -5041,6 +5049,34 @@
value,
function_strict_mode_flag());
}
+
+
+void HGraphBuilder::EnsureArgumentsArePushedForAccess() {
+ // Outermost function already has arguments on the stack.
+ if (function_state()->outer() == NULL) return;
+
+ if (function_state()->arguments_pushed()) return;
+
+ // Push arguments when entering inlined function.
+ HEnterInlined* entry = function_state()->entry();
+
+ ZoneList<HValue*>* arguments_values = entry->arguments_values();
+
+ HInstruction* insert_after = entry;
+ for (int i = 0; i < arguments_values->length(); i++) {
+ HValue* argument = arguments_values->at(i);
+ HInstruction* push_argument = new(zone()) HPushArgument(argument);
+ push_argument->InsertAfter(insert_after);
+ insert_after = push_argument;
+ }
+
+ HArgumentsElements* arguments_elements =
+ new(zone()) HArgumentsElements(true);
+ arguments_elements->ClearFlag(HValue::kUseGVN);
+ arguments_elements->InsertAfter(insert_after);
+ function_state()->set_arguments_elements(arguments_elements);
+}
+
bool HGraphBuilder::TryArgumentsAccess(Property* expr) {
VariableProxy* proxy = expr->obj()->AsVariableProxy();
@@ -5049,32 +5085,52 @@
if
(!environment()->Lookup(proxy->var())->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("arguments access in inlined function");
- return true;
- }
HInstruction* result = NULL;
if (expr->key()->IsPropertyName()) {
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
if (!name->IsEqualTo(CStrVector("length"))) return false;
- HInstruction* elements = AddInstruction(new(zone())
HArgumentsElements);
- result = new(zone()) HArgumentsLength(elements);
+
+ if (function_state()->outer() == NULL) {
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
+ result = new(zone()) HArgumentsLength(elements);
+ } else {
+ // Number of arguments without receiver.
+ int argument_count = environment()->
+ arguments_environment()->parameter_count() - 1;
+ result = new(zone()) HConstant(
+ Handle<Object>(Smi::FromInt(argument_count)),
+ Representation::Integer32());
+ }
} else {
Push(graph()->GetArgumentsObject());
VisitForValue(expr->key());
if (HasStackOverflow() || current_block() == NULL) return true;
HValue* key = Pop();
Drop(1); // Arguments object.
- HInstruction* elements = AddInstruction(new(zone())
HArgumentsElements);
- HInstruction* length = AddInstruction(
- new(zone()) HArgumentsLength(elements));
- HInstruction* checked_key =
- AddInstruction(new(zone()) HBoundsCheck(key, length));
- result = new(zone()) HAccessArgumentsAt(elements, length, checked_key);
+ if (function_state()->outer() == NULL) {
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
+ HInstruction* length = AddInstruction(
+ new(zone()) HArgumentsLength(elements));
+ HInstruction* checked_key =
+ AddInstruction(new(zone()) HBoundsCheck(key, length));
+ result = new(zone()) HAccessArgumentsAt(elements, length,
checked_key);
+ } else {
+ EnsureArgumentsArePushedForAccess();
+
+ // Number of arguments without receiver.
+ HInstruction* elements = function_state()->arguments_elements();
+ int argument_count = environment()->
+ arguments_environment()->parameter_count() - 1;
+ HInstruction* length = AddInstruction(new(zone()) HConstant(
+ Handle<Object>(Smi::FromInt(argument_count)),
+ Representation::Integer32()));
+ HInstruction* checked_key =
+ AddInstruction(new(zone()) HBoundsCheck(key, length));
+ result = new(zone()) HAccessArgumentsAt(elements, length,
checked_key);
+ }
}
ast_context()->ReturnInstruction(result, expr->id());
return true;
@@ -5481,20 +5537,42 @@
AddInstruction(context);
inner_env->BindContext(context);
#endif
+
AddSimulate(return_id);
current_block()->UpdateEnvironment(inner_env);
- AddInstruction(new(zone()) HEnterInlined(target,
- arguments->length(),
- function,
- call_kind,
-
function_state()->is_construct(),
-
function->scope()->arguments()));
+
+ ZoneList<HValue*>* arguments_values = NULL;
+
+ // If the function uses arguments copy current arguments values
+ // to use them for materialization.
+ if (function->scope()->arguments() != NULL) {
+ HEnvironment* arguments_env = inner_env->arguments_environment();
+ int arguments_count = arguments_env->parameter_count();
+ arguments_values = new(zone()) ZoneList<HValue*>(arguments_count);
+ for (int i = 0; i < arguments_count; i++) {
+ arguments_values->Add(arguments_env->Lookup(i));
+ }
+ }
+
+ HEnterInlined* enter_inlined =
+ new(zone()) HEnterInlined(target,
+ arguments->length(),
+ function,
+ call_kind,
+ function_state()->is_construct(),
+ function->scope()->arguments(),
+ arguments_values);
+ function_state()->set_entry(enter_inlined);
+ AddInstruction(enter_inlined);
+
// If the function uses arguments object create and bind one.
if (function->scope()->arguments() != NULL) {
ASSERT(function->scope()->arguments()->IsStackAllocated());
- environment()->Bind(function->scope()->arguments(),
- graph()->GetArgumentsObject());
- }
+ inner_env->Bind(function->scope()->arguments(),
+ graph()->GetArgumentsObject());
+ }
+
+
VisitDeclarations(target_info.scope()->declarations());
VisitStatements(function->body());
if (HasStackOverflow()) {
@@ -5523,17 +5601,17 @@
: undefined;
current_block()->AddLeaveInlined(return_value,
function_return(),
- function_state()->drop_extra());
+ function_state());
} else if (call_context()->IsEffect()) {
ASSERT(function_return() != NULL);
- current_block()->Goto(function_return(),
function_state()->drop_extra());
+ current_block()->Goto(function_return(), function_state());
} else {
ASSERT(call_context()->IsTest());
ASSERT(inlined_test_context() != NULL);
HBasicBlock* target = function_state()->is_construct()
? inlined_test_context()->if_true()
: inlined_test_context()->if_false();
- current_block()->Goto(target, function_state()->drop_extra());
+ current_block()->Goto(target, function_state());
}
}
@@ -5551,12 +5629,12 @@
if (if_true->HasPredecessor()) {
if_true->SetJoinId(ast_id);
HBasicBlock* true_target =
TestContext::cast(ast_context())->if_true();
- if_true->Goto(true_target, function_state()->drop_extra());
+ if_true->Goto(true_target, function_state());
}
if (if_false->HasPredecessor()) {
if_false->SetJoinId(ast_id);
HBasicBlock* false_target =
TestContext::cast(ast_context())->if_false();
- if_false->Goto(false_target, function_state()->drop_extra());
+ if_false->Goto(false_target, function_state());
}
set_current_block(NULL);
return true;
@@ -5865,7 +5943,8 @@
HValue* receiver = Pop();
if (function_state()->outer() == NULL) {
- HInstruction* elements = AddInstruction(new(zone())
HArgumentsElements);
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
HInstruction* length =
AddInstruction(new(zone()) HArgumentsLength(elements));
HValue* wrapped_receiver =
@@ -7335,7 +7414,8 @@
// function is blacklisted by AstNode::IsInlineable.
ASSERT(function_state()->outer() == NULL);
ASSERT(call->arguments()->length() == 0);
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
HArgumentsLength* result = new(zone()) HArgumentsLength(elements);
return ast_context()->ReturnInstruction(result, call->id());
}
@@ -7349,7 +7429,8 @@
ASSERT(call->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
HValue* index = Pop();
- HInstruction* elements = AddInstruction(new(zone()) HArgumentsElements);
+ HInstruction* elements = AddInstruction(
+ new(zone()) HArgumentsElements(false));
HInstruction* length = AddInstruction(new(zone())
HArgumentsLength(elements));
HAccessArgumentsAt* result =
new(zone()) HAccessArgumentsAt(elements, length, index);
=======================================
--- /branches/bleeding_edge/src/hydrogen.h Wed Apr 11 04:45:14 2012
+++ /branches/bleeding_edge/src/hydrogen.h Wed Apr 11 06:40:55 2012
@@ -42,6 +42,7 @@
// Forward declarations.
class BitVector;
+class FunctionState;
class HEnvironment;
class HGraph;
class HLoopInformation;
@@ -121,7 +122,7 @@
void Finish(HControlInstruction* last);
void FinishExit(HControlInstruction* instruction);
- void Goto(HBasicBlock* block, bool drop_extra = false);
+ void Goto(HBasicBlock* block, FunctionState* state = NULL);
int PredecessorIndexOf(HBasicBlock* predecessor) const;
void AddSimulate(int ast_id) { AddInstruction(CreateSimulate(ast_id)); }
@@ -136,7 +137,7 @@
// instruction and updating the bailout environment.
void AddLeaveInlined(HValue* return_value,
HBasicBlock* target,
- bool drop_extra = false);
+ FunctionState* state = NULL);
// If a target block is tagged as an inline function return, all
// predecessors should contain the inlined exit sequence:
@@ -714,6 +715,16 @@
}
FunctionState* outer() { return outer_; }
+
+ HEnterInlined* entry() { return entry_; }
+ void set_entry(HEnterInlined* entry) { entry_ = entry; }
+
+ HArgumentsElements* arguments_elements() { return arguments_elements_; }
+ void set_arguments_elements(HArgumentsElements* arguments_elements) {
+ arguments_elements_ = arguments_elements;
+ }
+
+ bool arguments_pushed() { return arguments_elements() != NULL; }
private:
HGraphBuilder* owner_;
@@ -741,6 +752,12 @@
// return blocks. NULL in all other cases.
TestContext* test_context_;
+ // When inlining HEnterInlined instruction corresponding to the function
+ // entry.
+ HEnterInlined* entry_;
+
+ HArgumentsElements* arguments_elements_;
+
FunctionState* outer_;
};
@@ -994,6 +1011,7 @@
LookupResult* lookup,
bool is_store);
+ void EnsureArgumentsArePushedForAccess();
bool TryArgumentsAccess(Property* expr);
// Try to optimize fun.apply(receiver, arguments) pattern.
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Thu Apr 5
08:36:31 2012
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Apr 11
06:40:55 2012
@@ -2543,25 +2543,29 @@
void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
Register result = ToRegister(instr->result());
- // Check for arguments adapter frame.
- Label done, adapted;
- __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
- __ mov(result, Operand(result, StandardFrameConstants::kContextOffset));
- __ cmp(Operand(result),
- Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
- __ j(equal, &adapted, Label::kNear);
-
- // No arguments adaptor frame.
- __ mov(result, Operand(ebp));
- __ jmp(&done, Label::kNear);
-
- // Arguments adaptor frame present.
- __ bind(&adapted);
- __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
-
- // Result is the frame pointer for the frame if not adapted and for the
real
- // frame below the adaptor frame if adapted.
- __ bind(&done);
+ if (instr->hydrogen()->from_inlined()) {
+ __ lea(result, Operand(esp, -2 * kPointerSize));
+ } else {
+ // Check for arguments adapter frame.
+ Label done, adapted;
+ __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
+ __ mov(result, Operand(result,
StandardFrameConstants::kContextOffset));
+ __ cmp(Operand(result),
+ Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+ __ j(equal, &adapted, Label::kNear);
+
+ // No arguments adaptor frame.
+ __ mov(result, Operand(ebp));
+ __ jmp(&done, Label::kNear);
+
+ // Arguments adaptor frame present.
+ __ bind(&adapted);
+ __ mov(result, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
+
+ // Result is the frame pointer for the frame if not adapted and for
the real
+ // frame below the adaptor frame if adapted.
+ __ bind(&done);
+ }
}
@@ -2681,6 +2685,11 @@
LOperand* argument = instr->InputAt(0);
EmitPushTaggedOperand(argument);
}
+
+
+void LCodeGen::DoDrop(LDrop* instr) {
+ __ Drop(instr->count());
+}
void LCodeGen::DoThisFunction(LThisFunction* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Fri Mar 30 06:22:39
2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Wed Apr 11 06:40:55
2012
@@ -2380,8 +2380,8 @@
undefined,
instr->call_kind(),
instr->is_construct());
- if (instr->arguments() != NULL) {
- inner->Bind(instr->arguments(), graph()->GetArgumentsObject());
+ if (instr->arguments_var() != NULL) {
+ inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
@@ -2390,10 +2390,20 @@
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+ LInstruction* pop = NULL;
+
+ HEnvironment* env = current_block_->last_environment();
+
+ if (instr->arguments_pushed()) {
+ int argument_count = env->arguments_environment()->parameter_count();
+ pop = new(zone()) LDrop(argument_count);
+ argument_count_ -= argument_count;
+ }
+
HEnvironment* outer = current_block_->last_environment()->
DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
- return NULL;
+ return pop;
}
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h Fri Mar 23 09:37:54 2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h Wed Apr 11 06:40:55 2012
@@ -174,7 +174,8 @@
V(CheckMapValue) \
V(LoadFieldByIndex) \
V(DateField) \
- V(WrapReceiver)
+ V(WrapReceiver) \
+ V(Drop)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
@@ -525,9 +526,8 @@
class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
public:
- LArgumentsElements() { }
-
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+ DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
};
@@ -1401,6 +1401,19 @@
};
+class LDrop: public LTemplateInstruction<0, 0, 0> {
+ public:
+ explicit LDrop(int count) : count_(count) { }
+
+ int count() const { return count_; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+ int count_;
+};
+
+
class LThisFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
=======================================
--- /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Thu Apr 5
08:36:31 2012
+++ /branches/bleeding_edge/src/mips/lithium-codegen-mips.cc Wed Apr 11
06:40:55 2012
@@ -2651,16 +2651,20 @@
Register temp = scratch1();
Register result = ToRegister(instr->result());
- // Check if the calling frame is an arguments adaptor frame.
- Label done, adapted;
- __ lw(scratch, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
- __ lw(result, MemOperand(scratch,
StandardFrameConstants::kContextOffset));
- __ Xor(temp, result,
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
-
- // Result is the frame pointer for the frame if not adapted and for the
real
- // frame below the adaptor frame if adapted.
- __ Movn(result, fp, temp); // Move only if temp is not equal to zero
(ne).
- __ Movz(result, scratch, temp); // Move only if temp is equal to zero
(eq).
+ if (instr->hydrogen()->from_inlined()) {
+ __ Subu(result, sp, 2 * kPointerSize);
+ } else {
+ // Check if the calling frame is an arguments adaptor frame.
+ Label done, adapted;
+ __ lw(scratch, MemOperand(fp,
StandardFrameConstants::kCallerFPOffset));
+ __ lw(result, MemOperand(scratch,
StandardFrameConstants::kContextOffset));
+ __ Xor(temp, result,
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
+
+ // Result is the frame pointer for the frame if not adapted and for
the real
+ // frame below the adaptor frame if adapted.
+ __ Movn(result, fp, temp); // Move only if temp is not equal to zero
(ne).
+ __ Movz(result, scratch, temp); // Move only if temp is equal to zero
(eq).
+ }
}
@@ -2791,6 +2795,11 @@
__ push(argument_reg);
}
}
+
+
+void LCodeGen::DoDrop(LDrop* instr) {
+ __ Drop(instr->count());
+}
void LCodeGen::DoThisFunction(LThisFunction* instr) {
=======================================
--- /branches/bleeding_edge/src/mips/lithium-mips.cc Fri Mar 30 06:22:39
2012
+++ /branches/bleeding_edge/src/mips/lithium-mips.cc Wed Apr 11 06:40:55
2012
@@ -2277,8 +2277,8 @@
undefined,
instr->call_kind(),
instr->is_construct());
- if (instr->arguments() != NULL) {
- inner->Bind(instr->arguments(), graph()->GetArgumentsObject());
+ if (instr->arguments_var() != NULL) {
+ inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
@@ -2287,10 +2287,21 @@
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+ LInstruction* pop = NULL;
+
+ HEnvironment* env = current_block_->last_environment();
+
+ if (instr->arguments_pushed()) {
+ int argument_count = env->arguments_environment()->parameter_count();
+ pop = new(zone()) LDrop(argument_count);
+ argument_count_ -= argument_count;
+ }
+
HEnvironment* outer = current_block_->last_environment()->
DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
- return NULL;
+
+ return pop;
}
=======================================
--- /branches/bleeding_edge/src/mips/lithium-mips.h Fri Mar 23 09:37:54 2012
+++ /branches/bleeding_edge/src/mips/lithium-mips.h Wed Apr 11 06:40:55 2012
@@ -179,7 +179,8 @@
V(CheckMapValue) \
V(LoadFieldByIndex) \
V(DateField) \
- V(WrapReceiver)
+ V(WrapReceiver) \
+ V(Drop)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
virtual Opcode opcode() const { return LInstruction::k##type; } \
@@ -533,9 +534,8 @@
class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
public:
- LArgumentsElements() { }
-
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+ DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
};
@@ -1358,6 +1358,19 @@
};
+class LDrop: public LTemplateInstruction<0, 0, 0> {
+ public:
+ explicit LDrop(int count) : count_(count) { }
+
+ int count() const { return count_; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+ int count_;
+};
+
+
class LThisFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
=======================================
--- /branches/bleeding_edge/src/runtime.cc Tue Apr 3 09:54:28 2012
+++ /branches/bleeding_edge/src/runtime.cc Wed Apr 11 06:40:55 2012
@@ -8126,6 +8126,14 @@
ASSERT(*arguments != isolate->heap()->undefined_value());
}
frame->SetExpression(i, *arguments);
+ if (FLAG_trace_deopt) {
+ PrintF("Materializing arguments object for frame %p - %p: %p ",
+ reinterpret_cast<void*>(frame->sp()),
+ reinterpret_cast<void*>(frame->fp()),
+ reinterpret_cast<void*>(*arguments));
+ arguments->ShortPrint();
+ PrintF("\n");
+ }
}
}
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Apr 5
08:36:31 2012
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Apr 11
06:40:55 2012
@@ -2497,24 +2497,28 @@
void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
Register result = ToRegister(instr->result());
- // Check for arguments adapter frame.
- Label done, adapted;
- __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
- __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
- Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
- __ j(equal, &adapted, Label::kNear);
-
- // No arguments adaptor frame.
- __ movq(result, rbp);
- __ jmp(&done, Label::kNear);
-
- // Arguments adaptor frame present.
- __ bind(&adapted);
- __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
-
- // Result is the frame pointer for the frame if not adapted and for the
real
- // frame below the adaptor frame if adapted.
- __ bind(&done);
+ if (instr->hydrogen()->from_inlined()) {
+ __ lea(result, Operand(rsp, -2 * kPointerSize));
+ } else {
+ // Check for arguments adapter frame.
+ Label done, adapted;
+ __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
+ __ Cmp(Operand(result, StandardFrameConstants::kContextOffset),
+ Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+ __ j(equal, &adapted, Label::kNear);
+
+ // No arguments adaptor frame.
+ __ movq(result, rbp);
+ __ jmp(&done, Label::kNear);
+
+ // Arguments adaptor frame present.
+ __ bind(&adapted);
+ __ movq(result, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
+
+ // Result is the frame pointer for the frame if not adapted and for
the real
+ // frame below the adaptor frame if adapted.
+ __ bind(&done);
+ }
}
@@ -2638,6 +2642,11 @@
LOperand* argument = instr->InputAt(0);
EmitPushTaggedOperand(argument);
}
+
+
+void LCodeGen::DoDrop(LDrop* instr) {
+ __ Drop(instr->count());
+}
void LCodeGen::DoThisFunction(LThisFunction* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Fri Mar 30 06:22:39 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Wed Apr 11 06:40:55 2012
@@ -2270,8 +2270,8 @@
undefined,
instr->call_kind(),
instr->is_construct());
- if (instr->arguments() != NULL) {
- inner->Bind(instr->arguments(), graph()->GetArgumentsObject());
+ if (instr->arguments_var() != NULL) {
+ inner->Bind(instr->arguments_var(), graph()->GetArgumentsObject());
}
current_block_->UpdateEnvironment(inner);
chunk_->AddInlinedClosure(instr->closure());
@@ -2280,10 +2280,21 @@
LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+ LInstruction* pop = NULL;
+
+ HEnvironment* env = current_block_->last_environment();
+
+ if (instr->arguments_pushed()) {
+ int argument_count = env->arguments_environment()->parameter_count();
+ pop = new(zone()) LDrop(argument_count);
+ argument_count_ -= argument_count;
+ }
+
HEnvironment* outer = current_block_->last_environment()->
DiscardInlined(false);
current_block_->UpdateEnvironment(outer);
- return NULL;
+
+ return pop;
}
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h Fri Mar 23 09:37:54 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.h Wed Apr 11 06:40:55 2012
@@ -179,7 +179,8 @@
V(CheckMapValue) \
V(LoadFieldByIndex) \
V(DateField) \
- V(WrapReceiver)
+ V(WrapReceiver) \
+ V(Drop)
#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic) \
@@ -535,9 +536,8 @@
class LArgumentsElements: public LTemplateInstruction<1, 0, 0> {
public:
- LArgumentsElements() { }
-
DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+ DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
};
@@ -1358,6 +1358,19 @@
};
+class LDrop: public LTemplateInstruction<0, 0, 0> {
+ public:
+ explicit LDrop(int count) : count_(count) { }
+
+ int count() const { return count_; }
+
+ DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+ int count_;
+};
+
+
class LThisFunction: public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
=======================================
--- /branches/bleeding_edge/test/mjsunit/compiler/inline-arguments.js Fri
Mar 23 08:39:34 2012
+++ /branches/bleeding_edge/test/mjsunit/compiler/inline-arguments.js Wed
Apr 11 06:40:55 2012
@@ -113,3 +113,70 @@
%OptimizeFunctionOnNextCall(test_adaptation);
test_adaptation();
})();
+
+// Test arguments access from the inlined function.
+function uninlinable(v) {
+ assertEquals(0, v);
+ try { } catch (e) { }
+ return 0;
+}
+
+function toarr_inner() {
+ var a = arguments;
+ var marker = a[0];
+ uninlinable(uninlinable(0, 0), marker.x);
+
+ var r = new Array();
+ for (var i = a.length - 1; i >= 1; i--) {
+ r.push(a[i]);
+ }
+
+ return r;
+}
+
+function toarr1(marker, a, b, c) {
+ return toarr_inner(marker, a / 2, b / 2, c / 2);
+}
+
+function toarr2(marker, a, b, c) {
+ var x = 0;
+ return uninlinable(uninlinable(0, 0),
+ x = toarr_inner(marker, a / 2, b / 2, c / 2)), x;
+}
+
+function test_toarr(toarr) {
+ var marker = { x: 0 };
+ assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
+ assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
+ %OptimizeFunctionOnNextCall(toarr);
+ assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
+ delete marker.x;
+ assertArrayEquals([3, 2, 1], toarr(marker, 2, 4, 6));
+}
+
+test_toarr(toarr1);
+test_toarr(toarr2);
+
+// Test that arguments access from inlined function uses correct values.
+(function () {
+ function inner(x, y) {
+ "use strict";
+ x = 10;
+ y = 20;
+ for (var i = 0; i < 1; i++) {
+ for (var j = 1; j <= arguments.length; j++) {
+ return arguments[arguments.length - j];
+ }
+ }
+ }
+
+ function outer(x, y) {
+ return inner(x, y);
+ }
+
+ assertEquals(2, outer(1, 2));
+ assertEquals(2, outer(1, 2));
+ assertEquals(2, outer(1, 2));
+ %OptimizeFunctionOnNextCall(outer);
+ assertEquals(2, outer(1, 2));
+})();
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev