Simplified the full codegens by removing the Expression::kTestValue

and Expression::kValueTest. At the same time, prepare the code for
keeping track of fall through labels to avoid unnecessary jumps.
Review URL: http://codereview.chromium.org/3152042

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5320 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
kasperl@chromium.org 2010-08-23 12:55:29 +00:00
parent 3a7d256596
commit d0bdc7956e
6 changed files with 214 additions and 948 deletions

View File

@ -266,16 +266,10 @@ void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
}
break;
case Expression::kValueTest:
case Expression::kTestValue:
// Push an extra copy of the value in case it's needed.
__ push(reg);
// Fall through.
case Expression::kTest:
// We always call the runtime on ARM, so push the value as argument.
__ push(reg);
DoTest(context);
// For simplicity we always test the accumulator register.
if (!reg.is(result_register())) __ mov(result_register(), reg);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -290,8 +284,6 @@ void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
break;
case Expression::kValue:
case Expression::kTest:
case Expression::kValueTest:
case Expression::kTestValue:
// On ARM we have to move the value into a register to do anything
// with it.
Move(result_register(), slot);
@ -310,8 +302,6 @@ void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
// Nothing to do.
case Expression::kValue:
case Expression::kTest:
case Expression::kValueTest:
case Expression::kTestValue:
// On ARM we have to move the value into a register to do anything
// with it.
__ mov(result_register(), Operand(lit->handle()));
@ -340,15 +330,9 @@ void FullCodeGenerator::ApplyTOS(Expression::Context context) {
}
break;
case Expression::kValueTest:
case Expression::kTestValue:
// Duplicate the value on the stack in case it's needed.
__ ldr(ip, MemOperand(sp));
__ push(ip);
// Fall through.
case Expression::kTest:
DoTest(context);
__ pop(result_register());
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -381,22 +365,9 @@ void FullCodeGenerator::DropAndApply(int count,
break;
case Expression::kTest:
if (count > 1) __ Drop(count - 1);
__ str(reg, MemOperand(sp));
DoTest(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
if (count == 1) {
__ str(reg, MemOperand(sp));
__ push(reg);
} else { // count > 1
__ Drop(count - 2);
__ str(reg, MemOperand(sp, kPointerSize));
__ str(reg, MemOperand(sp));
}
DoTest(context);
__ Drop(count);
if (!reg.is(result_register())) __ mov(result_register(), reg);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -422,14 +393,6 @@ void FullCodeGenerator::PrepareTest(Label* materialize_true,
*if_true = true_label_;
*if_false = false_label_;
break;
case Expression::kValueTest:
*if_true = materialize_true;
*if_false = false_label_;
break;
case Expression::kTestValue:
*if_true = true_label_;
*if_false = materialize_false;
break;
}
}
@ -471,34 +434,6 @@ void FullCodeGenerator::Apply(Expression::Context context,
case Expression::kTest:
break;
case Expression::kValueTest:
__ bind(materialize_true);
switch (location_) {
case kAccumulator:
__ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
break;
case kStack:
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ push(ip);
break;
}
__ jmp(true_label_);
break;
case Expression::kTestValue:
__ bind(materialize_false);
switch (location_) {
case kAccumulator:
__ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
break;
case kStack:
__ LoadRoot(ip, Heap::kFalseValueRootIndex);
__ push(ip);
break;
}
__ jmp(false_label_);
break;
}
}
@ -529,101 +464,34 @@ void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
case Expression::kTest:
__ b(flag ? true_label_ : false_label_);
break;
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
// If value is false it's needed.
if (!flag) __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
break;
case kStack:
// If value is false it's needed.
if (!flag) {
__ LoadRoot(ip, Heap::kFalseValueRootIndex);
__ push(ip);
}
break;
}
__ b(flag ? true_label_ : false_label_);
break;
case Expression::kValueTest:
switch (location_) {
case kAccumulator:
// If value is true it's needed.
if (flag) __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
break;
case kStack:
// If value is true it's needed.
if (flag) {
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ push(ip);
}
break;
}
__ b(flag ? true_label_ : false_label_);
break;
}
}
void FullCodeGenerator::DoTest(Expression::Context context) {
// The value to test is pushed on the stack, and duplicated on the stack
// if necessary (for value/test and test/value contexts).
ASSERT_NE(NULL, true_label_);
ASSERT_NE(NULL, false_label_);
void FullCodeGenerator::DoTest(Label* if_true,
Label* if_false,
Label* fall_through) {
// Call the runtime to find the boolean value of the source and then
// translate it into control flow to the pair of labels.
__ push(result_register());
__ CallRuntime(Runtime::kToBool, 1);
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(r0, ip);
Split(eq, if_true, if_false, fall_through);
}
// Complete based on the context.
switch (context) {
case Expression::kUninitialized:
case Expression::kEffect:
case Expression::kValue:
UNREACHABLE();
case Expression::kTest:
__ b(eq, true_label_);
__ jmp(false_label_);
break;
case Expression::kValueTest: {
Label discard;
switch (location_) {
case kAccumulator:
__ b(ne, &discard);
__ pop(result_register());
__ jmp(true_label_);
break;
case kStack:
__ b(eq, true_label_);
break;
}
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
}
case Expression::kTestValue: {
Label discard;
switch (location_) {
case kAccumulator:
__ b(eq, &discard);
__ pop(result_register());
__ jmp(false_label_);
break;
case kStack:
__ b(ne, false_label_);
break;
}
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
break;
}
void FullCodeGenerator::Split(Condition cc,
Label* if_true,
Label* if_false,
Label* fall_through) {
if (if_false == fall_through) {
__ b(cc, if_true);
} else if (if_true == fall_through) {
__ b(NegateCondition(cc), if_false);
} else {
__ b(cc, if_true);
__ b(if_false);
}
}
@ -1107,28 +975,33 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
// r2 = RegExp pattern
// r1 = RegExp flags
// r0 = temp + materialized value (RegExp literal)
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
__ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
__ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ ldr(r0, FieldMemOperand(r4, literal_offset));
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
__ cmp(r0, ip);
__ b(ne, &materialized);
// Create regexp literal using runtime function.
// Result will be in r0.
__ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
__ mov(r2, Operand(expr->pattern()));
__ mov(r1, Operand(expr->flags()));
__ Push(r4, r3, r2, r1);
__ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
__ bind(&materialized);
int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
__ push(r0);
__ mov(r0, Operand(Smi::FromInt(size)));
__ push(r0);
__ CallRuntime(Runtime::kAllocateInNewSpace, 1);
// After this, registers are used as follows:
// r0: Newly allocated regexp.
// r1: Materialized regexp
// r1: Materialized regexp.
// r2: temp.
__ pop(r1);
__ CopyFields(r0, r1, r2.bit(), size / kPointerSize);
@ -1885,8 +1758,7 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
__ tst(r0, Operand(kSmiTagMask | 0x80000000));
__ b(eq, if_true);
__ b(if_false);
Split(eq, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -1914,8 +1786,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));
__ b(le, if_true);
__ b(if_false);
Split(le, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -1933,8 +1804,7 @@ void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
__ b(ge, if_true);
__ b(if_false);
Split(ge, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -1954,8 +1824,7 @@ void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
__ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
__ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
__ tst(r1, Operand(1 << Map::kIsUndetectable));
__ b(ne, if_true);
__ b(if_false);
Split(ne, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -1993,8 +1862,7 @@ void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
__ b(eq, if_true);
__ b(if_false);
Split(eq, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2012,8 +1880,7 @@ void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
__ b(eq, if_true);
__ b(if_false);
Split(eq, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2031,8 +1898,7 @@ void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
__ BranchOnSmi(r0, if_false);
__ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
__ b(eq, if_true);
__ b(if_false);
Split(eq, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2061,8 +1927,7 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
__ bind(&check_frame_marker);
__ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset));
__ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
__ b(eq, if_true);
__ b(if_false);
Split(eq, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2082,8 +1947,7 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
__ pop(r1);
__ cmp(r0, r1);
__ b(eq, if_true);
__ b(if_false);
Split(eq, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2752,19 +2616,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
break;
}
break;
case Expression::kTestValue:
// Value is false so it's needed.
__ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
switch (location_) {
case kAccumulator:
break;
case kStack:
__ push(result_register());
break;
}
// Fall through.
case Expression::kTest:
case Expression::kValueTest:
__ jmp(false_label_);
break;
}
@ -2945,8 +2797,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
break;
case Expression::kValue:
case Expression::kTest:
case Expression::kValueTest:
case Expression::kTestValue:
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
@ -3034,41 +2884,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
VisitForEffect(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:
VisitForValue(expr->left(), kStack);
VisitForValue(expr->right(), kAccumulator);
EmitBinaryOp(expr->op(), context_);
break;
default:
UNREACHABLE();
}
}
void FullCodeGenerator::EmitNullCompare(bool strict,
Register obj,
Register null_const,
@ -3077,7 +2892,7 @@ void FullCodeGenerator::EmitNullCompare(bool strict,
Register scratch) {
__ cmp(obj, null_const);
if (strict) {
__ b(eq, if_true);
Split(eq, if_true, if_false, NULL);
} else {
__ b(eq, if_true);
__ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
@ -3088,9 +2903,8 @@ void FullCodeGenerator::EmitNullCompare(bool strict,
__ ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
__ ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
__ tst(scratch, Operand(1 << Map::kIsUndetectable));
__ b(ne, if_true);
Split(ne, if_true, if_false, NULL);
}
__ jmp(if_false);
}
@ -3112,17 +2926,16 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
__ InvokeBuiltin(Builtins::IN, CALL_JS);
__ LoadRoot(ip, Heap::kTrueValueRootIndex);
__ cmp(r0, ip);
__ b(eq, if_true);
__ jmp(if_false);
Split(eq, if_true, if_false, NULL);
break;
case Token::INSTANCEOF: {
VisitForValue(expr->right(), kStack);
InstanceofStub stub;
__ CallStub(&stub);
// The stub returns 0 for true.
__ tst(r0, r0);
__ b(eq, if_true); // The stub returns 0 for true.
__ jmp(if_false);
Split(eq, if_true, if_false, NULL);
break;
}
@ -3191,8 +3004,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
CompareStub stub(cc, strict, kBothCouldBeNaN, true, r1, r0);
__ CallStub(&stub);
__ cmp(r0, Operand(0));
__ b(cc, if_true);
__ jmp(if_false);
Split(cc, if_true, if_false, NULL);
}
}

View File

@ -201,13 +201,7 @@ class Expression: public AstNode {
// 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
kTest
};
Expression() : bitfields_(0) {}

View File

@ -865,6 +865,41 @@ void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
}
void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
VisitForEffect(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:
VisitForValue(expr->left(), kStack);
VisitForValue(expr->right(), kAccumulator);
EmitBinaryOp(expr->op(), context_);
break;
default:
UNREACHABLE();
}
}
void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
Label eval_right, done;
@ -879,23 +914,11 @@ void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
VisitForControl(expr->left(), &done, &eval_right);
break;
case Expression::kValue:
VisitForValueControl(expr->left(),
location_,
&done,
&eval_right);
VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
break;
case Expression::kTest:
VisitForControl(expr->left(), true_label_, &eval_right);
break;
case Expression::kValueTest:
VisitForValueControl(expr->left(),
location_,
true_label_,
&eval_right);
break;
case Expression::kTestValue:
VisitForControl(expr->left(), true_label_, &eval_right);
break;
}
} else {
ASSERT_EQ(Token::AND, expr->op());
@ -906,23 +929,11 @@ void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
VisitForControl(expr->left(), &eval_right, &done);
break;
case Expression::kValue:
VisitForControlValue(expr->left(),
location_,
&eval_right,
&done);
VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
break;
case Expression::kTest:
VisitForControl(expr->left(), &eval_right, false_label_);
break;
case Expression::kValueTest:
VisitForControl(expr->left(), &eval_right, false_label_);
break;
case Expression::kTestValue:
VisitForControlValue(expr->left(),
location_,
&eval_right,
false_label_);
break;
}
}
@ -933,6 +944,43 @@ void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
}
void FullCodeGenerator::VisitLogicalForValue(Expression* expr,
Token::Value op,
Location where,
Label* done) {
ASSERT(op == Token::AND || op == Token::OR);
VisitForValue(expr, kAccumulator);
__ push(result_register());
Label discard;
switch (where) {
case kAccumulator: {
Label restore;
if (op == Token::OR) {
DoTest(&restore, &discard, &restore);
} else {
DoTest(&discard, &restore, &restore);
}
__ bind(&restore);
__ pop(result_register());
__ jmp(done);
break;
}
case kStack: {
if (op == Token::OR) {
DoTest(done, &discard, &discard);
} else {
DoTest(&discard, done, &discard);
}
break;
}
}
__ bind(&discard);
__ Drop(1);
}
void FullCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
Breakable nested_statement(this, stmt);

