Add binary operations to fast compiler.
Review URL: http://codereview.chromium.org/342019 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3172 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
9ad7a66f98
commit
05d6294e98
@ -607,7 +607,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) {
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
Visit(args->at(i));
|
||||
ASSERT(args->at(i)->location().is_value());
|
||||
// If location is temporary, it is already on the stack,
|
||||
// If location is value, it is already on the stack,
|
||||
// so nothing to do here.
|
||||
}
|
||||
|
||||
@ -648,11 +648,57 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
// Compile a short-circuited boolean or operation in a non-test
|
||||
// context.
|
||||
ASSERT(expr->op() == Token::OR);
|
||||
switch (expr->op()) {
|
||||
case Token::COMMA:
|
||||
ASSERT(expr->left()->location().is_effect());
|
||||
ASSERT_EQ(expr->right()->location().type(), expr->location().type());
|
||||
Visit(expr->left());
|
||||
Visit(expr->right());
|
||||
break;
|
||||
|
||||
case Token::OR:
|
||||
case Token::AND:
|
||||
EmitLogicalOperation(expr);
|
||||
break;
|
||||
|
||||
case Token::ADD:
|
||||
case Token::SUB:
|
||||
case Token::DIV:
|
||||
case Token::MOD:
|
||||
case Token::MUL:
|
||||
case Token::BIT_OR:
|
||||
case Token::BIT_AND:
|
||||
case Token::BIT_XOR:
|
||||
case Token::SHL:
|
||||
case Token::SHR:
|
||||
case Token::SAR: {
|
||||
ASSERT(expr->left()->location().is_value());
|
||||
ASSERT(expr->right()->location().is_value());
|
||||
|
||||
Visit(expr->left());
|
||||
Visit(expr->right());
|
||||
__ pop(r0);
|
||||
__ pop(r1);
|
||||
GenericBinaryOpStub stub(expr->op(),
|
||||
NO_OVERWRITE);
|
||||
__ CallStub(&stub);
|
||||
Move(expr->location(), r0);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
|
||||
// Compile a short-circuited boolean operation in a non-test context.
|
||||
|
||||
// Compile (e0 || e1) as if it were
|
||||
// (let (temp = e0) temp ? temp : e1).
|
||||
// Compile (e0 && e1) as if it were
|
||||
// (let (temp = e0) !temp ? temp : e1).
|
||||
|
||||
Label done;
|
||||
Location destination = expr->location();
|
||||
@ -675,9 +721,13 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
}
|
||||
}
|
||||
// The left-hand value is in on top of the stack. It is duplicated on the
|
||||
// stack iff the destination location is temporary.
|
||||
// stack iff the destination location is value.
|
||||
__ CallRuntime(Runtime::kToBool, 1);
|
||||
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
||||
if (expr->op() == Token::OR) {
|
||||
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
||||
} else {
|
||||
__ LoadRoot(ip, Heap::kFalseValueRootIndex);
|
||||
}
|
||||
__ cmp(r0, ip);
|
||||
__ b(eq, &done);
|
||||
|
||||
|
@ -849,6 +849,12 @@ void CodeGenSelector::VisitCountOperation(CountOperation* expr) {
|
||||
|
||||
void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
switch (expr->op()) {
|
||||
case Token::COMMA:
|
||||
VisitAsEffect(expr->left());
|
||||
CHECK_BAILOUT;
|
||||
Visit(expr->right()); // Location is the same as the parent location.
|
||||
break;
|
||||
|
||||
case Token::OR:
|
||||
VisitAsValue(expr->left());
|
||||
CHECK_BAILOUT;
|
||||
@ -857,6 +863,22 @@ void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
Visit(expr->right());
|
||||
break;
|
||||
|
||||
case Token::ADD:
|
||||
case Token::SUB:
|
||||
case Token::DIV:
|
||||
case Token::MOD:
|
||||
case Token::MUL:
|
||||
case Token::BIT_OR:
|
||||
case Token::BIT_AND:
|
||||
case Token::BIT_XOR:
|
||||
case Token::SHL:
|
||||
case Token::SHR:
|
||||
case Token::SAR:
|
||||
VisitAsValue(expr->left());
|
||||
CHECK_BAILOUT;
|
||||
VisitAsValue(expr->right());
|
||||
break;
|
||||
|
||||
default:
|
||||
BAILOUT("Unsupported binary operation");
|
||||
}
|
||||
|
@ -78,6 +78,9 @@ class FastCodeGenerator: public AstVisitor {
|
||||
AST_NODE_LIST(DECLARE_VISIT)
|
||||
#undef DECLARE_VISIT
|
||||
|
||||
// Handles the shortcutted logical binary operations in VisitBinaryOperation.
|
||||
void EmitLogicalOperation(BinaryOperation* expr);
|
||||
|
||||
MacroAssembler* masm_;
|
||||
FunctionLiteral* function_;
|
||||
Handle<Script> script_;
|
||||
|
@ -590,7 +590,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) {
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
Visit(args->at(i));
|
||||
ASSERT(args->at(i)->location().is_value());
|
||||
// If location is temporary, it is already on the stack,
|
||||
// If location is value, it is already on the stack,
|
||||
// so nothing to do here.
|
||||
}
|
||||
|
||||
@ -631,13 +631,64 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
// Compile a short-circuited boolean or operation in a non-test
|
||||
// context.
|
||||
ASSERT(expr->op() == Token::OR);
|
||||
// Compile (e0 || e1) as if it were
|
||||
// (let (temp = e0) temp ? temp : e1).
|
||||
switch (expr->op()) {
|
||||
case Token::COMMA:
|
||||
ASSERT(expr->left()->location().is_effect());
|
||||
ASSERT_EQ(expr->right()->location().type(), expr->location().type());
|
||||
Visit(expr->left());
|
||||
Visit(expr->right());
|
||||
break;
|
||||
|
||||
case Token::OR:
|
||||
case Token::AND:
|
||||
EmitLogicalOperation(expr);
|
||||
break;
|
||||
|
||||
case Token::ADD:
|
||||
case Token::SUB:
|
||||
case Token::DIV:
|
||||
case Token::MOD:
|
||||
case Token::MUL:
|
||||
case Token::BIT_OR:
|
||||
case Token::BIT_AND:
|
||||
case Token::BIT_XOR:
|
||||
case Token::SHL:
|
||||
case Token::SHR:
|
||||
case Token::SAR: {
|
||||
ASSERT(expr->left()->location().is_value());
|
||||
ASSERT(expr->right()->location().is_value());
|
||||
|
||||
Visit(expr->left());
|
||||
Visit(expr->right());
|
||||
GenericBinaryOpStub stub(expr->op(),
|
||||
NO_OVERWRITE,
|
||||
NO_GENERIC_BINARY_FLAGS);
|
||||
__ CallStub(&stub);
|
||||
Move(expr->location(), eax);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
|
||||
// Compile a short-circuited boolean operation in a non-test context.
|
||||
|
||||
// Compile (e0 || e1) or (e0 && e1) as if it were
|
||||
// (let (temp = e0) temp [or !temp, for &&] ? temp : e1).
|
||||
|
||||
Label eval_right, done;
|
||||
Label *left_true, *left_false; // Where to branch to if lhs has that value.
|
||||
if (expr->op() == Token::OR) {
|
||||
left_true = &done;
|
||||
left_false = &eval_right;
|
||||
} else {
|
||||
left_true = &eval_right;
|
||||
left_false = &done;
|
||||
}
|
||||
Location destination = expr->location();
|
||||
Expression* left = expr->left();
|
||||
Expression* right = expr->right();
|
||||
@ -670,27 +721,31 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
}
|
||||
}
|
||||
// The left-hand value is in eax. It is also on the stack iff the
|
||||
// destination location is temporary.
|
||||
// destination location is value.
|
||||
|
||||
// Perform fast checks assumed by the stub.
|
||||
__ cmp(eax, Factory::undefined_value()); // The undefined value is false.
|
||||
__ j(equal, &eval_right);
|
||||
__ j(equal, left_false);
|
||||
__ cmp(eax, Factory::true_value()); // True is true.
|
||||
__ j(equal, &done);
|
||||
__ j(equal, left_true);
|
||||
__ cmp(eax, Factory::false_value()); // False is false.
|
||||
__ j(equal, &eval_right);
|
||||
__ j(equal, left_false);
|
||||
ASSERT(kSmiTag == 0);
|
||||
__ test(eax, Operand(eax)); // The smi zero is false.
|
||||
__ j(zero, &eval_right);
|
||||
__ j(zero, left_false);
|
||||
__ test(eax, Immediate(kSmiTagMask)); // All other smis are true.
|
||||
__ j(zero, &done);
|
||||
__ j(zero, left_true);
|
||||
|
||||
// Call the stub for all other cases.
|
||||
__ push(eax);
|
||||
ToBooleanStub stub;
|
||||
__ CallStub(&stub);
|
||||
__ test(eax, Operand(eax)); // The stub returns nonzero for true.
|
||||
__ j(not_zero, &done);
|
||||
if (expr->op() == Token::OR) {
|
||||
__ j(not_zero, &done);
|
||||
} else {
|
||||
__ j(zero, &done);
|
||||
}
|
||||
|
||||
__ bind(&eval_right);
|
||||
// Discard the left-hand value if present on the stack.
|
||||
|
@ -593,7 +593,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) {
|
||||
// Push function on the stack.
|
||||
Visit(node->expression());
|
||||
ASSERT(node->expression()->location().is_value());
|
||||
// If location is temporary, already on the stack,
|
||||
// If location is value, already on the stack,
|
||||
|
||||
// Push global object (receiver).
|
||||
__ push(CodeGenerator::GlobalObject());
|
||||
@ -604,7 +604,7 @@ void FastCodeGenerator::VisitCallNew(CallNew* node) {
|
||||
for (int i = 0; i < arg_count; i++) {
|
||||
Visit(args->at(i));
|
||||
ASSERT(args->at(i)->location().is_value());
|
||||
// If location is temporary, it is already on the stack,
|
||||
// If location is value, it is already on the stack,
|
||||
// so nothing to do here.
|
||||
}
|
||||
|
||||
@ -645,13 +645,66 @@ void FastCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
// Compile a short-circuited boolean or operation in a non-test
|
||||
// context.
|
||||
ASSERT(expr->op() == Token::OR);
|
||||
switch (expr->op()) {
|
||||
case Token::COMMA:
|
||||
ASSERT(expr->left()->location().is_effect());
|
||||
ASSERT_EQ(expr->right()->location().type(), expr->location().type());
|
||||
Visit(expr->left());
|
||||
Visit(expr->right());
|
||||
break;
|
||||
|
||||
case Token::OR:
|
||||
case Token::AND:
|
||||
EmitLogicalOperation(expr);
|
||||
break;
|
||||
|
||||
case Token::ADD:
|
||||
case Token::SUB:
|
||||
case Token::DIV:
|
||||
case Token::MOD:
|
||||
case Token::MUL:
|
||||
case Token::BIT_OR:
|
||||
case Token::BIT_AND:
|
||||
case Token::BIT_XOR:
|
||||
case Token::SHL:
|
||||
case Token::SHR:
|
||||
case Token::SAR: {
|
||||
ASSERT(expr->left()->location().is_value());
|
||||
ASSERT(expr->right()->location().is_value());
|
||||
|
||||
Visit(expr->left());
|
||||
Visit(expr->right());
|
||||
GenericBinaryOpStub stub(expr->op(),
|
||||
NO_OVERWRITE,
|
||||
NO_GENERIC_BINARY_FLAGS);
|
||||
__ CallStub(&stub);
|
||||
Move(expr->location(), kReturnRegister);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
|
||||
// Compile a short-circuited boolean operation in a non-test context.
|
||||
|
||||
// Compile (e0 || e1) as if it were
|
||||
// (let (temp = e0) temp ? temp : e1).
|
||||
// Compile (e0 && e1) as if it were
|
||||
// (let (temp = e0) !temp ? temp : e1).
|
||||
|
||||
Label eval_right, done;
|
||||
Label *left_true, *left_false; // Where to branch to if lhs has that value.
|
||||
if (expr->op() == Token::OR) {
|
||||
left_true = &done;
|
||||
left_false = &eval_right;
|
||||
} else {
|
||||
left_true = &eval_right;
|
||||
left_false = &done;
|
||||
}
|
||||
Location destination = expr->location();
|
||||
Expression* left = expr->left();
|
||||
Expression* right = expr->right();
|
||||
@ -684,28 +737,32 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
}
|
||||
}
|
||||
// The left-hand value is in rax. It is also on the stack iff the
|
||||
// destination location is temporary.
|
||||
// destination location is value.
|
||||
|
||||
// Perform fast checks assumed by the stub.
|
||||
// The undefined value is false.
|
||||
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, &eval_right);
|
||||
__ j(equal, left_false);
|
||||
__ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true.
|
||||
__ j(equal, &done);
|
||||
__ j(equal, left_true);
|
||||
__ CompareRoot(rax, Heap::kFalseValueRootIndex); // False is false.
|
||||
__ j(equal, &eval_right);
|
||||
__ j(equal, left_false);
|
||||
ASSERT(kSmiTag == 0);
|
||||
__ SmiCompare(rax, Smi::FromInt(0)); // The smi zero is false.
|
||||
__ j(equal, &eval_right);
|
||||
__ j(equal, left_false);
|
||||
Condition is_smi = masm_->CheckSmi(rax); // All other smis are true.
|
||||
__ j(is_smi, &done);
|
||||
__ j(is_smi, left_true);
|
||||
|
||||
// Call the stub for all other cases.
|
||||
__ push(rax);
|
||||
ToBooleanStub stub;
|
||||
__ CallStub(&stub);
|
||||
__ testq(rax, rax); // The stub returns nonzero for true.
|
||||
__ j(not_zero, &done);
|
||||
if (expr->op() == Token::OR) {
|
||||
__ j(not_zero, &done);
|
||||
} else {
|
||||
__ j(zero, &done);
|
||||
}
|
||||
|
||||
__ bind(&eval_right);
|
||||
// Discard the left-hand value if present on the stack.
|
||||
|
Loading…
Reference in New Issue
Block a user