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:
parent
3a7d256596
commit
d0bdc7956e
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {}
|
||||
|
@ -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);
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user