Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(749)

Unified Diff: src/hydrogen.cc

Issue 10836133: Inline simple setter calls. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Made VisitReturnStatement and TryInline more similar. Simplified AddLeaveInlined. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/hydrogen.cc
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 9727d91a58a3f9afbdc5aa11c2b2c5ca1d6cf201..071d3a624a13cbc3d2d5654d2db1297792638327 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -166,7 +166,8 @@ void HBasicBlock::Finish(HControlInstruction* end) {
void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) {
- bool drop_extra = state != NULL && state->drop_extra();
+ bool drop_extra = state != NULL &&
+ state->return_handling() == DROP_EXTRA_ON_RETURN;
bool arguments_pushed = state != NULL && state->arguments_pushed();
if (block->IsInlineReturnTarget()) {
@@ -181,18 +182,15 @@ void HBasicBlock::Goto(HBasicBlock* block, FunctionState* state) {
void HBasicBlock::AddLeaveInlined(HValue* return_value,
- HBasicBlock* target,
FunctionState* state) {
- bool drop_extra = state != NULL && state->drop_extra();
- bool arguments_pushed = state != NULL && state->arguments_pushed();
-
- ASSERT(target->IsInlineReturnTarget());
+ ASSERT(state->function_return()->IsInlineReturnTarget());
ASSERT(return_value != NULL);
- AddInstruction(new(zone()) HLeaveInlined(arguments_pushed));
- last_environment_ = last_environment()->DiscardInlined(drop_extra);
+ AddInstruction(new(zone()) HLeaveInlined(state->arguments_pushed()));
+ last_environment_ = last_environment()->DiscardInlined(
+ state->return_handling() == DROP_EXTRA_ON_RETURN);
last_environment()->Push(return_value);
AddSimulate(BailoutId::None());
- HGoto* instr = new(zone()) HGoto(target);
+ HGoto* instr = new(zone()) HGoto(state->function_return());
Finish(instr);
}
@@ -3828,23 +3826,24 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
+ FunctionState* state = function_state();
AstContext* context = call_context();
if (context == NULL) {
// Not an inlined return, so an actual one.
CHECK_ALIVE(VisitForValue(stmt->expression()));
HValue* result = environment()->Pop();
current_block()->FinishExit(new(zone()) HReturn(result));
- } else if (function_state()->is_construct()) {
- // Return from an inlined construct call. In a test context the return
- // value will always evaluate to true, in a value context the return value
- // needs to be a JSObject.
+ } else if (state->return_handling() == CONSTRUCT_CALL_RETURN) {
+ // Return from an inlined construct call. In a test context the return value
+ // will always evaluate to true, in a value context the return value needs
+ // to be a JSObject.
if (context->IsTest()) {
TestContext* test = TestContext::cast(context);
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(test->if_true(), function_state());
+ current_block()->Goto(test->if_true(), state);
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(function_return(), function_state());
+ current_block()->Goto(function_return(), state);
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
@@ -3859,31 +3858,34 @@ void HGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
typecheck->SetSuccessorAt(0, if_spec_object);
typecheck->SetSuccessorAt(1, not_spec_object);
current_block()->Finish(typecheck);
- if_spec_object->AddLeaveInlined(return_value,
- function_return(),
- function_state());
- not_spec_object->AddLeaveInlined(receiver,
- function_return(),
- function_state());
+ if_spec_object->AddLeaveInlined(return_value, state);
+ not_spec_object->AddLeaveInlined(receiver, state);
+ }
+ } else if (state->return_handling() == SETTER_CALL_RETURN) {
+ // Return from an inlined setter call. The returned value is never used, the
+ // value of an assignment is always the value of the RHS of the assignment.
+ CHECK_ALIVE(VisitForEffect(stmt->expression()));
+ if (context->IsTest()) {
+ context->ReturnValue(environment()->Lookup(1));
+ } else if (context->IsEffect()) {
+ current_block()->Goto(function_return(), state);
+ } else {
+ ASSERT(context->IsValue());
+ current_block()->AddLeaveInlined(environment()->Lookup(1), state);
}
} else {
- // Return from an inlined function, visit the subexpression in the
+ // Return from a normal inlined function. Visit the subexpression in the
// expression context of the call.
if (context->IsTest()) {
TestContext* test = TestContext::cast(context);
- VisitForControl(stmt->expression(),
- test->if_true(),
- test->if_false());
+ VisitForControl(stmt->expression(), test->if_true(), test->if_false());
} else if (context->IsEffect()) {
CHECK_ALIVE(VisitForEffect(stmt->expression()));
- current_block()->Goto(function_return(), function_state());
+ current_block()->Goto(function_return(), state);
} else {
ASSERT(context->IsValue());
CHECK_ALIVE(VisitForValue(stmt->expression()));
- HValue* return_value = Pop();
- current_block()->AddLeaveInlined(return_value,
- function_return(),
- function_state());
+ current_block()->AddLeaveInlined(Pop(), state);
}
}
set_current_block(NULL);
@@ -5230,8 +5232,15 @@ void HGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
Handle<AccessorPair> accessors;
Handle<JSObject> holder;
if (LookupAccessorPair(map, name, &accessors, &holder)) {
+ Handle<JSFunction> setter(JSFunction::cast(accessors->setter()));
+ AddCheckConstantFunction(holder, object, map, true);
+ if (FLAG_inline_accessors && TryInlineSetter(setter, expr, value)) {
+ return;
+ }
Drop(2);
- instr = BuildCallSetter(object, value, map, accessors, holder);
+ AddInstruction(new(zone()) HPushArgument(object));
+ AddInstruction(new(zone()) HPushArgument(value));
+ instr = new(zone()) HCallConstantFunction(setter, 2);
} else {
Drop(2);
CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object,
@@ -6630,7 +6639,7 @@ int HGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
bool HGraphBuilder::TryInline(CallKind call_kind,
Handle<JSFunction> target,
int arguments_count,
- HValue* receiver,
+ HValue* implicit_return_value,
BailoutId ast_id,
BailoutId return_id,
ReturnHandlingFlag return_handling) {
@@ -6795,7 +6804,7 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
function,
undefined,
call_kind,
- function_state()->is_construct());
+ function_state()->return_handling());
#ifdef V8_TARGET_ARCH_IA32
// IA32 only, overwrite the caller's context in the deoptimization
// environment with the correct one.
@@ -6830,7 +6839,7 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
arguments_count,
function,
call_kind,
- function_state()->is_construct(),
+ function_state()->return_handling(),
function->scope()->arguments(),
arguments_values);
function_state()->set_entry(enter_inlined);
@@ -6862,27 +6871,42 @@ bool HGraphBuilder::TryInline(CallKind call_kind,
TraceInline(target, caller, NULL);
if (current_block() != NULL) {
- // Add default return value (i.e. undefined for normals calls or the newly
- // allocated receiver for construct calls) if control can fall off the
- // body. In a test context, undefined is false and any JSObject is true.
- if (call_context()->IsValue()) {
- ASSERT(function_return() != NULL);
- HValue* return_value = function_state()->is_construct()
- ? receiver
- : undefined;
- current_block()->AddLeaveInlined(return_value,
- function_return(),
- function_state());
- } else if (call_context()->IsEffect()) {
- ASSERT(function_return() != NULL);
- current_block()->Goto(function_return(), function_state());
+ FunctionState* state = function_state();
+ if (state->return_handling() == CONSTRUCT_CALL_RETURN) {
+ // Falling from the end of an inlined construct call. In a test context
Michael Starzinger 2012/08/08 13:05:33 Hmm, how about "Falling off the end ..."?
Sven Panne 2012/08/08 14:15:20 Done.
+ // the return value will always evaluate to true, in a value context the
+ // return value is the newly allocated receiver.
+ if (call_context()->IsTest()) {
+ current_block()->Goto(inlined_test_context()->if_true(), state);
+ } else if (call_context()->IsEffect()) {
+ current_block()->Goto(function_return(), state);
+ } else {
+ ASSERT(call_context()->IsValue());
+ current_block()->AddLeaveInlined(implicit_return_value, state);
+ }
+ } else if (state->return_handling() == SETTER_CALL_RETURN) {
+ // Falling from the end of an inlined setter call. The returned value is
Michael Starzinger 2012/08/08 13:05:33 Likewise.
Sven Panne 2012/08/08 14:15:20 Done.
+ // never used, the value of an assignment is always the value of the RHS
+ // of the assignment.
+ if (call_context()->IsTest()) {
+ inlined_test_context()->ReturnValue(implicit_return_value);
+ } else if (call_context()->IsEffect()) {
+ current_block()->Goto(function_return(), state);
+ } else {
+ ASSERT(call_context()->IsValue());
+ current_block()->AddLeaveInlined(implicit_return_value, 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());
+ // Falling from the end of a normal inlined function. This basically means
Michael Starzinger 2012/08/08 13:05:33 Likewise.
Sven Panne 2012/08/08 14:15:20 Done.
+ // returning undefined.
+ if (call_context()->IsTest()) {
+ current_block()->Goto(inlined_test_context()->if_false(), state);
+ } else if (call_context()->IsEffect()) {
+ current_block()->Goto(function_return(), state);
+ } else {
+ ASSERT(call_context()->IsValue());
+ current_block()->AddLeaveInlined(undefined, state);
+ }
}
}
@@ -6961,6 +6985,19 @@ bool HGraphBuilder::TryInlineGetter(Handle<JSFunction> getter,
}
+bool HGraphBuilder::TryInlineSetter(Handle<JSFunction> setter,
+ Assignment* assignment,
+ HValue* implicit_return_value) {
+ return TryInline(CALL_AS_METHOD,
+ setter,
+ 1,
+ implicit_return_value,
+ assignment->id(),
+ assignment->AssignmentId(),
+ SETTER_CALL_RETURN);
+}
+
+
bool HGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, bool drop_extra) {
if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
@@ -8644,7 +8681,7 @@ void HGraphBuilder::GenerateIsConstructCall(CallRuntime* call) {
ASSERT(call->arguments()->length() == 0);
if (function_state()->outer() != NULL) {
// We are generating graph for inlined function.
- HValue* value = function_state()->is_construct()
+ HValue* value = function_state()->return_handling() == CONSTRUCT_CALL_RETURN
? graph()->GetConstantTrue()
: graph()->GetConstantFalse();
return ast_context()->ReturnValue(value);
@@ -9234,7 +9271,7 @@ HEnvironment* HEnvironment::CopyForInlining(
FunctionLiteral* function,
HConstant* undefined,
CallKind call_kind,
- bool is_construct) const {
+ ReturnHandlingFlag return_handling) const {
Michael Starzinger 2012/08/08 13:05:33 Since this flag is not only used to distinguish th
Sven Panne 2012/08/08 14:15:20 Done.
ASSERT(frame_type() == JS_FUNCTION);
// Outer environment is a copy of this one without the arguments.
@@ -9244,7 +9281,7 @@ HEnvironment* HEnvironment::CopyForInlining(
outer->Drop(arguments + 1); // Including receiver.
outer->ClearHistory();
- if (is_construct) {
+ if (return_handling == CONSTRUCT_CALL_RETURN) {
// Create artificial constructor stub environment. The receiver should
// actually be the constructor function, but we pass the newly allocated
// object instead, DoComputeConstructStubFrame() relies on that.
@@ -9268,7 +9305,8 @@ HEnvironment* HEnvironment::CopyForInlining(
// builtin function, pass undefined as the receiver for function
// calls (instead of the global receiver).
if ((target->shared()->native() || !function->is_classic_mode()) &&
- call_kind == CALL_AS_FUNCTION && !is_construct) {
+ call_kind == CALL_AS_FUNCTION &&
+ return_handling != CONSTRUCT_CALL_RETURN) {
inner->SetValueAt(0, undefined);
}
inner->SetValueAt(arity + 1, LookupContext());

Powered by Google App Engine
This is Rietveld 408576698