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:
parent
e38f89be6b
commit
59b0bb1e2a
@ -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);
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user