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

Unified Diff: src/codegen-ia32.cc

Issue 21077: Experimental: improve the code generated for possibly boolean-valued... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: '' Created 11 years, 10 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
« no previous file with comments | « src/codegen-ia32.h ('k') | src/disassembler.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/codegen-ia32.cc
===================================================================
--- src/codegen-ia32.cc (revision 1230)
+++ src/codegen-ia32.cc (working copy)
@@ -45,6 +45,7 @@
typeof_state_(NOT_INSIDE_TYPEOF),
true_target_(NULL),
false_target_(NULL),
+ fall_through_(NULL),
previous_(NULL) {
owner_->set_state(this);
}
@@ -53,11 +54,13 @@
CodeGenState::CodeGenState(CodeGenerator* owner,
TypeofState typeof_state,
JumpTarget* true_target,
- JumpTarget* false_target)
+ JumpTarget* false_target,
+ JumpTarget* fall_through)
: owner_(owner),
typeof_state_(typeof_state),
true_target_(true_target),
false_target_(false_target),
+ fall_through_(fall_through),
previous_(owner->state()) {
owner_->set_state(this);
}
@@ -398,22 +401,60 @@
TypeofState typeof_state,
JumpTarget* true_target,
JumpTarget* false_target,
+ JumpTarget* fall_through,
bool force_control) {
ASSERT(!in_spilled_code());
+ ASSERT(!fall_through->is_bound());
#ifdef DEBUG
int original_height = frame_->height();
#endif
- { CodeGenState new_state(this, typeof_state, true_target, false_target);
+ JumpTarget* non_fall_through =
+ (false_target == fall_through) ? true_target : false_target;
+ bool backward = non_fall_through->is_bound();
+ { CodeGenState new_state(this, typeof_state, true_target, false_target,
+ fall_through);
Visit(x);
}
+ // There are four possibilities for the code generated by a call to
+ // Visit on an expression:
+ //
+ // 1. Conditional control flow to both control destinations by
+ // branching to the non-fall-through destination and binding the
+ // fall-through destination for the very next instruction to be
+ // generated.
+ //
+ // 2. Unconditional control flow to the fall-through destination by
+ // binding it (and not generating a branch or jump to the
+ // non-fall-through destination).
+ //
+ // 3. Unconditional control flow to the non-fall-through destination
+ // by jumping backward to it (if it was already bound) or binding
+ // it.
+ //
+ // 4. No control flow and a result on top of the virtual frame. In
+ // this case there can still be dangling jumps to the true and
+ // false labels (eg, from subexpressions of the short-circuited
+ // boolean operators).
+ bool got_control = fall_through->is_bound() ||
+ (backward && !has_valid_frame()) ||
+ (!backward && non_fall_through->is_bound());
- if (force_control && has_valid_frame()) {
+ if (force_control && !got_control) {
// Convert the TOS value to a boolean in the condition code register.
- ToBoolean(true_target, false_target);
+ ToBoolean(true_target, false_target, fall_through);
}
- ASSERT(!(force_control && has_valid_frame()));
- ASSERT(!has_valid_frame() || frame_->height() == original_height + 1);
+#ifdef DEBUG
+ // ToBoolean will always bind the fall-through destination.
+ got_control = got_control || fall_through->is_bound();
+#endif
+ ASSERT(!force_control || got_control);
+ ASSERT(got_control || frame_->height() == original_height + 1);
+ ASSERT(!got_control ||
+ fall_through->is_bound() ||
+ (!fall_through->is_bound() && backward && !has_valid_frame()) ||
+ (!fall_through->is_bound() && !backward &&
+ non_fall_through->is_bound()));
}
@@ -424,35 +465,46 @@
ASSERT(!in_spilled_code());
JumpTarget true_target(this);
JumpTarget false_target(this);
- LoadCondition(x, typeof_state, &true_target, &false_target, false);
+ LoadCondition(x, typeof_state, &true_target, &false_target,
+ &true_target, false);
- if (true_target.is_linked() || false_target.is_linked()) {
- // We have at least one condition value that has been "translated" into
- // a branch, thus it needs to be loaded explicitly.
- JumpTarget loaded(this);
- if (has_valid_frame()) {
- loaded.Jump(); // Don't lose the current TOS.
- }
- bool both = true_target.is_linked() && false_target.is_linked();
- // Load "true" if necessary.
- if (true_target.is_linked()) {
- true_target.Bind();
- VirtualFrame::SpilledScope spilled_scope(this);
- frame_->EmitPush(Immediate(Factory::true_value()));
- }
- // If both "true" and "false" need to be reincarnated jump across the
- // code for "false".
- if (both) {
+ if (true_target.is_bound()) {
+ // We have control flow to the fall-through destination and
+ // possibly the non-fall-through.
+ frame_->Push(Factory::true_value());
+ if (false_target.is_linked()) {
+ JumpTarget loaded(this);
loaded.Jump();
- }
- // Load "false" if necessary.
- if (false_target.is_linked()) {
false_target.Bind();
- VirtualFrame::SpilledScope spilled_scope(this);
- frame_->EmitPush(Immediate(Factory::false_value()));
+ frame_->Push(Factory::false_value());
+ loaded.Bind();
}
- // A value is loaded on all paths reaching this point.
- loaded.Bind();
+ } else if (false_target.is_bound()) {
+ // We fell through to the label that was not our preferred fall
+ // through (ie, the expression was unconditionally false.
+ frame_->Push(Factory::false_value());
+ } else {
+ // We have a valid value on top of the frame, but we still may
+ // have dangling jumps to the true and false target from nested
+ // subexpressions (eg, the left subexpressions of the
+ // short-circuited boolean operators).
+ ASSERT(has_valid_frame());
+ if (true_target.is_linked() || false_target.is_linked()) {
+ JumpTarget loaded(this);
+ loaded.Jump(); // Don't lose the current TOS.
+ if (true_target.is_linked()) {
+ true_target.Bind();
+ frame_->Push(Factory::true_value());
+ if (false_target.is_linked()) {
+ loaded.Jump();
+ }
+ }
+ if (false_target.is_linked()) {
+ false_target.Bind();
+ frame_->Push(Factory::false_value());
+ }
+ loaded.Bind();
+ }
}
ASSERT(has_valid_frame());
ASSERT(frame_->height() == original_height + 1);
@@ -569,6 +621,22 @@
}
+void CodeGenerator::Branch(Condition cc,
+ JumpTarget* true_target,
+ JumpTarget* false_target,
+ JumpTarget* fall_through) {
+ ASSERT(!fall_through->is_bound());
+ if (fall_through == false_target) {
+ true_target->Branch(cc);
+ false_target->Bind();
+ } else {
+ ASSERT(fall_through == true_target);
+ false_target->Branch(NegateCondition(cc));
+ true_target->Bind();
+ }
+}
+
+
class ToBooleanStub: public CodeStub {
public:
ToBooleanStub() { }
@@ -585,7 +653,8 @@
// convert it to a boolean in the condition code register or jump to
// 'false_target'/'true_target' as appropriate.
void CodeGenerator::ToBoolean(JumpTarget* true_target,
- JumpTarget* false_target) {
+ JumpTarget* false_target,
+ JumpTarget* fall_through) {
Comment cmnt(masm_, "[ ToBoolean");
// The value to convert should be popped from the stack.
@@ -619,8 +688,7 @@
// Convert the result to a condition code.
__ test(temp.reg(), Operand(temp.reg()));
temp.Unuse();
- true_target->Branch(not_equal);
- false_target->Jump();
+ Branch(not_equal, true_target, false_target, fall_through);
}
@@ -1249,7 +1317,8 @@
void CodeGenerator::Comparison(Condition cc,
bool strict,
JumpTarget* true_target,
- JumpTarget* false_target) {
+ JumpTarget* false_target,
+ JumpTarget* fall_through) {
// Strict only makes sense for equality comparisons.
ASSERT(!strict || cc == equal);
@@ -1310,8 +1379,7 @@
__ cmp(left_side.reg(), Operand(right_side.reg()));
right_side.Unuse();
left_side.Unuse();
- true_target->Branch(cc);
- false_target->Jump();
+ Branch(cc, true_target, false_target, fall_through);
}
@@ -1347,8 +1415,7 @@
// Test smi equality and comparison by signed int comparison.
__ cmp(Operand(comparee.reg()), Immediate(smi_value));
comparee.Unuse();
- true_target()->Branch(cc);
- false_target()->Jump();
+ Branch(cc);
}
@@ -1554,36 +1621,36 @@
if (has_then_stm && has_else_stm) {
JumpTarget then(this);
JumpTarget else_(this);
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
- if (then.is_linked()) {
- then.Bind();
+ LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
+ &then, &else_, &then, true);
+ if (then.is_bound()) {
Visit(node->then_statement());
- if (has_valid_frame() && else_.is_linked()) {
- // We have fallen through from the then block and we need to compile
- // the else block. Emit an unconditional jump around it.
- exit.Jump();
+ if (else_.is_linked()) {
+ if (has_valid_frame()) {
+ exit.Jump();
+ }
+ else_.Bind();
}
}
- if (else_.is_linked()) {
- else_.Bind();
+ if (else_.is_bound()) {
Visit(node->else_statement());
}
} else if (has_then_stm) {
ASSERT(!has_else_stm);
JumpTarget then(this);
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
- if (then.is_linked()) {
- then.Bind();
+ LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
+ &then, &exit, &then, true);
+ if (then.is_bound()) {
Visit(node->then_statement());
}
} else if (has_else_stm) {
ASSERT(!has_then_stm);
JumpTarget else_(this);
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
- if (else_.is_linked()) {
- else_.Bind();
+ LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
+ &exit, &else_, &else_, true);
+ if (else_.is_bound()) {
Visit(node->else_statement());
}
@@ -1592,10 +1659,9 @@
// We only care about the condition's side effects (not its value
// or control flow effect). LoadCondition is called without
// forcing control flow.
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
- if (has_valid_frame()) {
- // Control flow can fall off the end of the condition with a
- // value on the frame.
+ LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
+ &exit, &exit, &exit, false);
+ if (!exit.is_bound()) {
frame_->Drop();
}
}
@@ -1898,11 +1964,10 @@
frame_->Dup();
Load(clause->label());
JumpTarget enter_body(this);
- Comparison(equal, true, &enter_body, &next_test);
+ Comparison(equal, true, &enter_body, &next_test, &enter_body);
// Before entering the body from the test remove the switch value from
// the frame.
- enter_body.Bind();
frame_->Drop();
// Label the body so that fall through is enabled.
@@ -2015,7 +2080,8 @@
node->continue_target()->Bind();
if (has_valid_frame()) {
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
- &body, node->break_target(), true);
+ &body, node->break_target(), node->break_target(),
+ true);
}
}
break;
@@ -2039,11 +2105,10 @@
if (info == DONT_KNOW) {
JumpTarget body(this);
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
- &body, node->break_target(), true);
- body.Bind();
+ &body, node->break_target(), &body, true);
}
- if (has_valid_frame()) {
+ if (!node->break_target()->is_bound()) {
CheckStack(); // TODO(1222600): ignore if body contains calls.
Visit(node->body());
@@ -2082,11 +2147,10 @@
if (info == DONT_KNOW) {
JumpTarget body(this);
LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
- &body, node->break_target(), true);
- body.Bind();
+ &body, node->break_target(), &body, true);
}
- if (has_valid_frame()) {
+ if (!node->break_target()->is_bound()) {
CheckStack(); // TODO(1222600): ignore if body contains calls.
Visit(node->body());
@@ -2117,7 +2181,12 @@
}
DecrementLoopNesting();
- node->break_target()->Bind();
+ // The break target may have been bound in the condition of a do
+ // loop, or in the conditions of the other loops if they are
+ // unconditionally false. Avoid rebinding it.
+ if (node->break_target()->is_linked()) {
+ node->break_target()->Bind();
+ }
}
@@ -2656,20 +2725,18 @@
JumpTarget then(this);
JumpTarget else_(this);
JumpTarget exit(this);
- LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
- if (then.is_linked()) {
- then.Bind();
+ LoadCondition(node->condition(), NOT_INSIDE_TYPEOF,
+ &then, &else_, &then, true);
+ if (then.is_bound()) {
Load(node->then_expression(), typeof_state());
if (else_.is_linked()) {
exit.Jump();
+ else_.Bind();
}
}
-
- if (else_.is_linked()) {
- else_.Bind();
+ if (else_.is_bound()) {
Load(node->else_expression(), typeof_state());
}
-
exit.Bind();
}
@@ -2824,15 +2891,7 @@
Variable* var = node->var();
Expression* expr = var->rewrite();
if (expr != NULL) {
- // We have to be wary of calling Visit directly on expressions. Because
- // of special casing comparisons of the form typeof<expr> === "string",
- // we can return from a call from Visit (to a comparison or a unary
- // operation) without a virtual frame; which will probably crash if we
- // try to emit frame code before reestablishing a frame. Here we're
- // safe as long as variable proxies can't rewrite into typeof
- // comparisons or unary logical not expressions.
Visit(expr);
- ASSERT(has_valid_frame());
} else {
ASSERT(var->is_global());
Reference ref(this, node);
@@ -3452,8 +3511,7 @@
ASSERT(value.is_valid());
__ test(value.reg(), Immediate(kSmiTagMask));
value.Unuse();
- true_target()->Branch(zero);
- false_target()->Jump();
+ Branch(zero);
}
@@ -3486,8 +3544,7 @@
ASSERT(value.is_valid());
__ test(value.reg(), Immediate(kSmiTagMask | 0x80000000));
value.Unuse();
- true_target()->Branch(zero);
- false_target()->Jump();
+ Branch(zero);
}
@@ -3648,8 +3705,7 @@
__ cmp(temp.reg(), JS_ARRAY_TYPE);
value.Unuse();
temp.Unuse();
- true_target()->Branch(equal);
- false_target()->Jump();
+ Branch(equal);
}
@@ -3754,8 +3810,7 @@
__ cmp(right.reg(), Operand(left.reg()));
right.Unuse();
left.Unuse();
- true_target()->Branch(equal);
- false_target()->Jump();
+ Branch(equal);
}
@@ -3814,7 +3869,7 @@
if (op == Token::NOT) {
LoadCondition(node->expression(), NOT_INSIDE_TYPEOF,
- false_target(), true_target(), true);
+ false_target(), true_target(), fall_through(), true);
} else if (op == Token::DELETE) {
Property* property = node->expression()->AsProperty();
@@ -4149,16 +4204,18 @@
if (op == Token::AND) {
JumpTarget is_true(this);
+ bool backward = false_target()->is_bound();
LoadCondition(node->left(), NOT_INSIDE_TYPEOF,
- &is_true, false_target(), false);
- if (!has_valid_frame()) {
- if (is_true.is_linked()) {
- // Evaluate right side expression.
- is_true.Bind();
- LoadCondition(node->right(), NOT_INSIDE_TYPEOF,
- true_target(), false_target(), false);
- }
- } else {
+ &is_true, false_target(), &is_true, false);
+ if (is_true.is_bound()) {
+ LoadCondition(node->right(), NOT_INSIDE_TYPEOF,
+ true_target(), false_target(), fall_through(),
+ false);
+ } else if (!backward && false_target()->is_bound()) {
+ // If the false target became bound due to the left operand,
+ // then that operand was unconditionally false.
+ return;
+ } else if (has_valid_frame()) {
// We have a materialized value on the frame.
JumpTarget pop_and_continue(this);
JumpTarget exit(this);
@@ -4169,10 +4226,9 @@
//
// Duplicate the TOS value. The duplicate will be popped by ToBoolean.
frame_->Dup();
- ToBoolean(&pop_and_continue, &exit);
+ ToBoolean(&pop_and_continue, &exit, &pop_and_continue);
// Pop the result of evaluating the first part.
- pop_and_continue.Bind();
frame_->Drop();
// Evaluate right side expression.
@@ -4185,15 +4241,17 @@
} else if (op == Token::OR) {
JumpTarget is_false(this);
+ bool backward = true_target()->is_bound();
LoadCondition(node->left(), NOT_INSIDE_TYPEOF,
- true_target(), &is_false, false);
- if (!has_valid_frame()) {
- if (is_false.is_linked()) {
- // Evaluate right side expression.
- is_false.Bind();
- LoadCondition(node->right(), NOT_INSIDE_TYPEOF,
- true_target(), false_target(), false);
- }
+ true_target(), &is_false, &is_false, false);
+ if (is_false.is_bound()) {
+ LoadCondition(node->right(), NOT_INSIDE_TYPEOF,
+ true_target(), false_target(), fall_through(),
+ false);
+ } else if (!backward && true_target()->is_bound()) {
+ // If the true target became bound due to the left operand, then
+ // that operand was unconditionally true.
+ return;
} else {
// We have a materialized value on the frame.
JumpTarget pop_and_continue(this);
@@ -4204,10 +4262,9 @@
// section 9.2, page 30.
// Duplicate the TOS value. The duplicate will be popped by ToBoolean.
frame_->Dup();
- ToBoolean(&exit, &pop_and_continue);
+ ToBoolean(&exit, &pop_and_continue, &pop_and_continue);
// Pop the result of evaluating the first part.
- pop_and_continue.Bind();
frame_->Drop();
// Evaluate right side expression.
@@ -4315,9 +4372,9 @@
__ test(temp.reg(), Immediate(1 << Map::kIsUndetectable));
cc = not_zero;
}
+
operand.Unuse();
- true_target()->Branch(cc);
- false_target()->Jump();
+ Branch(cc);
return;
}
}
@@ -4344,8 +4401,7 @@
__ mov(answer.reg(), FieldOperand(answer.reg(), HeapObject::kMapOffset));
__ cmp(answer.reg(), Factory::heap_number_map());
answer.Unuse();
- true_target()->Branch(equal);
- false_target()->Jump();
+ Branch(equal);
} else if (check->Equals(Heap::string_symbol())) {
__ test(answer.reg(), Immediate(kSmiTagMask));
@@ -4364,16 +4420,14 @@
__ cmp(temp.reg(), FIRST_NONSTRING_TYPE);
temp.Unuse();
answer.Unuse();
- true_target()->Branch(less);
- false_target()->Jump();
+ Branch(less);
} else if (check->Equals(Heap::boolean_symbol())) {
__ cmp(answer.reg(), Factory::true_value());
true_target()->Branch(equal);
__ cmp(answer.reg(), Factory::false_value());
answer.Unuse();
- true_target()->Branch(equal);
- false_target()->Jump();
+ Branch(equal);
} else if (check->Equals(Heap::undefined_symbol())) {
__ cmp(answer.reg(), Factory::undefined_value());
@@ -4389,8 +4443,7 @@
FieldOperand(answer.reg(), Map::kBitFieldOffset));
__ test(answer.reg(), Immediate(1 << Map::kIsUndetectable));
answer.Unuse();
- true_target()->Branch(not_zero);
- false_target()->Jump();
+ Branch(not_zero);
} else if (check->Equals(Heap::function_symbol())) {
__ test(answer.reg(), Immediate(kSmiTagMask));
@@ -4401,8 +4454,7 @@
FieldOperand(answer.reg(), Map::kInstanceTypeOffset));
__ cmp(answer.reg(), JS_FUNCTION_TYPE);
answer.Unuse();
- true_target()->Branch(equal);
- false_target()->Jump();
+ Branch(equal);
} else if (check->Equals(Heap::object_symbol())) {
__ test(answer.reg(), Immediate(kSmiTagMask));
@@ -4424,13 +4476,16 @@
__ cmp(map.reg(), LAST_JS_OBJECT_TYPE);
answer.Unuse();
map.Unuse();
- true_target()->Branch(less_equal);
- false_target()->Jump();
+ Branch(less_equal);
} else {
// Uncommon case: typeof testing against a string literal that is
// never returned from the typeof operator.
answer.Unuse();
- false_target()->Jump();
+ if (false_target()->is_bound()) {
+ false_target()->Jump();
+ } else {
+ false_target()->Bind();
+ }
}
return;
}
@@ -4471,8 +4526,7 @@
answer.ToRegister();
__ test(answer.reg(), Operand(answer.reg()));
answer.Unuse();
- true_target()->Branch(zero);
- false_target()->Jump();
+ Branch(zero);
return;
}
default:
@@ -4490,7 +4544,7 @@
} else {
Load(left);
Load(right);
- Comparison(cc, strict, true_target(), false_target());
+ Comparison(cc, strict, true_target(), false_target(), fall_through());
}
}
« no previous file with comments | « src/codegen-ia32.h ('k') | src/disassembler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698