Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1093)

Unified Diff: src/ia32/codegen-ia32.cc

Issue 1148007: Merge bleeding_edge from version 2.1.3 up to revision 4205... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/partial_snapshots/
Patch Set: Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/ia32/codegen-ia32.cc
===================================================================
--- src/ia32/codegen-ia32.cc (revision 4205)
+++ src/ia32/codegen-ia32.cc (working copy)
@@ -112,6 +112,8 @@
allocator_(NULL),
state_(NULL),
loop_nesting_(0),
+ in_safe_int32_mode_(false),
+ safe_int32_mode_enabled_(true),
function_return_is_shadowed_(false),
in_spilled_code_(false) {
}
@@ -437,14 +439,14 @@
// frame. If the expression is boolean-valued it may be compiled (or
// partially compiled) into control flow to the control destination.
// If force_control is true, control flow is forced.
-void CodeGenerator::LoadCondition(Expression* x,
+void CodeGenerator::LoadCondition(Expression* expr,
ControlDestination* dest,
bool force_control) {
ASSERT(!in_spilled_code());
int original_height = frame_->height();
{ CodeGenState new_state(this, dest);
- Visit(x);
+ Visit(expr);
// If we hit a stack overflow, we may not have actually visited
// the expression. In that case, we ensure that we have a
@@ -481,64 +483,157 @@
}
+void CodeGenerator::LoadInSafeInt32Mode(Expression* expr,
+ BreakTarget* unsafe_bailout) {
+ set_unsafe_bailout(unsafe_bailout);
+ set_in_safe_int32_mode(true);
+ Load(expr);
+ Result value = frame_->Pop();
+ ASSERT(frame_->HasNoUntaggedInt32Elements());
+ ConvertInt32ResultToNumber(&value);
+ set_in_safe_int32_mode(false);
+ set_unsafe_bailout(NULL);
+ frame_->Push(&value);
+}
+
+
+void CodeGenerator::LoadWithSafeInt32ModeDisabled(Expression* expr) {
+ set_safe_int32_mode_enabled(false);
+ Load(expr);
+ set_safe_int32_mode_enabled(true);
+}
+
+
+void CodeGenerator::ConvertInt32ResultToNumber(Result* value) {
+ ASSERT(value->is_untagged_int32());
+ if (value->is_register()) {
+ Register val = value->reg();
+ JumpTarget done;
+ __ add(val, Operand(val));
+ done.Branch(no_overflow, value);
+ __ sar(val, 1);
+ // If there was an overflow, bits 30 and 31 of the original number disagree.
+ __ xor_(val, 0x80000000u);
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope fscope(SSE2);
+ __ cvtsi2sd(xmm0, Operand(val));
+ } else {
+ // Move val to ST[0] in the FPU
+ // Push and pop are safe with respect to the virtual frame because
+ // all synced elements are below the actual stack pointer.
+ __ push(val);
+ __ fild_s(Operand(esp, 0));
+ __ pop(val);
+ }
+ Result scratch = allocator_->Allocate();
+ ASSERT(scratch.is_register());
+ Label allocation_failed;
+ __ AllocateHeapNumber(val, scratch.reg(),
+ no_reg, &allocation_failed);
+ VirtualFrame* clone = new VirtualFrame(frame_);
+ scratch.Unuse();
+ if (CpuFeatures::IsSupported(SSE2)) {
+ CpuFeatures::Scope fscope(SSE2);
+ __ movdbl(FieldOperand(val, HeapNumber::kValueOffset), xmm0);
+ } else {
+ __ fstp_d(FieldOperand(val, HeapNumber::kValueOffset));
+ }
+ done.Jump(value);
+
+ // Establish the virtual frame, cloned from where AllocateHeapNumber
+ // jumped to allocation_failed.
+ RegisterFile empty_regs;
+ SetFrame(clone, &empty_regs);
+ __ bind(&allocation_failed);
+ unsafe_bailout_->Jump();
+
+ done.Bind(value);
+ } else {
+ ASSERT(value->is_constant());
+ }
+ value->set_untagged_int32(false);
+}
+
+
void CodeGenerator::Load(Expression* expr) {
#ifdef DEBUG
int original_height = frame_->height();
#endif
ASSERT(!in_spilled_code());
- JumpTarget true_target;
- JumpTarget false_target;
- ControlDestination dest(&true_target, &false_target, true);
- LoadCondition(expr, &dest, false);
- if (dest.false_was_fall_through()) {
- // The false target was just bound.
- JumpTarget loaded;
- frame_->Push(Factory::false_value());
- // There may be dangling jumps to the true target.
- if (true_target.is_linked()) {
- loaded.Jump();
- true_target.Bind();
- frame_->Push(Factory::true_value());
- loaded.Bind();
- }
+ // If the expression should be a side-effect-free 32-bit int computation,
+ // compile that SafeInt32 path, and a bailout path.
+ if (!in_safe_int32_mode() &&
+ safe_int32_mode_enabled() &&
+ expr->side_effect_free() &&
+ expr->num_bit_ops() > 2 &&
+ CpuFeatures::IsSupported(SSE2)) {
+ BreakTarget unsafe_bailout;
+ JumpTarget done;
+ unsafe_bailout.set_expected_height(frame_->height());
+ LoadInSafeInt32Mode(expr, &unsafe_bailout);
+ done.Jump();
- } else if (dest.is_used()) {
- // There is true, and possibly false, control flow (with true as
- // the fall through).
- JumpTarget loaded;
- frame_->Push(Factory::true_value());
- if (false_target.is_linked()) {
- loaded.Jump();
- false_target.Bind();
- frame_->Push(Factory::false_value());
- loaded.Bind();
+ if (unsafe_bailout.is_linked()) {
+ unsafe_bailout.Bind();
+ LoadWithSafeInt32ModeDisabled(expr);
}
+ done.Bind();
+ } else {
+ JumpTarget true_target;
+ JumpTarget false_target;
- } else {
- // We have a valid value on top of the frame, but we still may
- // have dangling jumps to the true and false targets from nested
- // subexpressions (eg, the left subexpressions of the
- // short-circuited boolean operators).
- ASSERT(has_valid_frame());
- if (true_target.is_linked() || false_target.is_linked()) {
+ ControlDestination dest(&true_target, &false_target, true);
+ LoadCondition(expr, &dest, false);
+
+ if (dest.false_was_fall_through()) {
+ // The false target was just bound.
JumpTarget loaded;
- loaded.Jump(); // Don't lose the current TOS.
+ frame_->Push(Factory::false_value());
+ // There may be dangling jumps to the true target.
if (true_target.is_linked()) {
+ loaded.Jump();
true_target.Bind();
frame_->Push(Factory::true_value());
- if (false_target.is_linked()) {
- loaded.Jump();
- }
+ loaded.Bind();
}
+
+ } else if (dest.is_used()) {
+ // There is true, and possibly false, control flow (with true as
+ // the fall through).
+ JumpTarget loaded;
+ frame_->Push(Factory::true_value());
if (false_target.is_linked()) {
+ loaded.Jump();
false_target.Bind();
frame_->Push(Factory::false_value());
+ loaded.Bind();
}
- loaded.Bind();
+
+ } else {
+ // We have a valid value on top of the frame, but we still may
+ // have dangling jumps to the true and false targets from nested
+ // subexpressions (eg, the left subexpressions of the
+ // short-circuited boolean operators).
+ ASSERT(has_valid_frame());
+ if (true_target.is_linked() || false_target.is_linked()) {
+ JumpTarget loaded;
+ loaded.Jump(); // Don't lose the current TOS.
+ if (true_target.is_linked()) {
+ true_target.Bind();
+ frame_->Push(Factory::true_value());
+ if (false_target.is_linked()) {
+ loaded.Jump();
+ }
+ }
+ if (false_target.is_linked()) {
+ false_target.Bind();
+ frame_->Push(Factory::false_value());
+ }
+ loaded.Bind();
+ }
}
}
-
ASSERT(has_valid_frame());
ASSERT(frame_->height() == original_height + 1);
}
@@ -737,7 +832,7 @@
Comment cmnt(masm_, "ONLY_INTEGER_32");
if (FLAG_debug_code) {
Label ok;
- __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number.");
+ __ AbortIfNotNumber(value.reg());
__ test(value.reg(), Immediate(kSmiTagMask));
__ j(zero, &ok);
__ fldz();
@@ -757,7 +852,7 @@
Comment cmnt(masm_, "ONLY_NUMBER");
// Fast case if NumberInfo indicates only numbers.
if (FLAG_debug_code) {
- __ AbortIfNotNumber(value.reg(), "ToBoolean operand is not a number.");
+ __ AbortIfNotNumber(value.reg());
}
// Smi => false iff zero.
ASSERT(kSmiTag == 0);
@@ -943,6 +1038,8 @@
__ jmp(&load_right);
__ bind(&left_smi);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(left_);
}
__ SmiUntag(left_);
__ cvtsi2sd(xmm0, Operand(left_));
@@ -975,6 +1072,8 @@
__ jmp(&do_op);
__ bind(&right_smi);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(right_);
}
__ SmiUntag(right_);
__ cvtsi2sd(xmm1, Operand(right_));
@@ -1102,7 +1201,8 @@
void CodeGenerator::GenericBinaryOperation(Token::Value op,
StaticType* type,
- OverwriteMode overwrite_mode) {
+ OverwriteMode overwrite_mode,
+ bool no_negative_zero) {
Comment cmnt(masm_, "[ BinaryOperation");
Comment cmnt_token(masm_, Token::String(op));
@@ -1170,10 +1270,12 @@
answer = stub.GenerateCall(masm_, frame_, &left, &right);
} else if (right_is_smi_constant) {
answer = ConstantSmiBinaryOperation(op, &left, right.handle(),
- type, false, overwrite_mode);
+ type, false, overwrite_mode,
+ no_negative_zero);
} else if (left_is_smi_constant) {
answer = ConstantSmiBinaryOperation(op, &right, left.handle(),
- type, true, overwrite_mode);
+ type, true, overwrite_mode,
+ no_negative_zero);
} else {
// Set the flags based on the operation, type and loop nesting level.
// Bit operations always assume they likely operate on Smis. Still only
@@ -1184,7 +1286,8 @@
(Token::IsBitOp(op) ||
operands_type.IsInteger32() ||
type->IsLikelySmi())) {
- answer = LikelySmiBinaryOperation(op, &left, &right, overwrite_mode);
+ answer = LikelySmiBinaryOperation(op, &left, &right,
+ overwrite_mode, no_negative_zero);
} else {
GenericBinaryOpStub stub(op,
overwrite_mode,
@@ -1291,7 +1394,8 @@
Result CodeGenerator::LikelySmiBinaryOperation(Token::Value op,
Result* left,
Result* right,
- OverwriteMode overwrite_mode) {
+ OverwriteMode overwrite_mode,
+ bool no_negative_zero) {
Result answer;
// Special handling of div and mod because they use fixed registers.
if (op == Token::DIV || op == Token::MOD) {
@@ -1395,13 +1499,16 @@
// Check for negative zero result. If result is zero, and divisor
// is negative, return a floating point negative zero. The
// virtual frame is unchanged in this block, so local control flow
- // can use a Label rather than a JumpTarget.
- Label non_zero_result;
- __ test(left->reg(), Operand(left->reg()));
- __ j(not_zero, &non_zero_result);
- __ test(right->reg(), Operand(right->reg()));
- deferred->Branch(negative);
- __ bind(&non_zero_result);
+ // can use a Label rather than a JumpTarget. If the context of this
+ // expression will treat -0 like 0, do not do this test.
+ if (!no_negative_zero) {
+ Label non_zero_result;
+ __ test(left->reg(), Operand(left->reg()));
+ __ j(not_zero, &non_zero_result);
+ __ test(right->reg(), Operand(right->reg()));
+ deferred->Branch(negative);
+ __ bind(&non_zero_result);
+ }
// Check for the corner case of dividing the most negative smi by
// -1. We cannot use the overflow flag, since it is not set by
// idiv instruction.
@@ -1423,12 +1530,14 @@
// the dividend is negative, return a floating point negative
// zero. The frame is unchanged in this block, so local control
// flow can use a Label rather than a JumpTarget.
- Label non_zero_result;
- __ test(edx, Operand(edx));
- __ j(not_zero, &non_zero_result, taken);
- __ test(left->reg(), Operand(left->reg()));
- deferred->Branch(negative);
- __ bind(&non_zero_result);
+ if (!no_negative_zero) {
+ Label non_zero_result;
+ __ test(edx, Operand(edx));
+ __ j(not_zero, &non_zero_result, taken);
+ __ test(left->reg(), Operand(left->reg()));
+ deferred->Branch(negative);
+ __ bind(&non_zero_result);
+ }
deferred->BindExit();
left->Unuse();
right->Unuse();
@@ -1468,12 +1577,46 @@
left->number_info(),
right->number_info(),
overwrite_mode);
- CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(),
- left->number_info(), right->number_info(), deferred);
- // Untag both operands.
- __ mov(answer.reg(), left->reg());
- __ SmiUntag(answer.reg());
+ Label do_op, left_nonsmi;
+ // If right is a smi we make a fast case if left is either a smi
+ // or a heapnumber.
+ if (CpuFeatures::IsSupported(SSE2) && right->number_info().IsSmi()) {
+ CpuFeatures::Scope use_sse2(SSE2);
+ __ mov(answer.reg(), left->reg());
+ // Fast case - both are actually smis.
+ if (!left->number_info().IsSmi()) {
+ __ test(answer.reg(), Immediate(kSmiTagMask));
+ __ j(not_zero, &left_nonsmi);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(left->reg());
+ }
+ if (FLAG_debug_code) __ AbortIfNotSmi(right->reg());
+ __ SmiUntag(answer.reg());
+ __ jmp(&do_op);
+
+ __ bind(&left_nonsmi);
+ // Branch if not a heapnumber.
+ __ cmp(FieldOperand(answer.reg(), HeapObject::kMapOffset),
+ Factory::heap_number_map());
+ deferred->Branch(not_equal);
+
+ // Load integer value into answer register using truncation.
+ __ cvttsd2si(answer.reg(),
+ FieldOperand(answer.reg(), HeapNumber::kValueOffset));
+ // Branch if we do not fit in a smi.
+ __ cmp(answer.reg(), 0xc0000000);
+ deferred->Branch(negative);
+ } else {
+ CheckTwoForSminess(masm_, left->reg(), right->reg(), answer.reg(),
+ left->number_info(), right->number_info(), deferred);
+
+ // Untag both operands.
+ __ mov(answer.reg(), left->reg());
+ __ SmiUntag(answer.reg());
+ }
+
+ __ bind(&do_op);
__ SmiUntag(ecx);
// Perform the operation.
switch (op) {
@@ -1571,14 +1714,16 @@
// argument is negative, go to slow case. The frame is unchanged
// in this block, so local control flow can use a Label rather
// than a JumpTarget.
- Label non_zero_result;
- __ test(answer.reg(), Operand(answer.reg()));
- __ j(not_zero, &non_zero_result, taken);
- __ mov(answer.reg(), left->reg());
- __ or_(answer.reg(), Operand(right->reg()));
- deferred->Branch(negative);
- __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct.
- __ bind(&non_zero_result);
+ if (!no_negative_zero) {
+ Label non_zero_result;
+ __ test(answer.reg(), Operand(answer.reg()));
+ __ j(not_zero, &non_zero_result, taken);
+ __ mov(answer.reg(), left->reg());
+ __ or_(answer.reg(), Operand(right->reg()));
+ deferred->Branch(negative);
+ __ xor_(answer.reg(), Operand(answer.reg())); // Positive 0 is correct.
+ __ bind(&non_zero_result);
+ }
break;
}
@@ -1817,7 +1962,8 @@
Handle<Object> value,
StaticType* type,
bool reversed,
- OverwriteMode overwrite_mode) {
+ OverwriteMode overwrite_mode,
+ bool no_negative_zero) {
// NOTE: This is an attempt to inline (a bit) more of the code for
// some possible smi operations (like + and -) when (at least) one
// of the operands is a constant smi.
@@ -1828,10 +1974,10 @@
Result unsafe_operand(value);
if (reversed) {
return LikelySmiBinaryOperation(op, &unsafe_operand, operand,
- overwrite_mode);
+ overwrite_mode, no_negative_zero);
} else {
return LikelySmiBinaryOperation(op, operand, &unsafe_operand,
- overwrite_mode);
+ overwrite_mode, no_negative_zero);
}
}
@@ -1864,6 +2010,8 @@
if (!operand->number_info().IsSmi()) {
__ test(operand->reg(), Immediate(kSmiTagMask));
deferred->Branch(not_zero);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg());
}
deferred->BindExit();
answer = *operand;
@@ -1901,6 +2049,8 @@
if (!operand->number_info().IsSmi()) {
__ test(answer.reg(), Immediate(kSmiTagMask));
deferred->Branch(not_zero);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg());
}
deferred->BindExit();
operand->Unuse();
@@ -1911,7 +2061,7 @@
if (reversed) {
Result constant_operand(value);
answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
- overwrite_mode);
+ overwrite_mode, no_negative_zero);
} else {
// Only the least significant 5 bits of the shift value are used.
// In the slow case, this masking is done inside the runtime call.
@@ -1934,6 +2084,7 @@
}
deferred->BindExit();
} else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg());
if (shift_value > 0) {
__ sar(operand->reg(), shift_value);
__ and_(operand->reg(), ~kSmiTagMask);
@@ -1947,7 +2098,7 @@
if (reversed) {
Result constant_operand(value);
answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
- overwrite_mode);
+ overwrite_mode, no_negative_zero);
} else {
// Only the least significant 5 bits of the shift value are used.
// In the slow case, this masking is done inside the runtime call.
@@ -1965,6 +2116,8 @@
if (!operand->number_info().IsSmi()) {
__ test(operand->reg(), Immediate(kSmiTagMask));
deferred->Branch(not_zero);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg());
}
__ mov(answer.reg(), operand->reg());
__ SmiUntag(answer.reg());
@@ -2013,6 +2166,8 @@
__ sar(ecx, kSmiTagSize);
if (!right.number_info().IsSmi()) {
deferred->Branch(carry);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(right.reg());
}
__ shl_cl(answer.reg());
__ cmp(answer.reg(), 0xc0000000);
@@ -2053,6 +2208,8 @@
if (!operand->number_info().IsSmi()) {
__ test(operand->reg(), Immediate(kSmiTagMask));
deferred->Branch(not_zero);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg());
}
__ mov(answer.reg(), operand->reg());
ASSERT(kSmiTag == 0); // adjust code if not the case
@@ -2095,6 +2252,8 @@
if (!operand->number_info().IsSmi()) {
__ test(operand->reg(), Immediate(kSmiTagMask));
deferred->Branch(not_zero);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(operand->reg());
}
if (op == Token::BIT_AND) {
__ and_(Operand(operand->reg()), Immediate(value));
@@ -2140,10 +2299,10 @@
Result constant_operand(value);
if (reversed) {
answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
- overwrite_mode);
+ overwrite_mode, no_negative_zero);
} else {
answer = LikelySmiBinaryOperation(op, operand, &constant_operand,
- overwrite_mode);
+ overwrite_mode, no_negative_zero);
}
}
break;
@@ -2180,10 +2339,10 @@
Result constant_operand(value);
if (reversed) {
answer = LikelySmiBinaryOperation(op, &constant_operand, operand,
- overwrite_mode);
+ overwrite_mode, no_negative_zero);
} else {
answer = LikelySmiBinaryOperation(op, operand, &constant_operand,
- overwrite_mode);
+ overwrite_mode, no_negative_zero);
}
break;
}
@@ -2286,61 +2445,67 @@
// a jump target and branching to duplicate the virtual frame at
// the first split. We manually handle the off-frame references
// by reconstituting them on the non-fall-through path.
- JumpTarget is_smi;
- __ test(left_side.reg(), Immediate(kSmiTagMask));
- is_smi.Branch(zero, taken);
- bool is_for_loop_compare = (node->AsCompareOperation() != NULL)
- && node->AsCompareOperation()->is_for_loop_condition();
- if (!is_for_loop_compare
- && CpuFeatures::IsSupported(SSE2)
- && right_val->IsSmi()) {
- // Right side is a constant smi and left side has been checked
- // not to be a smi.
- CpuFeatures::Scope use_sse2(SSE2);
- JumpTarget not_number;
- __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
- Immediate(Factory::heap_number_map()));
- not_number.Branch(not_equal, &left_side);
- __ movdbl(xmm1,
- FieldOperand(left_reg, HeapNumber::kValueOffset));
- int value = Smi::cast(*right_val)->value();
- if (value == 0) {
- __ xorpd(xmm0, xmm0);
- } else {
- Result temp = allocator()->Allocate();
- __ mov(temp.reg(), Immediate(value));
- __ cvtsi2sd(xmm0, Operand(temp.reg()));
- temp.Unuse();
+ if (left_side.is_smi()) {
+ if (FLAG_debug_code) __ AbortIfNotSmi(left_side.reg());
+ } else {
+ JumpTarget is_smi;
+ __ test(left_side.reg(), Immediate(kSmiTagMask));
+ is_smi.Branch(zero, taken);
+
+ bool is_for_loop_compare = (node->AsCompareOperation() != NULL)
+ && node->AsCompareOperation()->is_for_loop_condition();
+ if (!is_for_loop_compare
+ && CpuFeatures::IsSupported(SSE2)
+ && right_val->IsSmi()) {
+ // Right side is a constant smi and left side has been checked
+ // not to be a smi.
+ CpuFeatures::Scope use_sse2(SSE2);
+ JumpTarget not_number;
+ __ cmp(FieldOperand(left_reg, HeapObject::kMapOffset),
+ Immediate(Factory::heap_number_map()));
+ not_number.Branch(not_equal, &left_side);
+ __ movdbl(xmm1,
+ FieldOperand(left_reg, HeapNumber::kValueOffset));
+ int value = Smi::cast(*right_val)->value();
+ if (value == 0) {
+ __ xorpd(xmm0, xmm0);
+ } else {
+ Result temp = allocator()->Allocate();
+ __ mov(temp.reg(), Immediate(value));
+ __ cvtsi2sd(xmm0, Operand(temp.reg()));
+ temp.Unuse();
+ }
+ __ comisd(xmm1, xmm0);
+ // Jump to builtin for NaN.
+ not_number.Branch(parity_even, &left_side);
+ left_side.Unuse();
+ Condition double_cc = cc;
+ switch (cc) {
+ case less: double_cc = below; break;
+ case equal: double_cc = equal; break;
+ case less_equal: double_cc = below_equal; break;
+ case greater: double_cc = above; break;
+ case greater_equal: double_cc = above_equal; break;
+ default: UNREACHABLE();
+ }
+ dest->true_target()->Branch(double_cc);
+ dest->false_target()->Jump();
+ not_number.Bind(&left_side);
}
- __ comisd(xmm1, xmm0);
- // Jump to builtin for NaN.
- not_number.Branch(parity_even, &left_side);
- left_side.Unuse();
- Condition double_cc = cc;
- switch (cc) {
- case less: double_cc = below; break;
- case equal: double_cc = equal; break;
- case less_equal: double_cc = below_equal; break;
- case greater: double_cc = above; break;
- case greater_equal: double_cc = above_equal; break;
- default: UNREACHABLE();
- }
- dest->true_target()->Branch(double_cc);
+
+ // Setup and call the compare stub.
+ CompareStub stub(cc, strict, kCantBothBeNaN);
+ Result result = frame_->CallStub(&stub, &left_side, &right_side);
+ result.ToRegister();
+ __ cmp(result.reg(), 0);
+ result.Unuse();
+ dest->true_target()->Branch(cc);
dest->false_target()->Jump();
- not_number.Bind(&left_side);
+
+ is_smi.Bind();
}
- // Setup and call the compare stub.
- CompareStub stub(cc, strict, kCantBothBeNaN);
- Result result = frame_->CallStub(&stub, &left_side, &right_side);
- result.ToRegister();
- __ cmp(result.reg(), 0);
- result.Unuse();
- dest->true_target()->Branch(cc);
- dest->false_target()->Jump();
-
- is_smi.Bind();
left_side = Result(left_reg);
right_side = Result(right_val);
// Test smi equality and comparison by signed int comparison.
@@ -3487,6 +3652,26 @@
}
+void CodeGenerator::SetTypeForStackSlot(Slot* slot, NumberInfo info) {
+ ASSERT(slot->type() == Slot::LOCAL || slot->type() == Slot::PARAMETER);
+ if (slot->type() == Slot::LOCAL) {
+ frame_->SetTypeForLocalAt(slot->index(), info);
+ } else {
+ frame_->SetTypeForParamAt(slot->index(), info);
+ }
+ if (FLAG_debug_code && info.IsSmi()) {
+ if (slot->type() == Slot::LOCAL) {
+ frame_->PushLocalAt(slot->index());
+ } else {
+ frame_->PushParameterAt(slot->index());
+ }
+ Result var = frame_->Pop();
+ var.ToRegister();
+ __ AbortIfNotSmi(var.reg());
+ }
+}
+
+
void CodeGenerator::VisitForStatement(ForStatement* node) {
ASSERT(!in_spilled_code());
Comment cmnt(masm_, "[ ForStatement");
@@ -3579,6 +3764,17 @@
}
CheckStack(); // TODO(1222600): ignore if body contains calls.
+
+ // We know that the loop index is a smi if it is not modified in the
+ // loop body and it is checked against a constant limit in the loop
+ // condition. In this case, we reset the static type information of the
+ // loop index to smi before compiling the body, the update expression, and
+ // the bottom check of the loop condition.
+ if (node->is_fast_smi_loop()) {
+ // Set number type of the loop variable to smi.
+ SetTypeForStackSlot(node->loop_variable()->slot(), NumberInfo::Smi());
+ }
+
Visit(node->body());
// If there is an update expression, compile it if necessary.
@@ -3598,6 +3794,13 @@
}
}
+ // Set the type of the loop variable to smi before compiling the test
+ // expression if we are in a fast smi loop condition.
+ if (node->is_fast_smi_loop() && has_valid_frame()) {
+ // Set number type of the loop variable to smi.
+ SetTypeForStackSlot(node->loop_variable()->slot(), NumberInfo::Smi());
+ }
+
// Based on the condition analysis, compile the backward jump as
// necessary.
switch (info) {
@@ -4244,7 +4447,7 @@
void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
Comment cmnt(masm_, "[ FunctionLiteral");
-
+ ASSERT(!in_safe_int32_mode());
// Build the function boilerplate and instantiate it.
Handle<JSFunction> boilerplate =
Compiler::BuildBoilerplate(node, script(), this);
@@ -4257,6 +4460,7 @@
void CodeGenerator::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
Result result = InstantiateBoilerplate(node->boilerplate());
frame()->Push(&result);
@@ -4265,6 +4469,7 @@
void CodeGenerator::VisitConditional(Conditional* node) {
Comment cmnt(masm_, "[ Conditional");
+ ASSERT(!in_safe_int32_mode());
JumpTarget then;
JumpTarget else_;
JumpTarget exit;
@@ -4435,6 +4640,7 @@
Slot* slot,
TypeofState typeof_state,
JumpTarget* slow) {
+ ASSERT(!in_safe_int32_mode());
// Check that no extension objects have been created by calls to
// eval from the current scope to the global scope.
Register context = esi;
@@ -4603,10 +4809,20 @@
}
-void CodeGenerator::VisitSlot(Slot* node) {
+void CodeGenerator::VisitSlot(Slot* slot) {
Comment cmnt(masm_, "[ Slot");
- Result result = LoadFromSlotCheckForArguments(node, NOT_INSIDE_TYPEOF);
- frame()->Push(&result);
+ if (in_safe_int32_mode()) {
+ if ((slot->type() == Slot::LOCAL && !slot->is_arguments())) {
+ frame()->UntaggedPushLocalAt(slot->index());
+ } else if (slot->type() == Slot::PARAMETER) {
+ frame()->UntaggedPushParameterAt(slot->index());
+ } else {
+ UNREACHABLE();
+ }
+ } else {
+ Result result = LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
+ frame()->Push(&result);
+ }
}
@@ -4618,6 +4834,7 @@
Visit(expr);
} else {
ASSERT(var->is_global());
+ ASSERT(!in_safe_int32_mode());
Reference ref(this, node);
ref.GetValue();
}
@@ -4626,7 +4843,11 @@
void CodeGenerator::VisitLiteral(Literal* node) {
Comment cmnt(masm_, "[ Literal");
- frame_->Push(node->handle());
+ if (in_safe_int32_mode()) {
+ frame_->PushUntaggedElement(node->handle());
+ } else {
+ frame_->Push(node->handle());
+ }
}
@@ -4700,6 +4921,7 @@
void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ RegExp Literal");
// Retrieve the literals array and check the allocated entry. Begin
@@ -4736,6 +4958,7 @@
void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ ObjectLiteral");
// Load a writable copy of the function of this activation in a
@@ -4754,11 +4977,13 @@
frame_->Push(Smi::FromInt(node->literal_index()));
// Constant properties.
frame_->Push(node->constant_properties());
+ // Should the object literal have fast elements?
+ frame_->Push(Smi::FromInt(node->fast_elements() ? 1 : 0));
Result clone;
if (node->depth() > 1) {
- clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 3);
+ clone = frame_->CallRuntime(Runtime::kCreateObjectLiteral, 4);
} else {
- clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
+ clone = frame_->CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
}
frame_->Push(&clone);
@@ -4818,6 +5043,7 @@
void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ ArrayLiteral");
// Load a writable copy of the function of this activation in a
@@ -4889,6 +5115,7 @@
void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) {
+ ASSERT(!in_safe_int32_mode());
ASSERT(!in_spilled_code());
// Call runtime routine to allocate the catch extension object and
// assign the exception value to the catch variable.
@@ -4922,7 +5149,8 @@
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
GenericBinaryOperation(node->binary_op(),
node->type(),
- overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE,
+ node->no_negative_zero());
} else {
Load(node->value());
}
@@ -4999,7 +5227,8 @@
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
GenericBinaryOperation(node->binary_op(),
node->type(),
- overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE,
+ node->no_negative_zero());
} else {
Load(node->value());
}
@@ -5078,7 +5307,8 @@
node->value()->AsBinaryOperation()->ResultOverwriteAllowed());
GenericBinaryOperation(node->binary_op(),
node->type(),
- overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE);
+ overwrite_value ? OVERWRITE_RIGHT : NO_OVERWRITE,
+ node->no_negative_zero());
} else {
Load(node->value());
}
@@ -5105,6 +5335,7 @@
void CodeGenerator::VisitAssignment(Assignment* node) {
+ ASSERT(!in_safe_int32_mode());
#ifdef DEBUG
int original_height = frame()->height();
#endif
@@ -5140,6 +5371,7 @@
void CodeGenerator::VisitThrow(Throw* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ Throw");
Load(node->exception());
Result result = frame_->CallRuntime(Runtime::kThrow, 1);
@@ -5148,6 +5380,7 @@
void CodeGenerator::VisitProperty(Property* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ Property");
Reference property(this, node);
property.GetValue();
@@ -5155,6 +5388,7 @@
void CodeGenerator::VisitCall(Call* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ Call");
Expression* function = node->expression();
@@ -5370,6 +5604,7 @@
void CodeGenerator::VisitCallNew(CallNew* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ CallNew");
// According to ECMA-262, section 11.2.2, page 44, the function
@@ -5912,7 +6147,7 @@
}
-void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
+void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
// ArgumentsAccessStub expects the key in edx and the formal
@@ -6297,6 +6532,7 @@
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
+ ASSERT(!in_safe_int32_mode());
if (CheckForInlineRuntimeCall(node)) {
return;
}
@@ -6423,64 +6659,123 @@
}
} else {
- Load(node->expression());
- bool overwrite =
- (node->expression()->AsBinaryOperation() != NULL &&
- node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
- switch (op) {
- case Token::SUB: {
- GenericUnaryOpStub stub(Token::SUB, overwrite);
- Result operand = frame_->Pop();
- Result answer = frame_->CallStub(&stub, &operand);
- frame_->Push(&answer);
- break;
+ if (in_safe_int32_mode()) {
+ Visit(node->expression());
+ Result value = frame_->Pop();
+ ASSERT(value.is_untagged_int32());
+ // Registers containing an int32 value are not multiply used.
+ ASSERT(!value.is_register() || !frame_->is_used(value.reg()));
+ value.ToRegister();
+ switch (op) {
+ case Token::SUB: {
+ __ neg(value.reg());
+ if (node->no_negative_zero()) {
+ // -MIN_INT is MIN_INT with the overflow flag set.
+ unsafe_bailout_->Branch(overflow);
+ } else {
+ // MIN_INT and 0 both have bad negations. They both have 31 zeros.
+ __ test(value.reg(), Immediate(0x7FFFFFFF));
+ unsafe_bailout_->Branch(zero);
+ }
+ break;
+ }
+ case Token::BIT_NOT: {
+ __ not_(value.reg());
+ break;
+ }
+ case Token::ADD: {
+ // Unary plus has no effect on int32 values.
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
}
+ frame_->Push(&value);
+ } else {
+ Load(node->expression());
+ bool overwrite =
+ (node->expression()->AsBinaryOperation() != NULL &&
+ node->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
+ switch (op) {
+ case Token::SUB: {
+ GenericUnaryOpStub stub(Token::SUB, overwrite);
+ Result operand = frame_->Pop();
+ Result answer = frame_->CallStub(&stub, &operand);
+ answer.set_number_info(NumberInfo::Number());
+ frame_->Push(&answer);
+ break;
+ }
+ case Token::BIT_NOT: {
+ // Smi check.
+ JumpTarget smi_label;
+ JumpTarget continue_label;
+ Result operand = frame_->Pop();
+ NumberInfo operand_info = operand.number_info();
+ operand.ToRegister();
+ if (operand_info.IsSmi()) {
+ if (FLAG_debug_code) __ AbortIfNotSmi(operand.reg());
+ frame_->Spill(operand.reg());
+ // Set smi tag bit. It will be reset by the not operation.
+ __ lea(operand.reg(), Operand(operand.reg(), kSmiTagMask));
+ __ not_(operand.reg());
+ Result answer = operand;
+ answer.set_number_info(NumberInfo::Smi());
+ frame_->Push(&answer);
+ } else {
+ __ test(operand.reg(), Immediate(kSmiTagMask));
+ smi_label.Branch(zero, &operand, taken);
- case Token::BIT_NOT: {
- // Smi check.
- JumpTarget smi_label;
- JumpTarget continue_label;
- Result operand = frame_->Pop();
- operand.ToRegister();
- __ test(operand.reg(), Immediate(kSmiTagMask));
- smi_label.Branch(zero, &operand, taken);
+ GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
+ Result answer = frame_->CallStub(&stub, &operand);
+ continue_label.Jump(&answer);
- GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
- Result answer = frame_->CallStub(&stub, &operand);
- continue_label.Jump(&answer);
+ smi_label.Bind(&answer);
+ answer.ToRegister();
+ frame_->Spill(answer.reg());
+ // Set smi tag bit. It will be reset by the not operation.
+ __ lea(answer.reg(), Operand(answer.reg(), kSmiTagMask));
+ __ not_(answer.reg());
- smi_label.Bind(&answer);
- answer.ToRegister();
- frame_->Spill(answer.reg());
- __ not_(answer.reg());
- __ and_(answer.reg(), ~kSmiTagMask); // Remove inverted smi-tag.
+ continue_label.Bind(&answer);
+ if (operand_info.IsInteger32()) {
+ answer.set_number_info(NumberInfo::Integer32());
+ } else {
+ answer.set_number_info(NumberInfo::Number());
+ }
+ frame_->Push(&answer);
+ }
+ break;
+ }
+ case Token::ADD: {
+ // Smi check.
+ JumpTarget continue_label;
+ Result operand = frame_->Pop();
+ NumberInfo operand_info = operand.number_info();
+ operand.ToRegister();
+ __ test(operand.reg(), Immediate(kSmiTagMask));
+ continue_label.Branch(zero, &operand, taken);
- continue_label.Bind(&answer);
- frame_->Push(&answer);
- break;
- }
-
- case Token::ADD: {
- // Smi check.
- JumpTarget continue_label;
- Result operand = frame_->Pop();
- operand.ToRegister();
- __ test(operand.reg(), Immediate(kSmiTagMask));
- continue_label.Branch(zero, &operand, taken);
-
- frame_->Push(&operand);
- Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER,
+ frame_->Push(&operand);
+ Result answer = frame_->InvokeBuiltin(Builtins::TO_NUMBER,
CALL_FUNCTION, 1);
- continue_label.Bind(&answer);
- frame_->Push(&answer);
- break;
+ continue_label.Bind(&answer);
+ if (operand_info.IsSmi()) {
+ answer.set_number_info(NumberInfo::Smi());
+ } else if (operand_info.IsInteger32()) {
+ answer.set_number_info(NumberInfo::Integer32());
+ } else {
+ answer.set_number_info(NumberInfo::Number());
+ }
+ frame_->Push(&answer);
+ break;
+ }
+ default:
+ // NOT, DELETE, TYPEOF, and VOID are handled outside the
+ // switch.
+ UNREACHABLE();
}
-
- default:
- // NOT, DELETE, TYPEOF, and VOID are handled outside the
- // switch.
- UNREACHABLE();
}
}
}
@@ -6573,6 +6868,7 @@
void CodeGenerator::VisitCountOperation(CountOperation* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ CountOperation");
bool is_postfix = node->is_postfix();
@@ -6607,23 +6903,39 @@
old_value = allocator_->Allocate();
ASSERT(old_value.is_valid());
__ mov(old_value.reg(), new_value.reg());
+
+ // The return value for postfix operations is the
+ // same as the input, and has the same number info.
+ old_value.set_number_info(new_value.number_info());
}
+
// Ensure the new value is writable.
frame_->Spill(new_value.reg());
- // In order to combine the overflow and the smi tag check, we need
- // to be able to allocate a byte register. We attempt to do so
- // without spilling. If we fail, we will generate separate overflow
- // and smi tag checks.
- //
- // We allocate and clear the temporary byte register before
- // performing the count operation since clearing the register using
- // xor will clear the overflow flag.
- Result tmp = allocator_->AllocateByteRegisterWithoutSpilling();
- if (tmp.is_valid()) {
- __ Set(tmp.reg(), Immediate(0));
+ Result tmp;
+ if (new_value.is_smi()) {
+ if (FLAG_debug_code) __ AbortIfNotSmi(new_value.reg());
+ } else {
+ // We don't know statically if the input is a smi.
+ // In order to combine the overflow and the smi tag check, we need
+ // to be able to allocate a byte register. We attempt to do so
+ // without spilling. If we fail, we will generate separate overflow
+ // and smi tag checks.
+ // We allocate and clear a temporary byte register before performing
+ // the count operation since clearing the register using xor will clear
+ // the overflow flag.
+ tmp = allocator_->AllocateByteRegisterWithoutSpilling();
+ if (tmp.is_valid()) {
+ __ Set(tmp.reg(), Immediate(0));
+ }
}
+ if (is_increment) {
+ __ add(Operand(new_value.reg()), Immediate(Smi::FromInt(1)));
+ } else {
+ __ sub(Operand(new_value.reg()), Immediate(Smi::FromInt(1)));
+ }
+
DeferredCode* deferred = NULL;
if (is_postfix) {
deferred = new DeferredPostfixCountOperation(new_value.reg(),
@@ -6634,31 +6946,38 @@
is_increment);
}
- if (is_increment) {
- __ add(Operand(new_value.reg()), Immediate(Smi::FromInt(1)));
+ if (new_value.is_smi()) {
+ // In case we have a smi as input just check for overflow.
+ deferred->Branch(overflow);
} else {
- __ sub(Operand(new_value.reg()), Immediate(Smi::FromInt(1)));
- }
-
- // If the count operation didn't overflow and the result is a valid
- // smi, we're done. Otherwise, we jump to the deferred slow-case
- // code.
- if (tmp.is_valid()) {
+ // If the count operation didn't overflow and the result is a valid
+ // smi, we're done. Otherwise, we jump to the deferred slow-case
+ // code.
// We combine the overflow and the smi tag check if we could
// successfully allocate a temporary byte register.
- __ setcc(overflow, tmp.reg());
- __ or_(Operand(tmp.reg()), new_value.reg());
- __ test(tmp.reg(), Immediate(kSmiTagMask));
- tmp.Unuse();
- deferred->Branch(not_zero);
- } else {
- // Otherwise we test separately for overflow and smi tag.
- deferred->Branch(overflow);
- __ test(new_value.reg(), Immediate(kSmiTagMask));
- deferred->Branch(not_zero);
+ if (tmp.is_valid()) {
+ __ setcc(overflow, tmp.reg());
+ __ or_(Operand(tmp.reg()), new_value.reg());
+ __ test(tmp.reg(), Immediate(kSmiTagMask));
+ tmp.Unuse();
+ deferred->Branch(not_zero);
+ } else {
+ // Otherwise we test separately for overflow and smi tag.
+ deferred->Branch(overflow);
+ __ test(new_value.reg(), Immediate(kSmiTagMask));
+ deferred->Branch(not_zero);
+ }
}
deferred->BindExit();
+ // The result of ++ or -- is an Integer32 if the
+ // input is a smi. Otherwise it is a number.
+ if (new_value.is_smi()) {
+ new_value.set_number_info(NumberInfo::Integer32());
+ } else {
+ new_value.set_number_info(NumberInfo::Number());
+ }
+
// Postfix: store the old value in the allocated slot under the
// reference.
if (is_postfix) frame_->SetElementAt(target.size(), &old_value);
@@ -6673,6 +6992,166 @@
}
+void CodeGenerator::Int32BinaryOperation(BinaryOperation* node) {
+ Token::Value op = node->op();
+ Comment cmnt(masm_, "[ Int32BinaryOperation");
+ ASSERT(in_safe_int32_mode());
+ ASSERT(safe_int32_mode_enabled());
+ ASSERT(FLAG_safe_int32_compiler);
+
+ if (op == Token::COMMA) {
+ // Discard left value.
+ frame_->Nip(1);
+ return;
+ }
+
+ Result right = frame_->Pop();
+ Result left = frame_->Pop();
+
+ ASSERT(right.is_untagged_int32());
+ ASSERT(left.is_untagged_int32());
+ // Registers containing an int32 value are not multiply used.
+ ASSERT(!left.is_register() || !frame_->is_used(left.reg()));
+ ASSERT(!right.is_register() || !frame_->is_used(right.reg()));
+
+ switch (op) {
+ case Token::COMMA:
+ case Token::OR:
+ case Token::AND:
+ UNREACHABLE();
+ break;
+ case Token::BIT_OR:
+ case Token::BIT_XOR:
+ case Token::BIT_AND:
+ left.ToRegister();
+ right.ToRegister();
+ if (op == Token::BIT_OR) {
+ __ or_(left.reg(), Operand(right.reg()));
+ } else if (op == Token::BIT_XOR) {
+ __ xor_(left.reg(), Operand(right.reg()));
+ } else {
+ ASSERT(op == Token::BIT_AND);
+ __ and_(left.reg(), Operand(right.reg()));
+ }
+ frame_->Push(&left);
+ right.Unuse();
+ break;
+ case Token::SAR:
+ case Token::SHL:
+ case Token::SHR: {
+ bool test_shr_overflow = false;
+ left.ToRegister();
+ if (right.is_constant()) {
+ ASSERT(right.handle()->IsSmi() || right.handle()->IsHeapNumber());
+ int shift_amount = NumberToInt32(*right.handle()) & 0x1F;
+ if (op == Token::SAR) {
+ __ sar(left.reg(), shift_amount);
+ } else if (op == Token::SHL) {
+ __ shl(left.reg(), shift_amount);
+ } else {
+ ASSERT(op == Token::SHR);
+ __ shr(left.reg(), shift_amount);
+ if (shift_amount == 0) test_shr_overflow = true;
+ }
+ } else {
+ // Move right to ecx
+ if (left.is_register() && left.reg().is(ecx)) {
+ right.ToRegister();
+ __ xchg(left.reg(), right.reg());
+ left = right; // Left is unused here, copy of right unused by Push.
+ } else {
+ right.ToRegister(ecx);
+ left.ToRegister();
+ }
+ if (op == Token::SAR) {
+ __ sar_cl(left.reg());
+ } else if (op == Token::SHL) {
+ __ shl_cl(left.reg());
+ } else {
+ ASSERT(op == Token::SHR);
+ __ shr_cl(left.reg());
+ test_shr_overflow = true;
+ }
+ }
+ {
+ Register left_reg = left.reg();
+ frame_->Push(&left);
+ right.Unuse();
+ if (test_shr_overflow && !node->to_int32()) {
+ // Uint32 results with top bit set are not Int32 values.
+ // If they will be forced to Int32, skip the test.
+ // Test is needed because shr with shift amount 0 does not set flags.
+ __ test(left_reg, Operand(left_reg));
+ unsafe_bailout_->Branch(sign);
+ }
+ }
+ break;
+ }
+ case Token::ADD:
+ case Token::SUB:
+ case Token::MUL:
+ left.ToRegister();
+ right.ToRegister();
+ if (op == Token::ADD) {
+ __ add(left.reg(), Operand(right.reg()));
+ } else if (op == Token::SUB) {
+ __ sub(left.reg(), Operand(right.reg()));
+ } else {
+ ASSERT(op == Token::MUL);
+ // We have statically verified that a negative zero can be ignored.
+ __ imul(left.reg(), Operand(right.reg()));
+ }
+ right.Unuse();
+ frame_->Push(&left);
+ if (!node->to_int32()) {
+ // If ToInt32 is called on the result of ADD, SUB, or MUL, we don't
+ // care about overflows.
+ unsafe_bailout_->Branch(overflow);
+ }
+ break;
+ case Token::DIV:
+ case Token::MOD: {
+ if (right.is_register() && (right.reg().is(eax) || right.reg().is(edx))) {
+ if (left.is_register() && left.reg().is(edi)) {
+ right.ToRegister(ebx);
+ } else {
+ right.ToRegister(edi);
+ }
+ }
+ left.ToRegister(eax);
+ Result edx_reg = allocator_->Allocate(edx);
+ right.ToRegister();
+ // The results are unused here because BreakTarget::Branch cannot handle
+ // live results.
+ Register right_reg = right.reg();
+ left.Unuse();
+ right.Unuse();
+ edx_reg.Unuse();
+ __ cmp(right_reg, 0);
+ // Ensure divisor is positive: no chance of non-int32 or -0 result.
+ unsafe_bailout_->Branch(less_equal);
+ __ cdq(); // Sign-extend eax into edx:eax
+ __ idiv(right_reg);
+ if (op == Token::MOD) {
+ Result edx_result(edx, NumberInfo::Integer32());
+ edx_result.set_untagged_int32(true);
+ frame_->Push(&edx_result);
+ } else {
+ ASSERT(op == Token::DIV);
+ __ test(edx, Operand(edx));
+ unsafe_bailout_->Branch(not_equal);
+ Result eax_result(eax, NumberInfo::Integer32());
+ eax_result.set_untagged_int32(true);
+ frame_->Push(&eax_result);
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+}
+
void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
Comment cmnt(masm_, "[ BinaryOperation");
Token::Value op = node->op();
@@ -6687,6 +7166,7 @@
// is necessary because we assume that if we get control flow on the
// last path out of an expression we got it on all paths.
if (op == Token::AND) {
+ ASSERT(!in_safe_int32_mode());
JumpTarget is_true;
ControlDestination dest(&is_true, destination()->false_target(), true);
LoadCondition(node->left(), &dest, false);
@@ -6750,6 +7230,7 @@
}
} else if (op == Token::OR) {
+ ASSERT(!in_safe_int32_mode());
JumpTarget is_false;
ControlDestination dest(destination()->true_target(), &is_false, false);
LoadCondition(node->left(), &dest, false);
@@ -6811,6 +7292,10 @@
exit.Bind();
}
+ } else if (in_safe_int32_mode()) {
+ Visit(node->left());
+ Visit(node->right());
+ Int32BinaryOperation(node);
} else {
// NOTE: The code below assumes that the slow cases (calls to runtime)
// never return a constant/immutable object.
@@ -6823,19 +7308,29 @@
overwrite_mode = OVERWRITE_RIGHT;
}
- Load(node->left());
- Load(node->right());
- GenericBinaryOperation(node->op(), node->type(), overwrite_mode);
+ if (node->left()->IsTrivial()) {
+ Load(node->right());
+ Result right = frame_->Pop();
+ frame_->Push(node->left());
+ frame_->Push(&right);
+ } else {
+ Load(node->left());
+ Load(node->right());
+ }
+ GenericBinaryOperation(node->op(), node->type(),
+ overwrite_mode, node->no_negative_zero());
}
}
void CodeGenerator::VisitThisFunction(ThisFunction* node) {
+ ASSERT(!in_safe_int32_mode());
frame_->PushFunction();
}
void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
+ ASSERT(!in_safe_int32_mode());
Comment cmnt(masm_, "[ CompareOperation");
bool left_already_loaded = false;
@@ -7024,8 +7519,20 @@
default:
UNREACHABLE();
}
- if (!left_already_loaded) Load(left);
- Load(right);
+
+ if (left->IsTrivial()) {
+ if (!left_already_loaded) {
+ Load(right);
+ Result right_result = frame_->Pop();
+ frame_->Push(left);
+ frame_->Push(&right_result);
+ } else {
+ Load(right);
+ }
+ } else {
+ if (!left_already_loaded) Load(left);
+ Load(right);
+ }
Comparison(node, cc, strict, destination());
}
@@ -7371,6 +7878,8 @@
if (!key.is_smi()) {
__ test(key.reg(), Immediate(kSmiTagMask));
deferred->Branch(not_zero);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(key.reg());
}
// Get the elements array from the receiver and check that it
@@ -7524,6 +8033,8 @@
if (!left_info.IsSmi()) {
__ test(left, Immediate(kSmiTagMask));
deferred->Branch(not_zero);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(left);
}
} else if (!left_info.IsSmi()) {
if (!right_info.IsSmi()) {
@@ -7534,11 +8045,15 @@
} else {
__ test(left, Immediate(kSmiTagMask));
deferred->Branch(not_zero);
+ if (FLAG_debug_code) __ AbortIfNotSmi(right);
}
} else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(left);
if (!right_info.IsSmi()) {
__ test(right, Immediate(kSmiTagMask));
deferred->Branch(not_zero);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(right);
}
}
}
@@ -8045,6 +8560,10 @@
}
if (static_operands_type_.IsSmi()) {
+ if (FLAG_debug_code) {
+ __ AbortIfNotSmi(left);
+ __ AbortIfNotSmi(right);
+ }
if (op_ == Token::BIT_OR) {
__ or_(right, Operand(left));
GenerateReturn(masm);
@@ -8399,12 +8918,14 @@
if (static_operands_type_.IsNumber()) {
if (FLAG_debug_code) {
// Assert at runtime that inputs are only numbers.
- __ AbortIfNotNumber(edx,
- "GenericBinaryOpStub operand not a number.");
- __ AbortIfNotNumber(eax,
- "GenericBinaryOpStub operand not a number.");
+ __ AbortIfNotNumber(edx);
+ __ AbortIfNotNumber(eax);
}
if (static_operands_type_.IsSmi()) {
+ if (FLAG_debug_code) {
+ __ AbortIfNotSmi(edx);
+ __ AbortIfNotSmi(eax);
+ }
FloatingPointHelper::LoadSSE2Smis(masm, ecx);
} else {
FloatingPointHelper::LoadSSE2Operands(masm);
@@ -8427,10 +8948,8 @@
if (static_operands_type_.IsNumber()) {
if (FLAG_debug_code) {
// Assert at runtime that inputs are only numbers.
- __ AbortIfNotNumber(edx,
- "GenericBinaryOpStub operand not a number.");
- __ AbortIfNotNumber(eax,
- "GenericBinaryOpStub operand not a number.");
+ __ AbortIfNotNumber(edx);
+ __ AbortIfNotNumber(eax);
}
} else {
FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
@@ -8792,9 +9311,9 @@
__ bind(&get_result);
}
+
Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) {
GenericBinaryOpStub stub(key, type_info);
- HandleScope scope;
return stub.GetCode();
}
@@ -9160,6 +9679,8 @@
if (!number_info.IsSmi()) {
__ test(edx, Immediate(kSmiTagMask));
__ j(not_zero, &arg1_is_object);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(edx);
}
__ SmiUntag(edx);
__ jmp(&load_arg2);
@@ -9178,6 +9699,8 @@
if (!number_info.IsSmi()) {
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, &arg2_is_object);
+ } else {
+ if (FLAG_debug_code) __ AbortIfNotSmi(eax);
}
__ SmiUntag(eax);
__ mov(ecx, eax);
@@ -10065,15 +10588,7 @@
__ j(negative, &done);
// Read the value from the static offsets vector buffer.
__ mov(edi, Operand(ecx, edx, times_int_size, 0));
- // Perform explicit shift
- ASSERT_EQ(0, kSmiTag);
- __ shl(edi, kSmiTagSize);
- // Add previous index (from its stack slot) if value is not negative.
- Label capture_negative;
- // Carry flag set by shift above.
- __ j(negative, &capture_negative, not_taken);
- __ add(edi, Operand(eax)); // Add previous index (adding smi to smi).
- __ bind(&capture_negative);
+ __ SmiTag(edi);
// Store the smi value in the last match info.
__ mov(FieldOperand(ebx,
edx,
@@ -10162,6 +10677,12 @@
}
+void RecordWriteStub::Generate(MacroAssembler* masm) {
+ masm->RecordWriteHelper(object_, addr_, scratch_);
+ masm->ret(0);
+}
+
+
void CompareStub::Generate(MacroAssembler* masm) {
Label call_builtin, done;

Powered by Google App Engine
This is Rietveld 408576698