View File

@ -296,7 +296,14 @@ class FullCodeGenerator: public AstVisitor {
// Helper function to convert a pure value into a test context. The value
// is expected on the stack or the accumulator, depending on the platform.
// See the platform-specific implementation for details.
void DoTest(Expression::Context context);
void DoTest(Label* if_true, Label* if_false, Label* fall_through);
// Helper function to split control flow and avoid a branch to the
// fall-through label if it is set up.
void Split(Condition cc,
Label* if_true,
Label* if_false,
Label* fall_through);
void Move(Slot* dst, Register source, Register scratch1, Register scratch2);
void Move(Register dst, Slot* source);
@ -336,44 +343,6 @@ class FullCodeGenerator: public AstVisitor {
false_label_ = saved_false;
}
void VisitForValueControl(Expression* expr,
Location where,
Label* if_true,
Label* if_false) {
Expression::Context saved_context = context_;
Location saved_location = location_;
Label* saved_true = true_label_;
Label* saved_false = false_label_;
context_ = Expression::kValueTest;
location_ = where;
true_label_ = if_true;
false_label_ = if_false;
Visit(expr);
context_ = saved_context;
location_ = saved_location;
true_label_ = saved_true;
false_label_ = saved_false;
}
void VisitForControlValue(Expression* expr,
Location where,
Label* if_true,
Label* if_false) {
Expression::Context saved_context = context_;
Location saved_location = location_;
Label* saved_true = true_label_;
Label* saved_false = false_label_;
context_ = Expression::kTestValue;
location_ = where;
true_label_ = if_true;
false_label_ = if_false;
Visit(expr);
context_ = saved_context;
location_ = saved_location;
true_label_ = saved_true;
false_label_ = saved_false;
}
void VisitDeclarations(ZoneList<Declaration*>* declarations);
void DeclareGlobals(Handle<FixedArray> pairs);
@ -491,6 +460,11 @@ class FullCodeGenerator: public AstVisitor {
#undef DECLARE_VISIT
// Handles the shortcutted logical binary operations in VisitBinaryOperation.
void EmitLogicalOperation(BinaryOperation* expr);
void VisitLogicalForValue(Expression* expr,
Token::Value op,
Location where,
Label* done);
MacroAssembler* masm_;
CompilationInfo* info_;

View File

@ -246,20 +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(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
if (!reg.is(result_register())) __ mov(result_register(), reg);
switch (location_) {
case kAccumulator:
break;
case kStack:
__ push(result_register());
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -289,20 +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(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
Move(result_register(), slot);
switch (location_) {
case kAccumulator:
break;
case kStack:
__ push(result_register());
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -330,20 +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(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
__ mov(result_register(), lit->handle());
switch (location_) {
case kAccumulator:
break;
case kStack:
__ push(result_register());
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -371,20 +332,7 @@ void FullCodeGenerator::ApplyTOS(Expression::Context context) {
case Expression::kTest:
// For simplicity we always test the accumulator register.
__ pop(result_register());
DoTest(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
__ pop(result_register());
break;
case kStack:
__ mov(result_register(), Operand(esp, 0));
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -420,23 +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(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
__ Drop(count);
if (!reg.is(result_register())) __ mov(result_register(), reg);
break;
case kStack:
if (count > 1) __ Drop(count - 1);
__ mov(result_register(), reg);
__ mov(Operand(esp, 0), result_register());
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -463,14 +395,6 @@ void FullCodeGenerator::PrepareTest(Label* materialize_true,
*if_true = true_label_;
*if_false = false_label_;
break;
case Expression::kValueTest:
*if_true = materialize_true;
*if_false = false_label_;
break;
case Expression::kTestValue:
*if_true = true_label_;
*if_false = materialize_false;
break;
}
}
@ -510,32 +434,6 @@ void FullCodeGenerator::Apply(Expression::Context context,
case Expression::kTest:
break;
case Expression::kValueTest:
__ bind(materialize_true);
switch (location_) {
case kAccumulator:
__ mov(result_register(), Factory::true_value());
break;
case kStack:
__ push(Immediate(Factory::true_value()));
break;
}
__ jmp(true_label_);
break;
case Expression::kTestValue:
__ bind(materialize_false);
switch (location_) {
case kAccumulator:
__ mov(result_register(), Factory::false_value());
break;
case kStack:
__ push(Immediate(Factory::false_value()));
break;
}
__ jmp(false_label_);
break;
}
}
@ -565,76 +463,13 @@ void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
case Expression::kTest:
__ jmp(flag ? true_label_ : false_label_);
break;
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
// If value is false it's needed.
if (!flag) __ mov(result_register(), Factory::false_value());
break;
case kStack:
// If value is false it's needed.
if (!flag) __ push(Immediate(Factory::false_value()));
break;
}
__ jmp(flag ? true_label_ : false_label_);
break;
case Expression::kValueTest:
switch (location_) {
case kAccumulator:
// If value is true it's needed.
if (flag) __ mov(result_register(), Factory::true_value());
break;
case kStack:
// If value is true it's needed.
if (flag) __ push(Immediate(Factory::true_value()));
break;
}
__ jmp(flag ? true_label_ : false_label_);
break;
}
}
void FullCodeGenerator::DoTest(Expression::Context context) {
// The value to test is in the accumulator. If the value might be needed
// on the stack (value/test and test/value contexts with a stack location
// desired), then the value is already duplicated on the stack.
ASSERT_NE(NULL, true_label_);
ASSERT_NE(NULL, false_label_);
// In value/test and test/value expression contexts with stack as the
// desired location, there is already an extra value on the stack. Use a
// label to discard it if unneeded.
Label discard;
Label* if_true = true_label_;
Label* if_false = false_label_;
switch (context) {
case Expression::kUninitialized:
case Expression::kEffect:
case Expression::kValue:
UNREACHABLE();
case Expression::kTest:
break;
case Expression::kValueTest:
switch (location_) {
case kAccumulator:
break;
case kStack:
if_false = &discard;
break;
}
break;
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
break;
case kStack:
if_true = &discard;
break;
}
break;
}
void FullCodeGenerator::DoTest(Label* if_true,
Label* if_false,
Label* fall_through) {
// Emit the inlined tests assumed by the stub.
__ cmp(result_register(), Factory::undefined_value());
__ j(equal, if_false);
@ -648,83 +483,28 @@ void FullCodeGenerator::DoTest(Expression::Context context) {
__ test(result_register(), Immediate(kSmiTagMask));
__ j(zero, if_true);
// Save a copy of the value if it may be needed and isn't already saved.
switch (context) {
case Expression::kUninitialized:
case Expression::kEffect:
case Expression::kValue:
UNREACHABLE();
case Expression::kTest:
break;
case Expression::kValueTest:
switch (location_) {
case kAccumulator:
__ push(result_register());
break;
case kStack:
break;
}
break;
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
__ push(result_register());
break;
case kStack:
break;
}
break;
}
// Call the ToBoolean stub for all other cases.
ToBooleanStub stub;
__ push(result_register());
__ CallStub(&stub);
__ test(eax, Operand(eax));
// The stub returns nonzero for true. Complete based on the context.
switch (context) {
case Expression::kUninitialized:
case Expression::kEffect:
case Expression::kValue:
UNREACHABLE();
// The stub returns nonzero for true.
Split(not_zero, if_true, if_false, fall_through);
}
case Expression::kTest:
__ j(not_zero, true_label_);
__ jmp(false_label_);
break;
case Expression::kValueTest:
switch (location_) {
case kAccumulator:
__ j(zero, &discard);
__ pop(result_register());
__ jmp(true_label_);
break;
case kStack:
__ j(not_zero, true_label_);
break;
}
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
__ j(not_zero, &discard);
__ pop(result_register());
__ jmp(false_label_);
break;
case kStack:
__ j(zero, false_label_);
break;
}
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
break;
void FullCodeGenerator::Split(Condition cc,
Label* if_true,
Label* if_false,
Label* fall_through) {
if (if_false == fall_through) {
__ j(cc, if_true);
} else if (if_true == fall_through) {
__ j(NegateCondition(cc), if_false);
} else {
__ j(cc, if_true);
__ jmp(if_false);
}
}
@ -1203,7 +983,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
__ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
__ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ mov(ebx, FieldOperand(ecx, literal_offset));
__ cmp(ebx, Factory::undefined_value());
__ j(not_equal, &materialized);
@ -1961,8 +1741,7 @@ void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, if_true);
__ jmp(if_false);
Split(zero, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -1979,8 +1758,7 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
__ test(eax, Immediate(kSmiTagMask | 0x80000000));
__ j(zero, if_true);
__ jmp(if_false);
Split(zero, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2009,8 +1787,7 @@ void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
__ cmp(ecx, FIRST_JS_OBJECT_TYPE);
__ j(below, if_false);
__ cmp(ecx, LAST_JS_OBJECT_TYPE);
__ j(below_equal, if_true);
__ jmp(if_false);
Split(below_equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2029,8 +1806,7 @@ void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
__ test(eax, Immediate(kSmiTagMask));
__ j(equal, if_false);
__ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
__ j(above_equal, if_true);
__ jmp(if_false);
Split(above_equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2051,8 +1827,7 @@ void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
__ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
__ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
__ test(ebx, Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, if_true);
__ jmp(if_false);
Split(not_zero, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2090,8 +1865,7 @@ void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
__ test(eax, Immediate(kSmiTagMask));
__ j(zero, if_false);
__ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2110,8 +1884,7 @@ void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
__ test(eax, Immediate(kSmiTagMask));
__ j(equal, if_false);
__ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2130,8 +1903,7 @@ void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
__ test(eax, Immediate(kSmiTagMask));
__ j(equal, if_false);
__ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2160,8 +1932,7 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
__ bind(&check_frame_marker);
__ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2181,8 +1952,7 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
__ pop(ebx);
__ cmp(eax, Operand(ebx));
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2845,19 +2615,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
break;
}
break;
case Expression::kTestValue:
// Value is false so it's needed.
switch (location_) {
case kAccumulator:
__ mov(result_register(), Factory::undefined_value());
break;
case kStack:
__ push(Immediate(Factory::undefined_value()));
break;
}
// Fall through.
case Expression::kTest:
case Expression::kValueTest:
__ jmp(false_label_);
break;
}
@ -3038,8 +2796,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
break;
case Expression::kValue:
case Expression::kTest:
case Expression::kValueTest:
case Expression::kTestValue:
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
@ -3146,41 +2902,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
VisitForEffect(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:
VisitForValue(expr->left(), kStack);
VisitForValue(expr->right(), kAccumulator);
EmitBinaryOp(expr->op(), context_);
break;
default:
UNREACHABLE();
}
}
void FullCodeGenerator::EmitNullCompare(bool strict,
Register obj,
Register null_const,
@ -3189,7 +2910,7 @@ void FullCodeGenerator::EmitNullCompare(bool strict,
Register scratch) {
__ cmp(obj, Operand(null_const));
if (strict) {
__ j(equal, if_true);
Split(equal, if_true, if_false, NULL);
} else {
__ j(equal, if_true);
__ cmp(obj, Factory::undefined_value());
@ -3200,9 +2921,8 @@ void FullCodeGenerator::EmitNullCompare(bool strict,
__ mov(scratch, FieldOperand(obj, HeapObject::kMapOffset));
__ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
__ test(scratch, Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, if_true);
Split(not_zero, if_true, if_false, NULL);
}
__ jmp(if_false);
}
@ -3223,8 +2943,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
VisitForValue(expr->right(), kStack);
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
__ cmp(eax, Factory::true_value());
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
break;
case Token::INSTANCEOF: {
@ -3232,8 +2951,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
InstanceofStub stub;
__ CallStub(&stub);
__ test(eax, Operand(eax));
__ j(zero, if_true); // The stub returns 0 for true.
__ jmp(if_false);
// The stub returns 0 for true.
Split(zero, if_true, if_false, NULL);
break;
}
@ -3304,8 +3023,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
CompareStub stub(cc, strict);
__ CallStub(&stub);
__ test(eax, Operand(eax));
__ j(cc, if_true);
__ jmp(if_false);
Split(cc, if_true, if_false, NULL);
}
}

View File

@ -253,20 +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(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
if (!reg.is(result_register())) __ movq(result_register(), reg);
switch (location_) {
case kAccumulator:
break;
case kStack:
__ push(result_register());
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -295,20 +282,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
case Expression::kTest:
Move(result_register(), slot);
DoTest(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
Move(result_register(), slot);
switch (location_) {
case kAccumulator:
break;
case kStack:
__ push(result_register());
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -334,20 +308,7 @@ void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
case Expression::kTest:
__ Move(result_register(), lit->handle());
DoTest(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
__ Move(result_register(), lit->handle());
switch (location_) {
case kAccumulator:
break;
case kStack:
__ push(result_register());
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -374,20 +335,7 @@ void FullCodeGenerator::ApplyTOS(Expression::Context context) {
case Expression::kTest:
__ pop(result_register());
DoTest(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
__ pop(result_register());
break;
case kStack:
__ movq(result_register(), Operand(rsp, 0));
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -422,23 +370,7 @@ void FullCodeGenerator::DropAndApply(int count,
case Expression::kTest:
__ Drop(count);
if (!reg.is(result_register())) __ movq(result_register(), reg);
DoTest(context);
break;
case Expression::kValueTest:
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
__ Drop(count);
if (!reg.is(result_register())) __ movq(result_register(), reg);
break;
case kStack:
if (count > 1) __ Drop(count - 1);
__ movq(result_register(), reg);
__ movq(Operand(rsp, 0), result_register());
break;
}
DoTest(context);
DoTest(true_label_, false_label_, NULL);
break;
}
}
@ -465,14 +397,6 @@ void FullCodeGenerator::PrepareTest(Label* materialize_true,
*if_true = true_label_;
*if_false = false_label_;
break;
case Expression::kValueTest:
*if_true = materialize_true;
*if_false = false_label_;
break;
case Expression::kTestValue:
*if_true = true_label_;
*if_false = materialize_false;
break;
}
}
@ -512,32 +436,6 @@ void FullCodeGenerator::Apply(Expression::Context context,
case Expression::kTest:
break;
case Expression::kValueTest:
__ bind(materialize_true);
switch (location_) {
case kAccumulator:
__ Move(result_register(), Factory::true_value());
break;
case kStack:
__ Push(Factory::true_value());
break;
}
__ jmp(true_label_);
break;
case Expression::kTestValue:
__ bind(materialize_false);
switch (location_) {
case kAccumulator:
__ Move(result_register(), Factory::false_value());
break;
case kStack:
__ Push(Factory::false_value());
break;
}
__ jmp(false_label_);
break;
}
}
@ -567,76 +465,13 @@ void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
case Expression::kTest:
__ jmp(flag ? true_label_ : false_label_);
break;
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
// If value is false it's needed.
if (!flag) __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
break;
case kStack:
// If value is false it's needed.
if (!flag) __ PushRoot(Heap::kFalseValueRootIndex);
break;
}
__ jmp(flag ? true_label_ : false_label_);
break;
case Expression::kValueTest:
switch (location_) {
case kAccumulator:
// If value is true it's needed.
if (flag) __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
break;
case kStack:
// If value is true it's needed.
if (flag) __ PushRoot(Heap::kTrueValueRootIndex);
break;
}
__ jmp(flag ? true_label_ : false_label_);
break;
}
}
void FullCodeGenerator::DoTest(Expression::Context context) {
// The value to test is in the accumulator. If the value might be needed
// on the stack (value/test and test/value contexts with a stack location
// desired), then the value is already duplicated on the stack.
ASSERT_NE(NULL, true_label_);
ASSERT_NE(NULL, false_label_);
// In value/test and test/value expression contexts with stack as the
// desired location, there is already an extra value on the stack. Use a
// label to discard it if unneeded.
Label discard;
Label* if_true = true_label_;
Label* if_false = false_label_;
switch (context) {
case Expression::kUninitialized:
case Expression::kEffect:
case Expression::kValue:
UNREACHABLE();
case Expression::kTest:
break;
case Expression::kValueTest:
switch (location_) {
case kAccumulator:
break;
case kStack:
if_false = &discard;
break;
}
break;
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
break;
case kStack:
if_true = &discard;
break;
}
break;
}
void FullCodeGenerator::DoTest(Label* if_true,
Label* if_false,
Label* fall_through) {
// Emit the inlined tests assumed by the stub.
__ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex);
__ j(equal, if_false);
@ -650,83 +485,28 @@ void FullCodeGenerator::DoTest(Expression::Context context) {
Condition is_smi = masm_->CheckSmi(result_register());
__ j(is_smi, if_true);
// Save a copy of the value if it may be needed and isn't already saved.
switch (context) {
case Expression::kUninitialized:
case Expression::kEffect:
case Expression::kValue:
UNREACHABLE();
case Expression::kTest:
break;
case Expression::kValueTest:
switch (location_) {
case kAccumulator:
__ push(result_register());
break;
case kStack:
break;
}
break;
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
__ push(result_register());
break;
case kStack:
break;
}
break;
}
// Call the ToBoolean stub for all other cases.
ToBooleanStub stub;
__ push(result_register());
__ CallStub(&stub);
__ testq(rax, rax);
// The stub returns nonzero for true. Complete based on the context.
switch (context) {
case Expression::kUninitialized:
case Expression::kEffect:
case Expression::kValue:
UNREACHABLE();
// The stub returns nonzero for true.
Split(not_zero, if_true, if_false, fall_through);
}
case Expression::kTest:
__ j(not_zero, true_label_);
__ jmp(false_label_);
break;
case Expression::kValueTest:
switch (location_) {
case kAccumulator:
__ j(zero, &discard);
__ pop(result_register());
__ jmp(true_label_);
break;
case kStack:
__ j(not_zero, true_label_);
break;
}
__ bind(&discard);
__ Drop(1);
__ jmp(false_label_);
break;
case Expression::kTestValue:
switch (location_) {
case kAccumulator:
__ j(not_zero, &discard);
__ pop(result_register());
__ jmp(false_label_);
break;
case kStack:
__ j(zero, false_label_);
break;
}
__ bind(&discard);
__ Drop(1);
__ jmp(true_label_);
break;
void FullCodeGenerator::Split(Condition cc,
Label* if_true,
Label* if_false,
Label* fall_through) {
if (if_false == fall_through) {
__ j(cc, if_true);
} else if (if_true == fall_through) {
__ j(NegateCondition(cc), if_false);
} else {
__ j(cc, if_true);
__ jmp(if_false);
}
}
@ -1206,7 +986,7 @@ void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
__ movq(rdi, Operand(rbp, JavaScriptFrameConstants::kFunctionOffset));
__ movq(rcx, FieldOperand(rdi, JSFunction::kLiteralsOffset));
int literal_offset =
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
__ movq(rbx, FieldOperand(rcx, literal_offset));
__ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
__ j(not_equal, &materialized);
@ -1987,8 +1767,7 @@ void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
Condition positive_smi = __ CheckPositiveSmi(rax);
__ j(positive_smi, if_true);
__ jmp(if_false);
Split(positive_smi, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2016,8 +1795,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));
__ j(below_equal, if_true);
__ jmp(if_false);
Split(below_equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2035,8 +1813,7 @@ void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rbx);
__ j(above_equal, if_true);
__ jmp(if_false);
Split(above_equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2056,8 +1833,7 @@ void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
__ movq(rbx, FieldOperand(rax, HeapObject::kMapOffset));
__ testb(FieldOperand(rbx, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, if_true);
__ jmp(if_false);
Split(not_zero, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2094,8 +1870,7 @@ void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_FUNCTION_TYPE, rbx);
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2113,8 +1888,7 @@ void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_ARRAY_TYPE, rbx);
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2132,8 +1906,7 @@ void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
__ JumpIfSmi(rax, if_false);
__ CmpObjectType(rax, JS_REGEXP_TYPE, rbx);
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2162,8 +1935,7 @@ void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
__ bind(&check_frame_marker);
__ SmiCompare(Operand(rax, StandardFrameConstants::kMarkerOffset),
Smi::FromInt(StackFrame::CONSTRUCT));
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2183,8 +1955,7 @@ void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
__ pop(rbx);
__ cmpq(rax, rbx);
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
Apply(context_, if_true, if_false);
}
@ -2840,19 +2611,7 @@ void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
break;
}
break;
case Expression::kTestValue:
// Value is false so it's needed.
switch (location_) {
case kAccumulator:
__ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
break;
case kStack:
__ PushRoot(Heap::kUndefinedValueRootIndex);
break;
}
// Fall through.
case Expression::kTest:
case Expression::kValueTest:
__ jmp(false_label_);
break;
}
@ -3033,8 +2792,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
break;
case Expression::kValue:
case Expression::kTest:
case Expression::kValueTest:
case Expression::kTestValue:
// Save the result on the stack. If we have a named or keyed property
// we store the result under the receiver that is currently on top
// of the stack.
@ -3138,40 +2895,6 @@ void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
}
}
void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
Comment cmnt(masm_, "[ BinaryOperation");
switch (expr->op()) {
case Token::COMMA:
VisitForEffect(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:
VisitForValue(expr->left(), kStack);
VisitForValue(expr->right(), kAccumulator);
EmitBinaryOp(expr->op(), context_);
break;
default:
UNREACHABLE();
}
}
void FullCodeGenerator::EmitNullCompare(bool strict,
Register obj,
@ -3181,7 +2904,7 @@ void FullCodeGenerator::EmitNullCompare(bool strict,
Register scratch) {
__ cmpq(obj, null_const);
if (strict) {
__ j(equal, if_true);
Split(equal, if_true, if_false, NULL);
} else {
__ j(equal, if_true);
__ CompareRoot(obj, Heap::kUndefinedValueRootIndex);
@ -3191,9 +2914,8 @@ void FullCodeGenerator::EmitNullCompare(bool strict,
__ movq(scratch, FieldOperand(obj, HeapObject::kMapOffset));
__ testb(FieldOperand(scratch, Map::kBitFieldOffset),
Immediate(1 << Map::kIsUndetectable));
__ j(not_zero, if_true);
Split(not_zero, if_true, if_false, NULL);
}
__ jmp(if_false);
}
@ -3213,8 +2935,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
VisitForValue(expr->right(), kStack);
__ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
__ CompareRoot(rax, Heap::kTrueValueRootIndex);
__ j(equal, if_true);
__ jmp(if_false);
Split(equal, if_true, if_false, NULL);
break;
case Token::INSTANCEOF: {
@ -3222,8 +2943,8 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
InstanceofStub stub;
__ CallStub(&stub);
__ testq(rax, rax);
__ j(zero, if_true); // The stub returns 0 for true.
__ jmp(if_false);
// The stub returns 0 for true.
Split(zero, if_true, if_false, NULL);
break;
}
@ -3291,8 +3012,7 @@ void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
CompareStub stub(cc, strict);
__ CallStub(&stub);
__ testq(rax, rax);
__ j(cc, if_true);
__ jmp(if_false);
Split(cc, if_true, if_false, NULL);
}
}