Remove the forward-bailout stack from the non-optimizing compiler.

This was pretty heavyweight.  It was kept in just for a few corner cases
that assumed it was there.  We can work around them by making sure that the
expression in a reified test context is always really the expression that
was visited in that context; and by inspecting the context manually and
consing up a pair of extra AST IDs for the unusual case of unary not in a
value AST context.

R=fschneider@chromium.org
BUG=
TEST=

Review URL: http://codereview.chromium.org/8386037

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9863 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 307b589e
This diff is collapsed.
......@@ -1288,8 +1288,17 @@ class UnaryOperation: public Expression {
Token::Value op,
Expression* expression,
int pos)
: Expression(isolate), op_(op), expression_(expression), pos_(pos) {
: Expression(isolate),
op_(op),
expression_(expression),
pos_(pos),
materialize_true_id_(AstNode::kNoNumber),
materialize_false_id_(AstNode::kNoNumber) {
ASSERT(Token::IsUnaryOp(op));
if (op == Token::NOT) {
materialize_true_id_ = GetNextId(isolate);
materialize_false_id_ = GetNextId(isolate);
}
}
DECLARE_NODE_TYPE(UnaryOperation)
......@@ -1302,10 +1311,18 @@ class UnaryOperation: public Expression {
Expression* expression() const { return expression_; }
virtual int position() const { return pos_; }
int MaterializeTrueId() { return materialize_true_id_; }
int MaterializeFalseId() { return materialize_false_id_; }
private:
Token::Value op_;
Expression* expression_;
int pos_;
// For unary not (Token::NOT), the AST ids where true and false will
// actually be materialized, respectively.
int materialize_true_id_;
int materialize_false_id_;
};
......
......@@ -416,7 +416,7 @@ void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
void FullCodeGenerator::TestContext::Plug(Register reg) const {
// For simplicity we always test the accumulator register.
__ Move(result_register(), reg);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
codegen()->DoTest(this);
}
......@@ -438,7 +438,7 @@ void FullCodeGenerator::StackValueContext::PlugTOS() const {
void FullCodeGenerator::TestContext::PlugTOS() const {
// For simplicity we always test the accumulator register.
__ pop(result_register());
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
codegen()->DoTest(this);
}
......@@ -652,14 +652,13 @@ FullCodeGenerator::InlineFunctionGenerator
}
void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) {
ZoneList<Expression*>* args = node->arguments();
const Runtime::Function* function = node->function();
void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
const Runtime::Function* function = expr->function();
ASSERT(function != NULL);
ASSERT(function->intrinsic_type == Runtime::INLINE);
InlineFunctionGenerator generator =
FindInlineFunctionGenerator(function->function_id);
((*this).*(generator))(args);
((*this).*(generator))(expr);
}
......@@ -676,11 +675,25 @@ void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
}
void FullCodeGenerator::VisitInDuplicateContext(Expression* expr) {
if (context()->IsEffect()) {
VisitForEffect(expr);
} else if (context()->IsAccumulatorValue()) {
VisitForAccumulatorValue(expr);
} else if (context()->IsStackValue()) {
VisitForStackValue(expr);
} else if (context()->IsTest()) {
const TestContext* test = TestContext::cast(context());
VisitForControl(expr, test->true_label(), test->false_label(),
test->fall_through());
}
}
void FullCodeGenerator::VisitComma(BinaryOperation* expr) {
Comment cmnt(masm_, "[ Comma");
VisitForEffect(expr->left());
if (context()->IsTest()) ForwardBailoutToChild(expr);
VisitInCurrentContext(expr->right());
VisitInDuplicateContext(expr->right());
}
......@@ -702,7 +715,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
}
PrepareForBailoutForId(right_id, NO_REGISTERS);
__ bind(&eval_right);
ForwardBailoutToChild(expr);
} else if (context()->IsAccumulatorValue()) {
VisitForAccumulatorValue(left);
......@@ -710,7 +722,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
// case we need it.
__ push(result_register());
Label discard, restore;
PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
if (is_logical_and) {
DoTest(left, &discard, &restore, &restore);
} else {
......@@ -729,7 +740,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
// case we need it.
__ push(result_register());
Label discard;
PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
if (is_logical_and) {
DoTest(left, &discard, &done, &discard);
} else {
......@@ -751,7 +761,7 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
__ bind(&eval_right);
}
VisitInCurrentContext(right);
VisitInDuplicateContext(right);
__ bind(&done);
}
......@@ -778,34 +788,6 @@ void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
}
void FullCodeGenerator::ForwardBailoutToChild(Expression* expr) {
if (!info_->HasDeoptimizationSupport()) return;
ASSERT(context()->IsTest());
ASSERT(expr == forward_bailout_stack_->expr());
forward_bailout_pending_ = forward_bailout_stack_;
}
void FullCodeGenerator::VisitInCurrentContext(Expression* expr) {
if (context()->IsTest()) {
ForwardBailoutStack stack(expr, forward_bailout_pending_);
ForwardBailoutStack* saved = forward_bailout_stack_;
forward_bailout_pending_ = NULL;
forward_bailout_stack_ = &stack;
Visit(expr);
forward_bailout_stack_ = saved;
} else {
ASSERT(forward_bailout_pending_ == NULL);
Visit(expr);
State state = context()->IsAccumulatorValue() ? TOS_REG : NO_REGISTERS;
PrepareForBailout(expr, state);
// Forwarding bailouts to children is a one shot operation. It should have
// been processed at this point.
ASSERT(forward_bailout_pending_ == NULL);
}
}
void FullCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
NestedBlock nested_block(this, stmt);
......@@ -1247,16 +1229,15 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
for_test->false_label(),
NULL);
} else {
VisitInCurrentContext(expr->then_expression());
VisitInDuplicateContext(expr->then_expression());
__ jmp(&done);
}
PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS);
__ bind(&false_case);
if (context()->IsTest()) ForwardBailoutToChild(expr);
SetExpressionPosition(expr->else_expression(),
expr->else_expression_position());
VisitInCurrentContext(expr->else_expression());
VisitInDuplicateContext(expr->else_expression());
// If control flow falls through Visit, merge it with true case here.
if (!context()->IsTest()) {
__ bind(&done);
......@@ -1314,7 +1295,7 @@ bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) {
Expression *sub_expr;
Handle<String> check;
if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
EmitLiteralCompareTypeof(sub_expr, check);
EmitLiteralCompareTypeof(expr, sub_expr, check);
return true;
}
......
......@@ -85,9 +85,7 @@ class FullCodeGenerator: public AstVisitor {
loop_depth_(0),
context_(NULL),
bailout_entries_(0),
stack_checks_(2), // There's always at least one.
forward_bailout_stack_(NULL),
forward_bailout_pending_(NULL) {
stack_checks_(2) { // There's always at least one.
}
static bool MakeCode(CompilationInfo* info);
......@@ -275,27 +273,8 @@ class FullCodeGenerator: public AstVisitor {
}
};
// The forward bailout stack keeps track of the expressions that can
// bail out to just before the control flow is split in a child
// node. The stack elements are linked together through the parent
// link when visiting expressions in test contexts after requesting
// bailout in child forwarding.
class ForwardBailoutStack BASE_EMBEDDED {
public:
ForwardBailoutStack(Expression* expr, ForwardBailoutStack* parent)
: expr_(expr), parent_(parent) { }
Expression* expr() const { return expr_; }
ForwardBailoutStack* parent() const { return parent_; }
private:
Expression* const expr_;
ForwardBailoutStack* const parent_;
};
// Type of a member function that generates inline code for a native function.
typedef void (FullCodeGenerator::*InlineFunctionGenerator)
(ZoneList<Expression*>*);
typedef void (FullCodeGenerator::*InlineFunctionGenerator)(CallRuntime* expr);
static const InlineFunctionGenerator kInlineFunctionGenerators[];
......@@ -356,23 +335,22 @@ class FullCodeGenerator: public AstVisitor {
// need the write barrier if location is CONTEXT.
MemOperand VarOperand(Variable* var, Register scratch);
// Forward the bailout responsibility for the given expression to
// the next child visited (which must be in a test context).
void ForwardBailoutToChild(Expression* expr);
void VisitForEffect(Expression* expr) {
EffectContext context(this);
VisitInCurrentContext(expr);
Visit(expr);
PrepareForBailout(expr, NO_REGISTERS);
}
void VisitForAccumulatorValue(Expression* expr) {
AccumulatorValueContext context(this);
VisitInCurrentContext(expr);
Visit(expr);
PrepareForBailout(expr, TOS_REG);
}
void VisitForStackValue(Expression* expr) {
StackValueContext context(this);
VisitInCurrentContext(expr);
Visit(expr);
PrepareForBailout(expr, NO_REGISTERS);
}
void VisitForControl(Expression* expr,
......@@ -380,9 +358,14 @@ class FullCodeGenerator: public AstVisitor {
Label* if_false,
Label* fall_through) {
TestContext context(this, expr, if_true, if_false, fall_through);
VisitInCurrentContext(expr);
Visit(expr);
// For test contexts, we prepare for bailout before branching, not at
// the end of the entire expression. This happens as part of visiting
// the expression.
}
void VisitInDuplicateContext(Expression* expr);
void VisitDeclarations(ZoneList<Declaration*>* declarations);
void DeclareGlobals(Handle<FixedArray> pairs);
int DeclareGlobalsFlags();
......@@ -394,7 +377,9 @@ class FullCodeGenerator: public AstVisitor {
// Platform-specific code for comparing the type of a value with
// a given literal string.
void EmitLiteralCompareTypeof(Expression* expr, Handle<String> check);
void EmitLiteralCompareTypeof(Expression* expr,
Expression* sub_expr,
Handle<String> check);
// Platform-specific code for equality comparison with a nil-like value.
void EmitLiteralCompareNil(CompareOperation* expr,
......@@ -414,7 +399,7 @@ class FullCodeGenerator: public AstVisitor {
// canonical JS true value so we will insert a (dead) test against true at
// the actual bailout target from the optimized code. If not
// should_normalize, the true and false labels are ignored.
void PrepareForBailoutBeforeSplit(State state,
void PrepareForBailoutBeforeSplit(Expression* expr,
bool should_normalize,
Label* if_true,
Label* if_false);
......@@ -449,7 +434,7 @@ class FullCodeGenerator: public AstVisitor {
void EmitInlineRuntimeCall(CallRuntime* expr);
#define EMIT_INLINE_RUNTIME_CALL(name, x, y) \
void Emit##name(ZoneList<Expression*>* arguments);
void Emit##name(CallRuntime* expr);
INLINE_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
INLINE_RUNTIME_FUNCTION_LIST(EMIT_INLINE_RUNTIME_CALL)
#undef EMIT_INLINE_RUNTIME_CALL
......@@ -576,7 +561,6 @@ class FullCodeGenerator: public AstVisitor {
void VisitComma(BinaryOperation* expr);
void VisitLogicalExpression(BinaryOperation* expr);
void VisitArithmeticExpression(BinaryOperation* expr);
void VisitInCurrentContext(Expression* expr);
void VisitForTypeofValue(Expression* expr);
......@@ -771,8 +755,6 @@ class FullCodeGenerator: public AstVisitor {
const ExpressionContext* context_;
ZoneList<BailoutEntry> bailout_entries_;
ZoneList<BailoutEntry> stack_checks_;
ForwardBailoutStack* forward_bailout_stack_;
ForwardBailoutStack* forward_bailout_pending_;
friend class NestedStatement;
......
......@@ -5379,7 +5379,7 @@ void HGraphBuilder::VisitNot(UnaryOperation* expr) {
materialize_true));
if (materialize_false->HasPredecessor()) {
materialize_false->SetJoinId(expr->expression()->id());
materialize_false->SetJoinId(expr->MaterializeFalseId());
set_current_block(materialize_false);
Push(graph()->GetConstantFalse());
} else {
......@@ -5387,7 +5387,7 @@ void HGraphBuilder::VisitNot(UnaryOperation* expr) {
}
if (materialize_true->HasPredecessor()) {
materialize_true->SetJoinId(expr->expression()->id());
materialize_true->SetJoinId(expr->MaterializeTrueId());
set_current_block(materialize_true);
Push(graph()->GetConstantTrue());
} else {
......
This diff is collapsed.
......@@ -405,7 +405,7 @@ void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
void FullCodeGenerator::TestContext::Plug(Variable* var) const {
// For simplicity we always test the accumulator register.
codegen()->GetVar(result_register(), var);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->PrepareForBailoutBeforeSplit(false, NULL, NULL);
codegen()->DoTest(this);
}
......@@ -522,7 +522,7 @@ void FullCodeGenerator::TestContext::DropAndPlug(int count,
// For simplicity we always test the accumulator register.
__ Drop(count);
__ Move(result_register(), reg);
codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
codegen()->PrepareForBailoutBeforeSplit(false, NULL, NULL);
codegen()->DoTest(this);
}
......@@ -2413,7 +2413,7 @@ void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
context()->PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
__ And(t0, v0, Operand(kSmiTagMask));
Split(eq, t0, Operand(zero_reg), if_true, if_false, fall_through);
......@@ -2433,7 +2433,7 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
context()->PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
__ And(at, v0, Operand(kSmiTagMask | 0x80000000));
Split(eq, at, Operand(zero_reg), if_true, if_false, fall_through);
......@@ -2463,7 +2463,7 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
__ Branch(if_false, ne, at, Operand(zero_reg));
__ lbu(a1, FieldMemOperand(a2, Map::kInstanceTypeOffset));
__ Branch(if_false, lt, a1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Split(le, a1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE),
if_true, if_false, fall_through);
......@@ -2485,7 +2485,7 @@ void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
__ JumpIfSmi(v0, if_false);
__ GetObjectType(v0, a1, a1);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Split(ge, a1, Operand(FIRST_SPEC_OBJECT_TYPE),
if_true, if_false, fall_through);
......@@ -2509,7 +2509,7 @@ void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
__ lw(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
__ lbu(a1, FieldMemOperand(a1, Map::kBitFieldOffset));
__ And(at, a1, Operand(1 << Map::kIsUndetectable));
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Split(ne, at, Operand(zero_reg), if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
......@@ -2594,7 +2594,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
__ sb(a2, FieldMemOperand(a1, Map::kBitField2Offset));
__ jmp(if_true);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
context()->Plug(if_true, if_false);
}
......@@ -2613,7 +2613,7 @@ void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
__ JumpIfSmi(v0, if_false);
__ GetObjectType(v0, a1, a2);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
__ Branch(if_true, eq, a2, Operand(JS_FUNCTION_TYPE));
__ Branch(if_false);
......@@ -2635,7 +2635,7 @@ void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
__ JumpIfSmi(v0, if_false);
__ GetObjectType(v0, a1, a1);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Split(eq, a1, Operand(JS_ARRAY_TYPE),
if_true, if_false, fall_through);
......@@ -2657,7 +2657,7 @@ void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
__ JumpIfSmi(v0, if_false);
__ GetObjectType(v0, a1, a1);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Split(eq, a1, Operand(JS_REGEXP_TYPE), if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
......@@ -2687,7 +2687,7 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
// Check the marker in the calling frame.
__ bind(&check_frame_marker);
__ lw(a1, MemOperand(a2, StandardFrameConstants::kMarkerOffset));
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Split(eq, a1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)),
if_true, if_false, fall_through);
......@@ -2710,7 +2710,7 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
&if_true, &if_false, &fall_through);
__ pop(a1);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Split(eq, v0, Operand(a1), if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
......@@ -3396,7 +3396,7 @@ void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
__ lw(a0, FieldMemOperand(v0, String::kHashFieldOffset));
__ And(a0, a0, Operand(String::kContainsCachedArrayIndexMask));
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Split(eq, a0, Operand(zero_reg), if_true, if_false, fall_through);
context()->Plug(if_true, if_false);
......@@ -4048,7 +4048,7 @@ void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
{ AccumulatorValueContext context(this);
VisitForTypeofValue(expr);
}
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
if (check->Equals(isolate()->heap()->number_symbol())) {
__ JumpIfSmi(v0, if_true);
......@@ -4134,7 +4134,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
case Token::IN:
VisitForStackValue(expr->right());
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
PrepareForBailoutBeforeSplit(false, NULL, NULL);
__ LoadRoot(t0, Heap::kTrueValueRootIndex);
Split(eq, v0, Operand(t0), if_true, if_false, fall_through);
break;
......@@ -4143,7 +4143,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
VisitForStackValue(expr->right());
InstanceofStub stub(InstanceofStub::kNoFlags);
__ CallStub(&stub);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
// The stub returns 0 for true.
Split(eq, v0, Operand(zero_reg), if_true, if_false, fall_through);
break;
......@@ -4191,7 +4191,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Handle<Code> ic = CompareIC::GetUninitialized(op);
__ Call(ic, RelocInfo::CODE_TARGET, expr->id());
patch_site.EmitPatchInfo();
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through);
}
}
......@@ -4213,7 +4213,7 @@ void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
&if_true, &if_false, &fall_through);
VisitForAccumulatorValue(sub_expr);
PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
PrepareForBailoutBeforeSplit(true, if_true, if_false);
Heap::RootListIndex nil_value = nil == kNullValue ?
Heap::kNullValueRootIndex :
Heap::kUndefinedValueRootIndex;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment