Improve the code generated by the full codegen by keeping

track of the fall-through label and avoiding silly jumps.
Review URL: http://codereview.chromium.org/3166033

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5337 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kasperl@chromium.org 2010-08-25 08:57:21 +00:00
parent e38f89be6b
commit 59b0bb1e2a
5 changed files with 294 additions and 230 deletions

View File

@ -269,7 +269,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
case Expression::kTest:
// For simplicity we always test the accumulator register.
if (!reg.is(result_register())) __ mov(result_register(), reg);
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -332,7 +332,7 @@ void FullCodeGenerator::ApplyTOS(Expression::Context context) {
case Expression::kTest:
__ pop(result_register());
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -367,31 +367,7 @@ void FullCodeGenerator::DropAndApply(int count,
case Expression::kTest:
__ Drop(count);
if (!reg.is(result_register())) __ mov(result_register(), reg);
DoTest(true_label_, false_label_, NULL);
break;
}
}
void FullCodeGenerator::PrepareTest(Label* materialize_true,
Label* materialize_false,
Label** if_true,
Label** if_false) {
switch (context_) {
case Expression::kUninitialized:
UNREACHABLE();
break;
case Expression::kEffect:
// In an effect context, the true and the false case branch to the
// same label.
*if_true = *if_false = materialize_true;
break;
case Expression::kValue:
*if_true = materialize_true;
*if_false = materialize_false;
break;
case Expression::kTest:
*if_true = true_label_;
*if_false = false_label_;
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -462,7 +438,11 @@ void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
break;
}
case Expression::kTest:
__ b(flag ? true_label_ : false_label_);
if (flag) {
if (true_label_ != fall_through_) __ b(true_label_);
} else {
if (false_label_ != fall_through_) __ b(false_label_);
}
break;
}
}
@ -1735,7 +1715,9 @@ void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ BranchOnSmi(r0, if_true);
__ b(if_false);
@ -1752,10 +1734,12 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ tst(r0, Operand(kSmiTagMask | 0x80000000));
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1769,7 +1753,10 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ BranchOnSmi(r0, if_false);
__ LoadRoot(ip, Heap::kNullValueRootIndex);
__ cmp(r0, ip);
@ -1783,7 +1770,7 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
__ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
__ b(lt, if_false);
__ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
Split(le, if_true, if_false, NULL);
Split(le, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1797,11 +1784,13 @@ void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
Split(ge, if_true, if_false, NULL);
Split(ge, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1815,13 +1804,15 @@ void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ BranchOnSmi(r0, if_false);
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
__ tst(r1, Operand(1 << Map::kIsUndetectable));
Split(ne, if_true, if_false, NULL);
Split(ne, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1837,7 +1828,9 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
// used in a few functions in runtime.js which should not normally be hit by
@ -1855,11 +1848,13 @@ void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1873,11 +1868,13 @@ void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1891,11 +1888,13 @@ void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1908,7 +1907,9 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Get the frame pointer for the calling frame.
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
@ -1924,7 +1925,7 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
__ bind(&check_frame_marker);
__ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset));
__ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1940,11 +1941,13 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ pop(r1);
__ cmp(r0, r1);
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -2617,12 +2620,12 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
// Notice that the labels are swapped.
PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
VisitForControl(expr->expression(), if_true, if_false);
PrepareTest(&materialize_true, &materialize_false,
&if_false, &if_true, &fall_through);
VisitForControl(expr->expression(), if_true, if_false, fall_through);
Apply(context_, if_false, if_true); // Labels swapped.
break;
}
@ -2979,14 +2982,16 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// First we try a fast inlined version of the compare when one of
// the operands is a literal.
Token::Value op = expr->op();
Expression* left = expr->left();
Expression* right = expr->right();
if (TryLiteralCompare(op, left, right, if_true, if_false, NULL)) {
if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
Apply(context_, if_true, if_false);
return;
}
@ -2998,7 +3003,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
__ InvokeBuiltin(Builtins::IN, CALL_JS);
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(r0, ip);
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
break;
case Token::INSTANCEOF: {
@ -3007,7 +3012,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
__ CallStub(&stub);
// The stub returns 0 for true.
__ tst(r0, r0);
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
break;
}
@ -3062,7 +3067,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
CompareStub stub(cc, strict, kBothCouldBeNaN, true, r1, r0);
__ CallStub(&stub);
__ cmp(r0, Operand(0));
Split(cc, if_true, if_false, NULL);
Split(cc, if_true, if_false, fall_through);
}
}
@ -3077,13 +3082,15 @@ void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
VisitForValue(expr->expression(), kAccumulator);
__ LoadRoot(r1, Heap::kNullValueRootIndex);
__ cmp(r0, r1);
if (expr->is_strict()) {
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
} else {
__ b(eq, if_true);
__ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
@ -3096,7 +3103,7 @@ void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
__ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
__ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
__ cmp(r1, Operand(1 << Map::kIsUndetectable));
Split(eq, if_true, if_false, NULL);
Split(eq, if_true, if_false, fall_through);
}
Apply(context_, if_true, if_false);
}

View File

@ -317,6 +317,33 @@ int FullCodeGenerator::SlotOffset(Slot* slot) {
}
void FullCodeGenerator::PrepareTest(Label* materialize_true,
Label* materialize_false,
Label** if_true,
Label** if_false,
Label** fall_through) {
switch (context_) {
case Expression::kUninitialized:
UNREACHABLE();
break;
case Expression::kEffect:
// In an effect context, the true and the false case branch to the
// same label.
*if_true = *if_false = *fall_through = materialize_true;
break;
case Expression::kValue:
*if_true = *fall_through = materialize_true;
*if_false = materialize_false;
break;
case Expression::kTest:
*if_true = true_label_;
*if_false = false_label_;
*fall_through = fall_through_;
break;
}
}
void FullCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
int length = declarations->length();
@ -521,13 +548,13 @@ void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
VisitForControl(expr->left(), &done, &eval_right);
VisitForControl(expr->left(), &done, &eval_right, &eval_right);
break;
case Expression::kValue:
VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
break;
case Expression::kTest:
VisitForControl(expr->left(), true_label_, &eval_right);
VisitForControl(expr->left(), true_label_, &eval_right, &eval_right);
break;
}
} else {
@ -536,13 +563,13 @@ void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
case Expression::kUninitialized:
UNREACHABLE();
case Expression::kEffect:
VisitForControl(expr->left(), &eval_right, &done);
VisitForControl(expr->left(), &eval_right, &done, &eval_right);
break;
case Expression::kValue:
VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
break;
case Expression::kTest:
VisitForControl(expr->left(), &eval_right, false_label_);
VisitForControl(expr->left(), &eval_right, false_label_, &eval_right);
break;
}
}
@ -618,16 +645,19 @@ void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
SetStatementPosition(stmt);
Label then_part, else_part, done;
// Do not worry about optimizing for empty then or else bodies.
VisitForControl(stmt->condition(), &then_part, &else_part);
__ bind(&then_part);
Visit(stmt->then_statement());
__ jmp(&done);
__ bind(&else_part);
Visit(stmt->else_statement());
if (stmt->HasElseStatement()) {
VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
__ bind(&then_part);
Visit(stmt->then_statement());
__ jmp(&done);
__ bind(&else_part);
Visit(stmt->else_statement());
} else {
VisitForControl(stmt->condition(), &then_part, &done, &then_part);
__ bind(&then_part);
Visit(stmt->then_statement());
}
__ bind(&done);
}
@ -715,7 +745,7 @@ void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
Comment cmnt(masm_, "[ DoWhileStatement");
SetStatementPosition(stmt);
Label body, stack_limit_hit, stack_check_success;
Label body, stack_limit_hit, stack_check_success, done;
Iteration loop_statement(this, stmt);
increment_loop_depth();
@ -727,21 +757,24 @@ void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
__ StackLimitCheck(&stack_limit_hit);
__ bind(&stack_check_success);
// Record the position of the do while condition and make sure it is
// possible to break on the condition.
__ bind(loop_statement.continue_target());
// Record the position of the do while condition and make sure it is possible
// to break on the condition.
SetExpressionPosition(stmt->cond(), stmt->condition_position());
VisitForControl(stmt->cond(),
&body,
loop_statement.break_target(),
loop_statement.break_target());
VisitForControl(stmt->cond(), &body, loop_statement.break_target());
__ bind(loop_statement.break_target());
__ jmp(&done);
__ bind(&stack_limit_hit);
StackCheckStub stack_stub;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
__ bind(loop_statement.break_target());
__ bind(&done);
decrement_loop_depth();
}
@ -756,24 +789,27 @@ void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
// Emit the test at the bottom of the loop.
__ jmp(loop_statement.continue_target());
__ bind(&stack_limit_hit);
StackCheckStub stack_stub;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
__ bind(&body);
Visit(stmt->body());
__ bind(loop_statement.continue_target());
// Emit the statement position here as this is where the while statement code
// starts.
// Emit the statement position here as this is where the while
// statement code starts.
SetStatementPosition(stmt);
// Check stack before looping.
__ StackLimitCheck(&stack_limit_hit);
__ bind(&stack_check_success);
VisitForControl(stmt->cond(), &body, loop_statement.break_target());
__ bind(&stack_limit_hit);
StackCheckStub stack_stub;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
VisitForControl(stmt->cond(),
&body,
loop_statement.break_target(),
loop_statement.break_target());
__ bind(loop_statement.break_target());
decrement_loop_depth();
@ -793,6 +829,11 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
// Emit the test at the bottom of the loop (even if empty).
__ jmp(&test);
__ bind(&stack_limit_hit);
StackCheckStub stack_stub;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
__ bind(&body);
Visit(stmt->body());
@ -804,8 +845,8 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
}
__ bind(&test);
// Emit the statement position here as this is where the for statement code
// starts.
// Emit the statement position here as this is where the for
// statement code starts.
SetStatementPosition(stmt);
// Check stack before looping.
@ -813,16 +854,14 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
__ bind(&stack_check_success);
if (stmt->cond() != NULL) {
VisitForControl(stmt->cond(), &body, loop_statement.break_target());
VisitForControl(stmt->cond(),
&body,
loop_statement.break_target(),
loop_statement.break_target());
} else {
__ jmp(&body);
}
__ bind(&stack_limit_hit);
StackCheckStub stack_stub;
__ CallStub(&stack_stub);
__ jmp(&stack_check_success);
__ bind(loop_statement.break_target());
decrement_loop_depth();
}
@ -949,7 +988,7 @@ void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
void FullCodeGenerator::VisitConditional(Conditional* expr) {
Comment cmnt(masm_, "[ Conditional");
Label true_case, false_case, done;
VisitForControl(expr->condition(), &true_case, &false_case);
VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
__ bind(&true_case);
SetExpressionPosition(expr->then_expression(),

View File

@ -73,7 +73,8 @@ class FullCodeGenerator: public AstVisitor {
loop_depth_(0),
location_(kStack),
true_label_(NULL),
false_label_(NULL) {
false_label_(NULL),
fall_through_(NULL) {
}
static Handle<Code> MakeCode(CompilationInfo* info);
@ -258,7 +259,8 @@ class FullCodeGenerator: public AstVisitor {
void PrepareTest(Label* materialize_true,
Label* materialize_false,
Label** if_true,
Label** if_false);
Label** if_false,
Label** fall_through);
// Emit code to convert pure control flow to a pair of labels into the
// result expected according to an expression context.
@ -307,17 +309,23 @@ class FullCodeGenerator: public AstVisitor {
location_ = saved_location;
}
void VisitForControl(Expression* expr, Label* if_true, Label* if_false) {
void VisitForControl(Expression* expr,
Label* if_true,
Label* if_false,
Label* fall_through) {
Expression::Context saved_context = context_;
Label* saved_true = true_label_;
Label* saved_false = false_label_;
Label* saved_fall_through = fall_through_;
context_ = Expression::kTest;
true_label_ = if_true;
false_label_ = if_false;
fall_through_ = fall_through;
Visit(expr);
context_ = saved_context;
true_label_ = saved_true;
false_label_ = saved_false;
fall_through_ = saved_fall_through;
}
void VisitDeclarations(ZoneList<Declaration*>* declarations);
@ -459,6 +467,7 @@ class FullCodeGenerator: public AstVisitor {
Location location_;
Label* true_label_;
Label* false_label_;
Label* fall_through_;
friend class NestedStatement;

View File

@ -246,7 +246,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
case Expression::kTest:
// For simplicity we always test the accumulator register.
if (!reg.is(result_register())) __ mov(result_register(), reg);
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -276,7 +276,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
case Expression::kTest:
// For simplicity we always test the accumulator register.
Move(result_register(), slot);
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -304,7 +304,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
case Expression::kTest:
// For simplicity we always test the accumulator register.
__ mov(result_register(), lit->handle());
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -332,7 +332,7 @@ void FullCodeGenerator::ApplyTOS(Expression::Context context) {
case Expression::kTest:
// For simplicity we always test the accumulator register.
__ pop(result_register());
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -368,32 +368,7 @@ void FullCodeGenerator::DropAndApply(int count,
// For simplicity we always test the accumulator register.
__ Drop(count);
if (!reg.is(result_register())) __ mov(result_register(), reg);
DoTest(true_label_, false_label_, NULL);
break;
}
}
void FullCodeGenerator::PrepareTest(Label* materialize_true,
Label* materialize_false,
Label** if_true,
Label** if_false) {
switch (context_) {
case Expression::kUninitialized:
UNREACHABLE();
break;
case Expression::kEffect:
// In an effect context, the true and the false case branch to the
// same label.
*if_true = *if_false = materialize_true;
break;
case Expression::kValue:
*if_true = materialize_true;
*if_false = materialize_false;
break;
case Expression::kTest:
*if_true = true_label_;
*if_false = false_label_;
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -461,7 +436,11 @@ void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
break;
}
case Expression::kTest:
__ jmp(flag ? true_label_ : false_label_);
if (flag) {
if (true_label_ != fall_through_) __ jmp(true_label_);
} else {
if (false_label_ != fall_through_) __ jmp(false_label_);
}
break;
}
}
@ -1735,10 +1714,12 @@ void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ test(eax, Immediate(kSmiTagMask));
Split(zero, if_true, if_false, NULL);
Split(zero, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1752,10 +1733,12 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ test(eax, Immediate(kSmiTagMask | 0x80000000));
Split(zero, if_true, if_false, NULL);
Split(zero, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1769,7 +1752,9 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, if_false);
@ -1784,7 +1769,7 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
__ j(below, if_false);
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
Split(below_equal, if_true, if_false, NULL);
Split(below_equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1798,12 +1783,14 @@ void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ test(eax, Immediate(kSmiTagMask));
__ j(equal, if_false);
__ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
Split(above_equal, if_true, if_false, NULL);
Split(above_equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1817,14 +1804,16 @@ void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, if_false);
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
__ test(ebx, Immediate(1 << Map::kIsUndetectable));
Split(not_zero, if_true, if_false, NULL);
Split(not_zero, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1839,7 +1828,9 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
// used in a few functions in runtime.js which should not normally be hit by
@ -1857,12 +1848,14 @@ void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, if_false);
__ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1876,12 +1869,14 @@ void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ test(eax, Immediate(kSmiTagMask));
__ j(equal, if_false);
__ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1895,12 +1890,14 @@ void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ test(eax, Immediate(kSmiTagMask));
__ j(equal, if_false);
__ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1913,7 +1910,9 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Get the frame pointer for the calling frame.
__ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
@ -1929,7 +1928,7 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
__ bind(&check_frame_marker);
__ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1945,11 +1944,13 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ pop(ebx);
__ cmp(eax, Operand(ebx));
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -2613,15 +2614,15 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
case Token::NOT: {
Comment cmnt(masm_, "[ UnaryOperation (NOT)");
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
// Notice that the labels are swapped.
PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
VisitForControl(expr->expression(), if_true, if_false);
PrepareTest(&materialize_true, &materialize_false,
&if_false, &if_true, &fall_through);
VisitForControl(expr->expression(), if_true, if_false, fall_through);
Apply(context_, if_false, if_true); // Labels swapped.
break;
}
@ -2988,14 +2989,16 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// First we try a fast inlined version of the compare when one of
// the operands is a literal.
Token::Value op = expr->op();
Expression* left = expr->left();
Expression* right = expr->right();
if (TryLiteralCompare(op, left, right, if_true, if_false, NULL)) {
if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
Apply(context_, if_true, if_false);
return;
}
@ -3006,7 +3009,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
VisitForValue(expr->right(), kStack);
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
__ cmp(eax, Factory::true_value());
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
break;
case Token::INSTANCEOF: {
@ -3015,7 +3018,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
__ CallStub(&stub);
__ test(eax, Operand(eax));
// The stub returns 0 for true.
Split(zero, if_true, if_false, NULL);
Split(zero, if_true, if_false, fall_through);
break;
}
@ -3072,7 +3075,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
CompareStub stub(cc, strict);
__ CallStub(&stub);
__ test(eax, Operand(eax));
Split(cc, if_true, if_false, NULL);
Split(cc, if_true, if_false, fall_through);
}
}
@ -3086,12 +3089,14 @@ void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
VisitForValue(expr->expression(), kAccumulator);
__ cmp(eax, Factory::null_value());
if (expr->is_strict()) {
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
} else {
__ j(equal, if_true);
__ cmp(eax, Factory::undefined_value());
@ -3102,7 +3107,7 @@ void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
__ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(edx, FieldOperand(edx, Map::kBitFieldOffset));
__ test(edx, Immediate(1 << Map::kIsUndetectable));
Split(not_zero, if_true, if_false, NULL);
Split(not_zero, if_true, if_false, fall_through);
}
Apply(context_, if_true, if_false);
}

View File

@ -253,7 +253,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
case Expression::kTest:
// For simplicity we always test the accumulator register.
if (!reg.is(result_register())) __ movq(result_register(), reg);
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -282,7 +282,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
case Expression::kTest:
Move(result_register(), slot);
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -308,7 +308,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
case Expression::kTest:
__ Move(result_register(), lit->handle());
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -335,7 +335,7 @@ void FullCodeGenerator::ApplyTOS(Expression::Context context) {
case Expression::kTest:
__ pop(result_register());
DoTest(true_label_, false_label_, NULL);
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -370,32 +370,7 @@ void FullCodeGenerator::DropAndApply(int count,
case Expression::kTest:
__ Drop(count);
if (!reg.is(result_register())) __ movq(result_register(), reg);
DoTest(true_label_, false_label_, NULL);
break;
}
}
void FullCodeGenerator::PrepareTest(Label* materialize_true,
Label* materialize_false,
Label** if_true,
Label** if_false) {
switch (context_) {
case Expression::kUninitialized:
UNREACHABLE();
break;
case Expression::kEffect:
// In an effect context, the true and the false case branch to the
// same label.
*if_true = *if_false = materialize_true;
break;
case Expression::kValue:
*if_true = materialize_true;
*if_false = materialize_false;
break;
case Expression::kTest:
*if_true = true_label_;
*if_false = false_label_;
DoTest(true_label_, false_label_, fall_through_);
break;
}
}
@ -463,7 +438,11 @@ void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
break;
}
case Expression::kTest:
__ jmp(flag ? true_label_ : false_label_);
if (flag) {
if (true_label_ != fall_through_) __ jmp(true_label_);
} else {
if (false_label_ != fall_through_) __ jmp(false_label_);
}
break;
}
}
@ -1744,7 +1723,9 @@ void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_true);
__ jmp(if_false);
@ -1761,10 +1742,12 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
Condition positive_smi = __ CheckPositiveSmi(rax);
Split(positive_smi, if_true, if_false, NULL);
Split(positive_smi, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1778,7 +1761,9 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CompareRoot(rax, Heap::kNullValueRootIndex);
@ -1792,7 +1777,7 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
__ cmpq(rbx, Immediate(FIRST_JS_OBJECT_TYPE));
__ j(below, if_false);
__ cmpq(rbx, Immediate(LAST_JS_OBJECT_TYPE));
Split(below_equal, if_true, if_false, NULL);
Split(below_equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1806,11 +1791,13 @@ void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
Split(above_equal, if_true, if_false, NULL);
Split(above_equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1824,13 +1811,15 @@ void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
__ testb(FieldOperand(rbx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
Split(not_zero, if_true, if_false, NULL);
Split(not_zero, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1845,7 +1834,9 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
// used in a few functions in runtime.js which should not normally be hit by
@ -1863,11 +1854,13 @@ void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1881,11 +1874,13 @@ void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1899,11 +1894,13 @@ void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1916,7 +1913,9 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// Get the frame pointer for the calling frame.
__ movq(rax, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
@ -1932,7 +1931,7 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
__ bind(&check_frame_marker);
__ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset),
Smi::FromInt(StackFrame::CONSTRUCT));
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -1948,11 +1947,13 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
__ pop(rbx);
__ cmpq(rax, rbx);
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
Apply(context_, if_true, if_false);
}
@ -2612,12 +2613,11 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
Label* fall_through = NULL;
// Notice that the labels are swapped.
PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
VisitForControl(expr->expression(), if_true, if_false);
PrepareTest(&materialize_true, &materialize_false,
&if_false, &if_true, &fall_through);
VisitForControl(expr->expression(), if_true, if_false, fall_through);
Apply(context_, if_false, if_true); // Labels swapped.
break;
}
@ -2979,14 +2979,16 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
// First we try a fast inlined version of the compare when one of
// the operands is a literal.
Token::Value op = expr->op();
Expression* left = expr->left();
Expression* right = expr->right();
if (TryLiteralCompare(op, left, right, if_true, if_false, NULL)) {
if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
Apply(context_, if_true, if_false);
return;
}
@ -2997,7 +2999,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
VisitForValue(expr->right(), kStack);
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
break;
case Token::INSTANCEOF: {
@ -3006,7 +3008,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
__ CallStub(&stub);
__ testq(rax, rax);
// The stub returns 0 for true.
Split(zero, if_true, if_false, NULL);
Split(zero, if_true, if_false, fall_through);
break;
}
@ -3060,7 +3062,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
CompareStub stub(cc, strict);
__ CallStub(&stub);
__ testq(rax, rax);
Split(cc, if_true, if_false, NULL);
Split(cc, if_true, if_false, fall_through);
}
}
@ -3075,12 +3077,14 @@ void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
Label materialize_true, materialize_false;
Label* if_true = NULL;
Label* if_false = NULL;
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Label* fall_through = NULL;
PrepareTest(&materialize_true, &materialize_false,
&if_true, &if_false, &fall_through);
VisitForValue(expr->expression(), kAccumulator);
__ CompareRoot(rax, Heap::kNullValueRootIndex);
if (expr->is_strict()) {
Split(equal, if_true, if_false, NULL);
Split(equal, if_true, if_false, fall_through);
} else {
__ j(equal, if_true);
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
@ -3091,7 +3095,7 @@ void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
__ movq(rdx, FieldOperand(rax, HeapObject::kMapOffset));
__ testb(FieldOperand(rdx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
Split(not_zero, if_true, if_false, NULL);
Split(not_zero, if_true, if_false, fall_through);
}
Apply(context_, if_true, if_false);
}