Initial implementation of top-level compilation of expressions in test
context. Test contexts are used for the left subexpressions of short-circuited boolean operators. The right subexpressions inherit their expression context from the binary op expression. Compilation of short-circuited operations in effect and test context is straightforward: effect(e0 || e1) = test(e0, L0, L1) L1: effect(e1) L0: test(e0 || e1, L0, L1) = test(e0, L0, L2) L2: test(e1, L0, L1) Because the value of the first subexpression may be needed as the value of the whole expression in a value context, we introduce a hybrid value/test contest (the value is needed if true, but not if false). value(e0 || e1) = value/test(e0, L0, L1) L1: value(e1) L0: The compilation of value/test and test/value (introduced by boolean AND) is: value/test(e0 || e1, L0, L1) = value/test(e0, L0, L2) L2: value/test(e1, L0, L1) test/value(e0 || e1, L0, L1) = test(e0, L0, L2) L2: test/value(e1, L0, L1) Boolean AND is the dual. The AST nodes themselves (not their parents) are responsible for producing the proper result (effect, value, or control flow) depending on their context. Review URL: http://codereview.chromium.org/339082 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3187 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
b7c0b738c7
commit
ab3e85eeb4
@ -123,15 +123,51 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
|
||||
void FastCodeGenerator::Move(Expression::Context context, Register source) {
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
break;
|
||||
case Expression::kValue:
|
||||
__ push(source);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
TestAndBranch(source, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
__ push(source);
|
||||
TestAndBranch(source, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
__ push(source);
|
||||
TestAndBranch(source, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(true_label_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
break;
|
||||
case Expression::kValue: // Fall through.
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest: // Fall through.
|
||||
case Expression::kTestValue:
|
||||
__ ldr(ip, MemOperand(fp, SlotOffset(source)));
|
||||
__ push(ip);
|
||||
Move(context, ip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -143,9 +179,12 @@ void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
break;
|
||||
case Expression::kValue:
|
||||
case Expression::kValue: // Fall through.
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest: // Fall through.
|
||||
case Expression::kTestValue:
|
||||
__ mov(ip, Operand(expr->handle()));
|
||||
__ push(ip);
|
||||
Move(context, ip);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -162,10 +201,49 @@ void FastCodeGenerator::DropAndMove(Expression::Context context,
|
||||
case Expression::kValue:
|
||||
__ str(source, MemOperand(sp));
|
||||
break;
|
||||
case Expression::kTest:
|
||||
ASSERT(!source.is(sp));
|
||||
__ pop();
|
||||
TestAndBranch(source, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
__ str(source, MemOperand(sp));
|
||||
TestAndBranch(source, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
__ str(source, MemOperand(sp));
|
||||
TestAndBranch(source, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::TestAndBranch(Register source,
|
||||
Label* true_label,
|
||||
Label* false_label) {
|
||||
ASSERT_NE(NULL, true_label);
|
||||
ASSERT_NE(NULL, false_label);
|
||||
// Call the runtime to find the boolean value of the source and then
|
||||
// translate it into control flow to the pair of labels.
|
||||
__ push(source);
|
||||
__ CallRuntime(Runtime::kToBool, 1);
|
||||
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
||||
__ cmp(r0, ip);
|
||||
__ b(eq, true_label);
|
||||
__ jmp(false_label);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
|
||||
// Call the runtime to declare the globals.
|
||||
// The context is the first argument.
|
||||
@ -369,6 +447,28 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
case Expression::kValue:
|
||||
if (!result_saved) __ push(r0);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
if (result_saved) __ pop(r0);
|
||||
TestAndBranch(r0, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(r0);
|
||||
TestAndBranch(r0, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(r0);
|
||||
TestAndBranch(r0, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,6 +546,28 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
case Expression::kValue:
|
||||
if (!result_saved) __ push(r0);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
if (result_saved) __ pop(r0);
|
||||
TestAndBranch(r0, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(r0);
|
||||
TestAndBranch(r0, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(r0);
|
||||
TestAndBranch(r0, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -530,16 +652,44 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
// Case 'var = temp'. Discard right-hand-side temporary.
|
||||
__ pop(ip);
|
||||
__ pop(r0);
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// Case 'temp1 <- (var = temp0)'. Preserve right-hand-side
|
||||
// temporary on the stack.
|
||||
__ ldr(ip, MemOperand(sp));
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
break;
|
||||
case Expression::kTest:
|
||||
// Case 'if (var = temp) ...'.
|
||||
__ pop(r0);
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
TestAndBranch(r0, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
// Case '(var = temp) || ...' in value context.
|
||||
Label discard;
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
TestAndBranch(r0, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
// Case '(var = temp) && ...' in value context.
|
||||
Label discard;
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ str(r0, MemOperand(fp, SlotOffset(var->slot())));
|
||||
TestAndBranch(r0, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ pop();
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Do the slot assignment.
|
||||
__ str(ip, MemOperand(fp, SlotOffset(var->slot())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -734,11 +884,19 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case Expression::kEffect:
|
||||
break;
|
||||
case Expression::kValue:
|
||||
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
||||
__ push(ip);
|
||||
break;
|
||||
case Expression::kEffect:
|
||||
case Expression::kTestValue:
|
||||
// Value is false so it's needed.
|
||||
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
|
||||
__ push(ip);
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest:
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -794,52 +952,4 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
Expression::Context context = expr->context();
|
||||
Expression* left = expr->left();
|
||||
Expression* right = expr->right();
|
||||
|
||||
// Call the runtime to find the boolean value of the left-hand
|
||||
// subexpression. Duplicate the value if it may be needed as the final
|
||||
// result.
|
||||
if (left->AsLiteral() != NULL) {
|
||||
__ mov(r0, Operand(left->AsLiteral()->handle()));
|
||||
__ push(r0);
|
||||
if (context == Expression::kValue) __ push(r0);
|
||||
} else {
|
||||
Visit(left);
|
||||
ASSERT_EQ(Expression::kValue, left->context());
|
||||
if (context == Expression::kValue) {
|
||||
__ ldr(r0, MemOperand(sp));
|
||||
__ push(r0);
|
||||
}
|
||||
}
|
||||
// The left-hand value is in on top of the stack. It is duplicated on the
|
||||
// stack iff the destination location is value.
|
||||
__ CallRuntime(Runtime::kToBool, 1);
|
||||
if (expr->op() == Token::OR) {
|
||||
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
|
||||
} else {
|
||||
__ LoadRoot(ip, Heap::kFalseValueRootIndex);
|
||||
}
|
||||
__ cmp(r0, ip);
|
||||
__ b(eq, &done);
|
||||
|
||||
// Discard the left-hand value if present on the stack.
|
||||
if (context == Expression::kValue) __ pop();
|
||||
// Save or discard the right-hand value as needed.
|
||||
Visit(right);
|
||||
ASSERT_EQ(context, right->context());
|
||||
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
14
src/ast.h
14
src/ast.h
@ -162,9 +162,21 @@ class Statement: public AstNode {
|
||||
class Expression: public AstNode {
|
||||
public:
|
||||
enum Context {
|
||||
// Not assigned a context yet, or else will not be visited during
|
||||
// code generation.
|
||||
kUninitialized,
|
||||
// Evaluated for its side effects.
|
||||
kEffect,
|
||||
kValue
|
||||
// Evaluated for its value (and side effects).
|
||||
kValue,
|
||||
// Evaluated for control flow (and side effects).
|
||||
kTest,
|
||||
// Evaluated for control flow and side effects. Value is also
|
||||
// needed if true.
|
||||
kValueTest,
|
||||
// Evaluated for control flow and side effects. Value is also
|
||||
// needed if false.
|
||||
kTestValue
|
||||
};
|
||||
|
||||
Expression() : context_(kUninitialized) {}
|
||||
|
@ -849,7 +849,45 @@ void CodeGenSelector::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
break;
|
||||
|
||||
case Token::OR:
|
||||
ProcessExpression(expr->left(), Expression::kValue);
|
||||
switch (context_) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect: // Fall through.
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kTestValue:
|
||||
// The left subexpression's value is not needed, it is in a pure
|
||||
// test context.
|
||||
ProcessExpression(expr->left(), Expression::kTest);
|
||||
break;
|
||||
case Expression::kValue: // Fall through.
|
||||
case Expression::kValueTest:
|
||||
// The left subexpression's value is needed, it is in a hybrid
|
||||
// value/test context.
|
||||
ProcessExpression(expr->left(), Expression::kValueTest);
|
||||
break;
|
||||
}
|
||||
CHECK_BAILOUT;
|
||||
ProcessExpression(expr->right(), context_);
|
||||
break;
|
||||
|
||||
case Token::AND:
|
||||
switch (context_) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect: // Fall through.
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest:
|
||||
// The left subexpression's value is not needed, it is in a pure
|
||||
// test context.
|
||||
ProcessExpression(expr->left(), Expression::kTest);
|
||||
break;
|
||||
case Expression::kValue: // Fall through.
|
||||
case Expression::kTestValue:
|
||||
// The left subexpression's value is needed, it is in a hybrid
|
||||
// test/value context.
|
||||
ProcessExpression(expr->left(), Expression::kTestValue);
|
||||
break;
|
||||
}
|
||||
CHECK_BAILOUT;
|
||||
ProcessExpression(expr->right(), context_);
|
||||
break;
|
||||
|
@ -35,6 +35,8 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
#define __ ACCESS_MASM(masm_)
|
||||
|
||||
Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
|
||||
Handle<Script> script,
|
||||
bool is_eval) {
|
||||
@ -71,21 +73,6 @@ int FastCodeGenerator::SlotOffset(Slot* slot) {
|
||||
}
|
||||
|
||||
|
||||
// All platform macro assemblers in {ia32,x64,arm} have a push(Register)
|
||||
// function.
|
||||
void FastCodeGenerator::Move(Expression::Context context, Register source) {
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
break;
|
||||
case Expression::kValue:
|
||||
masm_->push(source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitDeclarations(
|
||||
ZoneList<Declaration*>* declarations) {
|
||||
int length = declarations->length();
|
||||
@ -202,6 +189,80 @@ void FastCodeGenerator::SetSourcePosition(int pos) {
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
|
||||
#ifdef DEBUG
|
||||
Expression::Context expected = Expression::kUninitialized;
|
||||
switch (expr->context()) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect: // Fall through.
|
||||
case Expression::kTest:
|
||||
// The value of the left subexpression is not needed.
|
||||
expected = Expression::kTest;
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// The value of the left subexpression is needed and its specific
|
||||
// context depends on the operator.
|
||||
expected = (expr->op() == Token::OR)
|
||||
? Expression::kValueTest
|
||||
: Expression::kTestValue;
|
||||
break;
|
||||
case Expression::kValueTest:
|
||||
// The value of the left subexpression is needed for OR.
|
||||
expected = (expr->op() == Token::OR)
|
||||
? Expression::kValueTest
|
||||
: Expression::kTest;
|
||||
break;
|
||||
case Expression::kTestValue:
|
||||
// The value of the left subexpression is needed for AND.
|
||||
expected = (expr->op() == Token::OR)
|
||||
? Expression::kTest
|
||||
: Expression::kTestValue;
|
||||
break;
|
||||
}
|
||||
ASSERT_EQ(expected, expr->left()->context());
|
||||
ASSERT_EQ(expr->context(), expr->right()->context());
|
||||
#endif
|
||||
|
||||
Label eval_right, done;
|
||||
Label* saved_true = true_label_;
|
||||
Label* saved_false = false_label_;
|
||||
|
||||
// Set up the appropriate context for the left subexpression based on the
|
||||
// operation and our own context.
|
||||
if (expr->op() == Token::OR) {
|
||||
// If there is no usable true label in the OR expression's context, use
|
||||
// the end of this expression, otherwise inherit the same true label.
|
||||
if (expr->context() == Expression::kEffect ||
|
||||
expr->context() == Expression::kValue) {
|
||||
true_label_ = &done;
|
||||
}
|
||||
// The false label is the label of the second subexpression.
|
||||
false_label_ = &eval_right;
|
||||
} else {
|
||||
ASSERT_EQ(Token::AND, expr->op());
|
||||
// The true label is the label of the second subexpression.
|
||||
true_label_ = &eval_right;
|
||||
// If there is no usable false label in the AND expression's context,
|
||||
// use the end of the expression, otherwise inherit the same false
|
||||
// label.
|
||||
if (expr->context() == Expression::kEffect ||
|
||||
expr->context() == Expression::kValue) {
|
||||
false_label_ = &done;
|
||||
}
|
||||
}
|
||||
|
||||
Visit(expr->left());
|
||||
true_label_ = saved_true;
|
||||
false_label_ = saved_false;
|
||||
|
||||
__ bind(&eval_right);
|
||||
Visit(expr->right());
|
||||
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::VisitDeclaration(Declaration* decl) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
@ -339,4 +400,7 @@ void FastCodeGenerator::VisitThisFunction(ThisFunction* expr) {
|
||||
}
|
||||
|
||||
|
||||
#undef __
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -39,7 +39,12 @@ namespace internal {
|
||||
class FastCodeGenerator: public AstVisitor {
|
||||
public:
|
||||
FastCodeGenerator(MacroAssembler* masm, Handle<Script> script, bool is_eval)
|
||||
: masm_(masm), function_(NULL), script_(script), is_eval_(is_eval) {
|
||||
: masm_(masm),
|
||||
function_(NULL),
|
||||
script_(script),
|
||||
is_eval_(is_eval),
|
||||
true_label_(NULL),
|
||||
false_label_(NULL) {
|
||||
}
|
||||
|
||||
static Handle<Code> MakeCode(FunctionLiteral* fun,
|
||||
@ -59,6 +64,10 @@ class FastCodeGenerator: public AstVisitor {
|
||||
// If destination is TOS, just overwrite TOS with source.
|
||||
void DropAndMove(Expression::Context destination, Register source);
|
||||
|
||||
// Test the JavaScript value in source as if in a test context, compile
|
||||
// control flow to a pair of labels.
|
||||
void TestAndBranch(Register source, Label* true_label, Label* false_label);
|
||||
|
||||
void VisitDeclarations(ZoneList<Declaration*>* declarations);
|
||||
Handle<JSFunction> BuildBoilerplate(FunctionLiteral* fun);
|
||||
void DeclareGlobals(Handle<FixedArray> pairs);
|
||||
@ -85,6 +94,9 @@ class FastCodeGenerator: public AstVisitor {
|
||||
bool is_eval_;
|
||||
Label return_label_;
|
||||
|
||||
Label* true_label_;
|
||||
Label* false_label_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
|
||||
};
|
||||
|
||||
|
@ -117,6 +117,39 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::Move(Expression::Context context, Register source) {
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
break;
|
||||
case Expression::kValue:
|
||||
__ push(source);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
TestAndBranch(source, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
__ push(source);
|
||||
TestAndBranch(source, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
__ push(source);
|
||||
TestAndBranch(source, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
@ -126,6 +159,12 @@ void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
|
||||
case Expression::kValue:
|
||||
__ push(Operand(ebp, SlotOffset(source)));
|
||||
break;
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest: // Fall through.
|
||||
case Expression::kTestValue:
|
||||
__ mov(eax, Operand(ebp, SlotOffset(source)));
|
||||
Move(context, eax);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,6 +178,12 @@ void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
|
||||
case Expression::kValue:
|
||||
__ push(Immediate(expr->handle()));
|
||||
break;
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest: // Fall through.
|
||||
case Expression::kTestValue:
|
||||
__ mov(eax, expr->handle());
|
||||
Move(context, eax);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,10 +199,63 @@ void FastCodeGenerator::DropAndMove(Expression::Context context,
|
||||
case Expression::kValue:
|
||||
__ mov(Operand(esp, 0), source);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
ASSERT(!source.is(esp));
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
TestAndBranch(source, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
__ mov(Operand(esp, 0), source);
|
||||
TestAndBranch(source, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
__ mov(Operand(esp, 0), source);
|
||||
TestAndBranch(source, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::TestAndBranch(Register source,
|
||||
Label* true_label,
|
||||
Label* false_label) {
|
||||
ASSERT_NE(NULL, true_label);
|
||||
ASSERT_NE(NULL, false_label);
|
||||
// Use the shared ToBoolean stub to compile the value in the register into
|
||||
// control flow to the code generator's true and false labels. Perform
|
||||
// the fast checks assumed by the stub.
|
||||
__ cmp(source, Factory::undefined_value()); // The undefined value is false.
|
||||
__ j(equal, false_label);
|
||||
__ cmp(source, Factory::true_value()); // True is true.
|
||||
__ j(equal, true_label);
|
||||
__ cmp(source, Factory::false_value()); // False is false.
|
||||
__ j(equal, false_label);
|
||||
ASSERT_EQ(0, kSmiTag);
|
||||
__ test(source, Operand(source)); // The smi zero is false.
|
||||
__ j(zero, false_label);
|
||||
__ test(source, Immediate(kSmiTagMask)); // All other smis are true.
|
||||
__ j(zero, true_label);
|
||||
|
||||
// Call the stub for all other cases.
|
||||
__ push(source);
|
||||
ToBooleanStub stub;
|
||||
__ CallStub(&stub);
|
||||
__ test(eax, Operand(eax)); // The stub returns nonzero for true.
|
||||
__ j(not_zero, true_label);
|
||||
__ jmp(false_label);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
|
||||
// Call the runtime to declare the globals.
|
||||
__ push(esi); // The context is the first argument.
|
||||
@ -366,6 +464,28 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
case Expression::kValue:
|
||||
if (!result_saved) __ push(eax);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
if (result_saved) __ pop(eax);
|
||||
TestAndBranch(eax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(eax);
|
||||
TestAndBranch(eax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(eax);
|
||||
TestAndBranch(eax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -440,6 +560,28 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
case Expression::kValue:
|
||||
if (!result_saved) __ push(eax);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
if (result_saved) __ pop(eax);
|
||||
TestAndBranch(eax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(eax);
|
||||
TestAndBranch(eax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(eax);
|
||||
TestAndBranch(eax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -535,6 +677,34 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
// Case 'if (var = temp) ...'.
|
||||
__ pop(eax);
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
TestAndBranch(eax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
// Case '(var = temp) || ...' in value context.
|
||||
Label discard;
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
TestAndBranch(eax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
// Case '(var = temp) && ...' in value context.
|
||||
Label discard;
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
__ mov(Operand(ebp, SlotOffset(var->slot())), eax);
|
||||
TestAndBranch(eax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -740,10 +910,18 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case Expression::kEffect:
|
||||
break;
|
||||
case Expression::kValue:
|
||||
__ push(Immediate(Factory::undefined_value()));
|
||||
break;
|
||||
case Expression::kEffect:
|
||||
case Expression::kTestValue:
|
||||
// Value is false so it's needed.
|
||||
__ push(Immediate(Factory::undefined_value()));
|
||||
// Fall through.
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest:
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -798,90 +976,7 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
Expression::Context context = expr->context();
|
||||
Expression* left = expr->left();
|
||||
Expression* right = expr->right();
|
||||
|
||||
// Use the shared ToBoolean stub to find the boolean value of the
|
||||
// left-hand subexpression. Load the value into eax to perform some
|
||||
// inlined checks assumed by the stub.
|
||||
|
||||
// Compile the left-hand value into eax. Put it on the stack if we may
|
||||
// need it as the value of the whole expression.
|
||||
if (left->AsLiteral() != NULL) {
|
||||
__ mov(eax, left->AsLiteral()->handle());
|
||||
if (context == Expression::kValue) __ push(eax);
|
||||
} else {
|
||||
Visit(left);
|
||||
ASSERT_EQ(Expression::kValue, left->context());
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
// Pop the left-hand value into eax because we will not need it as the
|
||||
// final result.
|
||||
__ pop(eax);
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// Copy the left-hand value into eax because we may need it as the
|
||||
// final result.
|
||||
__ mov(eax, Operand(esp, 0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// The left-hand value is in eax. It is also on the stack iff the
|
||||
// destination location is value.
|
||||
|
||||
// Perform fast checks assumed by the stub.
|
||||
__ cmp(eax, Factory::undefined_value()); // The undefined value is false.
|
||||
__ j(equal, left_false);
|
||||
__ cmp(eax, Factory::true_value()); // True is true.
|
||||
__ j(equal, left_true);
|
||||
__ cmp(eax, Factory::false_value()); // False is false.
|
||||
__ j(equal, left_false);
|
||||
ASSERT_EQ(0, kSmiTag);
|
||||
__ test(eax, Operand(eax)); // The smi zero is false.
|
||||
__ j(zero, left_false);
|
||||
__ test(eax, Immediate(kSmiTagMask)); // All other smis are true.
|
||||
__ 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.
|
||||
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.
|
||||
if (context == Expression::kValue) {
|
||||
__ add(Operand(esp), Immediate(kPointerSize));
|
||||
}
|
||||
// Save or discard the right-hand value as needed.
|
||||
Visit(right);
|
||||
ASSERT_EQ(context, right->context());
|
||||
|
||||
__ bind(&done);
|
||||
}
|
||||
#undef __
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -125,6 +125,41 @@ void FastCodeGenerator::Generate(FunctionLiteral* fun) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FastCodeGenerator::Move(Expression::Context context, Register source) {
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
break;
|
||||
case Expression::kValue:
|
||||
__ push(source);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
TestAndBranch(source, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
__ push(source);
|
||||
TestAndBranch(source, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
__ push(source);
|
||||
TestAndBranch(source, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
@ -134,6 +169,12 @@ void FastCodeGenerator::Move(Expression::Context context, Slot* source) {
|
||||
case Expression::kValue:
|
||||
__ push(Operand(rbp, SlotOffset(source)));
|
||||
break;
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest: // Fall through.
|
||||
case Expression::kTestValue:
|
||||
__ movq(rax, Operand(rbp, SlotOffset(source)));
|
||||
Move(context, rax);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,6 +188,12 @@ void FastCodeGenerator::Move(Expression::Context context, Literal* expr) {
|
||||
case Expression::kValue:
|
||||
__ Push(expr->handle());
|
||||
break;
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest: // Fall through.
|
||||
case Expression::kTestValue:
|
||||
__ Move(rax, expr->handle());
|
||||
Move(context, rax);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -162,10 +209,65 @@ void FastCodeGenerator::DropAndMove(Expression::Context context,
|
||||
case Expression::kValue:
|
||||
__ movq(Operand(rsp, 0), source);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
ASSERT(!source.is(rsp));
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
TestAndBranch(source, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
__ movq(Operand(rsp, 0), source);
|
||||
TestAndBranch(source, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
__ movq(Operand(rsp, 0), source);
|
||||
TestAndBranch(source, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::TestAndBranch(Register source,
|
||||
Label* true_label,
|
||||
Label* false_label) {
|
||||
ASSERT_NE(NULL, true_label);
|
||||
ASSERT_NE(NULL, false_label);
|
||||
// Use the shared ToBoolean stub to compile the value in the register into
|
||||
// control flow to the code generator's true and false labels. Perform
|
||||
// the fast checks assumed by the stub.
|
||||
|
||||
// The undefined value is false.
|
||||
__ CompareRoot(source, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, false_label);
|
||||
__ CompareRoot(source, Heap::kTrueValueRootIndex); // True is true.
|
||||
__ j(equal, true_label);
|
||||
__ CompareRoot(source, Heap::kFalseValueRootIndex); // False is false.
|
||||
__ j(equal, false_label);
|
||||
ASSERT_EQ(0, kSmiTag);
|
||||
__ SmiCompare(source, Smi::FromInt(0)); // The smi zero is false.
|
||||
__ j(equal, false_label);
|
||||
Condition is_smi = masm_->CheckSmi(source); // All other smis are true.
|
||||
__ j(is_smi, true_label);
|
||||
|
||||
// Call the stub for all other cases.
|
||||
__ push(source);
|
||||
ToBooleanStub stub;
|
||||
__ CallStub(&stub);
|
||||
__ testq(rax, rax); // The stub returns nonzero for true.
|
||||
__ j(not_zero, true_label);
|
||||
__ jmp(false_label);
|
||||
}
|
||||
|
||||
|
||||
void FastCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
|
||||
// Call the runtime to declare the globals.
|
||||
__ push(rsi); // The context is the first argument.
|
||||
@ -376,6 +478,28 @@ void FastCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
case Expression::kValue:
|
||||
if (!result_saved) __ push(rax);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
if (result_saved) __ pop(rax);
|
||||
TestAndBranch(rax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(rax);
|
||||
TestAndBranch(rax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(rax);
|
||||
TestAndBranch(rax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -450,6 +574,28 @@ void FastCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
|
||||
case Expression::kValue:
|
||||
if (!result_saved) __ push(rax);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
if (result_saved) __ pop(rax);
|
||||
TestAndBranch(rax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(rax);
|
||||
TestAndBranch(rax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
Label discard;
|
||||
if (!result_saved) __ push(rax);
|
||||
TestAndBranch(rax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -544,6 +690,34 @@ void FastCodeGenerator::VisitAssignment(Assignment* expr) {
|
||||
__ movq(kScratchRegister, Operand(rsp, 0));
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), kScratchRegister);
|
||||
break;
|
||||
case Expression::kTest:
|
||||
// Case 'if (var = temp) ...'.
|
||||
__ pop(rax);
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
TestAndBranch(rax, true_label_, false_label_);
|
||||
break;
|
||||
case Expression::kValueTest: {
|
||||
// Case '(var = temp) || ...' in value context.
|
||||
Label discard;
|
||||
__ movq(rax, Operand(rsp, 0));
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
TestAndBranch(rax, true_label_, &discard);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
case Expression::kTestValue: {
|
||||
// Case '(var = temp) && ...' in value context.
|
||||
Label discard;
|
||||
__ movq(rax, Operand(rsp, 0));
|
||||
__ movq(Operand(rbp, SlotOffset(var->slot())), rax);
|
||||
TestAndBranch(rax, &discard, false_label_);
|
||||
__ bind(&discard);
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
__ jmp(true_label_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -752,10 +926,18 @@ void FastCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
case Expression::kEffect:
|
||||
break;
|
||||
case Expression::kValue:
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||
break;
|
||||
case Expression::kEffect:
|
||||
case Expression::kTestValue:
|
||||
// Value is false so it's needed.
|
||||
__ PushRoot(Heap::kUndefinedValueRootIndex);
|
||||
// Fall through.
|
||||
case Expression::kTest: // Fall through.
|
||||
case Expression::kValueTest:
|
||||
__ jmp(false_label_);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -810,93 +992,4 @@ void FastCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
Expression::Context context = expr->context();
|
||||
Expression* left = expr->left();
|
||||
Expression* right = expr->right();
|
||||
|
||||
// Use the shared ToBoolean stub to find the boolean value of the
|
||||
// left-hand subexpression. Load the value into rax to perform some
|
||||
// inlined checks assumed by the stub.
|
||||
|
||||
// Compile the left-hand value into rax. Put it on the stack if we may
|
||||
// need it as the value of the whole expression.
|
||||
if (left->AsLiteral() != NULL) {
|
||||
__ Move(rax, left->AsLiteral()->handle());
|
||||
if (context == Expression::kValue) __ push(rax);
|
||||
} else {
|
||||
Visit(left);
|
||||
ASSERT_EQ(Expression::kValue, left->context());
|
||||
switch (context) {
|
||||
case Expression::kUninitialized:
|
||||
UNREACHABLE();
|
||||
case Expression::kEffect:
|
||||
// Pop the left-hand value into rax because we will not need it as the
|
||||
// final result.
|
||||
__ pop(rax);
|
||||
break;
|
||||
case Expression::kValue:
|
||||
// Copy the left-hand value into rax because we may need it as the
|
||||
// final result.
|
||||
__ movq(rax, Operand(rsp, 0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
// The left-hand value is in rax. It is also on the stack iff the
|
||||
// destination location is value.
|
||||
|
||||
// Perform fast checks assumed by the stub.
|
||||
// The undefined value is false.
|
||||
__ CompareRoot(rax, Heap::kUndefinedValueRootIndex);
|
||||
__ j(equal, left_false);
|
||||
__ CompareRoot(rax, Heap::kTrueValueRootIndex); // True is true.
|
||||
__ j(equal, left_true);
|
||||
__ CompareRoot(rax, Heap::kFalseValueRootIndex); // False is false.
|
||||
__ j(equal, left_false);
|
||||
ASSERT(kSmiTag == 0);
|
||||
__ SmiCompare(rax, Smi::FromInt(0)); // The smi zero is false.
|
||||
__ j(equal, left_false);
|
||||
Condition is_smi = masm_->CheckSmi(rax); // All other smis are true.
|
||||
__ 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.
|
||||
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.
|
||||
if (context == Expression::kValue) {
|
||||
__ addq(rsp, Immediate(kPointerSize));
|
||||
}
|
||||
// Save or discard the right-hand value as needed.
|
||||
Visit(right);
|
||||
ASSERT_EQ(context, right->context());
|
||||
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
Loading…
Reference in New Issue
Block a user