}
-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;
}
}
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;
}
}
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.
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;
+ }
}
}
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;
+ }
}
}
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())));
}
}
}
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;
}
-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
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) {}
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;
namespace v8 {
namespace internal {
+#define __ ACCESS_MASM(masm_)
+
Handle<Code> FastCodeGenerator::MakeCode(FunctionLiteral* fun,
Handle<Script> script,
bool is_eval) {
}
-// 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();
}
+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();
}
}
+#undef __
+
+
} } // namespace v8::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,
// 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);
bool is_eval_;
Label return_label_;
+ Label* true_label_;
+ Label* false_label_;
+
DISALLOW_COPY_AND_ASSIGN(FastCodeGenerator);
};
}
+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:
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;
}
}
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;
}
}
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.
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;
+ }
}
}
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;
+ }
}
}
__ 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;
+ }
}
}
}
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;
}
-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
}
+
+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:
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;
}
}
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;
}
}
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.
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;
+ }
}
}
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;
+ }
}
}
__ 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;
+ }
}
}
}
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;
}
-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