Index: src/ia32/lithium-codegen-ia32.cc |
=================================================================== |
--- src/ia32/lithium-codegen-ia32.cc (revision 9808) |
+++ src/ia32/lithium-codegen-ia32.cc (working copy) |
@@ -355,6 +355,12 @@ |
} |
+double LCodeGen::ToDouble(LConstantOperand* op) const { |
+ Handle<Object> value = chunk_->LookupLiteral(op); |
+ return value->Number(); |
+} |
+ |
+ |
Immediate LCodeGen::ToImmediate(LOperand* op) { |
LConstantOperand* const_op = LConstantOperand::cast(op); |
Handle<Object> literal = chunk_->LookupLiteral(const_op); |
@@ -1574,32 +1580,40 @@ |
} |
-void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) { |
- if (right->IsConstantOperand()) { |
- __ cmp(ToOperand(left), ToImmediate(right)); |
- } else { |
- __ cmp(ToRegister(left), ToOperand(right)); |
- } |
-} |
- |
- |
void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
LOperand* left = instr->InputAt(0); |
LOperand* right = instr->InputAt(1); |
int false_block = chunk_->LookupDestination(instr->false_block_id()); |
int true_block = chunk_->LookupDestination(instr->true_block_id()); |
+ Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
- if (instr->is_double()) { |
- // Don't base result on EFLAGS when a NaN is involved. Instead |
- // jump to the false block. |
- __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
- __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); |
+ if (left->IsConstantOperand() && right->IsConstantOperand()) { |
+ // We can statically evaluate the comparison. |
+ double left_val = ToDouble(LConstantOperand::cast(left)); |
+ double right_val = ToDouble(LConstantOperand::cast(right)); |
+ int next_block = |
+ EvalComparison(instr->op(), left_val, right_val) ? true_block |
+ : false_block; |
+ EmitGoto(next_block); |
} else { |
- EmitCmpI(left, right); |
+ if (instr->is_double()) { |
+ // Don't base result on EFLAGS when a NaN is involved. Instead |
+ // jump to the false block. |
+ __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right)); |
+ __ j(parity_even, chunk_->GetAssemblyLabel(false_block)); |
+ } else { |
+ if (right->IsConstantOperand()) { |
+ __ cmp(ToRegister(left), ToImmediate(right)); |
+ } else if (left->IsConstantOperand()) { |
+ __ cmp(ToOperand(right), ToImmediate(left)); |
+ // We transposed the operands. Reverse the condition. |
+ cc = ReverseCondition(cc); |
+ } else { |
+ __ cmp(ToRegister(left), ToOperand(right)); |
+ } |
+ } |
+ EmitBranch(true_block, false_block, cc); |
} |
- |
- Condition cc = TokenToCondition(instr->op(), instr->is_double()); |
- EmitBranch(true_block, false_block, cc); |
} |
@@ -2029,9 +2043,6 @@ |
CallCode(ic, RelocInfo::CODE_TARGET, instr); |
Condition condition = ComputeCompareCondition(op); |
- if (op == Token::GT || op == Token::LTE) { |
- condition = ReverseCondition(condition); |
- } |
Label true_value, done; |
__ test(eax, Operand(eax)); |
__ j(condition, &true_value, Label::kNear); |
@@ -2116,12 +2127,18 @@ |
__ mov(FieldOperand(object, offset), value); |
// Cells are always in the remembered set. |
- __ RecordWriteField(object, |
- offset, |
- value, |
- address, |
- kSaveFPRegs, |
- OMIT_REMEMBERED_SET); |
+ if (instr->hydrogen()->NeedsWriteBarrier()) { |
+ HType type = instr->hydrogen()->value()->type(); |
+ SmiCheck check_needed = |
+ type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
+ __ RecordWriteField(object, |
+ offset, |
+ value, |
+ address, |
+ kSaveFPRegs, |
+ OMIT_REMEMBERED_SET, |
+ check_needed); |
+ } |
} |
@@ -2149,10 +2166,19 @@ |
Register context = ToRegister(instr->context()); |
Register value = ToRegister(instr->value()); |
__ mov(ContextOperand(context, instr->slot_index()), value); |
- if (instr->needs_write_barrier()) { |
+ if (instr->hydrogen()->NeedsWriteBarrier()) { |
+ HType type = instr->hydrogen()->value()->type(); |
+ SmiCheck check_needed = |
+ type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
Register temp = ToRegister(instr->TempAt(0)); |
int offset = Context::SlotOffset(instr->slot_index()); |
- __ RecordWriteContextSlot(context, offset, value, temp, kSaveFPRegs); |
+ __ RecordWriteContextSlot(context, |
+ offset, |
+ value, |
+ temp, |
+ kSaveFPRegs, |
+ EMIT_REMEMBERED_SET, |
+ check_needed); |
} |
} |
@@ -2173,7 +2199,7 @@ |
Register object, |
Handle<Map> type, |
Handle<String> name) { |
- LookupResult lookup; |
+ LookupResult lookup(isolate()); |
type->LookupInDescriptors(NULL, *name, &lookup); |
ASSERT(lookup.IsProperty() && |
(lookup.type() == FIELD || lookup.type() == CONSTANT_FUNCTION)); |
@@ -2614,7 +2640,7 @@ |
void LCodeGen::DoThisFunction(LThisFunction* instr) { |
Register result = ToRegister(instr->result()); |
- __ mov(result, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
+ LoadHeapObject(result, instr->hydrogen()->closure()); |
} |
@@ -3146,21 +3172,36 @@ |
} |
// Do the store. |
+ HType type = instr->hydrogen()->value()->type(); |
+ SmiCheck check_needed = |
+ type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
if (instr->is_in_object()) { |
__ mov(FieldOperand(object, offset), value); |
- if (instr->needs_write_barrier()) { |
+ if (instr->hydrogen()->NeedsWriteBarrier()) { |
Register temp = ToRegister(instr->TempAt(0)); |
// Update the write barrier for the object for in-object properties. |
- __ RecordWriteField(object, offset, value, temp, kSaveFPRegs); |
+ __ RecordWriteField(object, |
+ offset, |
+ value, |
+ temp, |
+ kSaveFPRegs, |
+ EMIT_REMEMBERED_SET, |
+ check_needed); |
} |
} else { |
Register temp = ToRegister(instr->TempAt(0)); |
__ mov(temp, FieldOperand(object, JSObject::kPropertiesOffset)); |
__ mov(FieldOperand(temp, offset), value); |
- if (instr->needs_write_barrier()) { |
+ if (instr->hydrogen()->NeedsWriteBarrier()) { |
// Update the write barrier for the properties array. |
// object is used as a scratch register. |
- __ RecordWriteField(temp, offset, value, object, kSaveFPRegs); |
+ __ RecordWriteField(temp, |
+ offset, |
+ value, |
+ object, |
+ kSaveFPRegs, |
+ EMIT_REMEMBERED_SET, |
+ check_needed); |
} |
} |
} |
@@ -3259,13 +3300,21 @@ |
} |
if (instr->hydrogen()->NeedsWriteBarrier()) { |
+ HType type = instr->hydrogen()->value()->type(); |
+ SmiCheck check_needed = |
+ type.IsHeapObject() ? OMIT_SMI_CHECK : INLINE_SMI_CHECK; |
// Compute address of modified element and store it into key register. |
__ lea(key, |
FieldOperand(elements, |
key, |
times_pointer_size, |
FixedArray::kHeaderSize)); |
- __ RecordWrite(elements, key, value, kSaveFPRegs); |
+ __ RecordWrite(elements, |
+ key, |
+ value, |
+ kSaveFPRegs, |
+ EMIT_REMEMBERED_SET, |
+ check_needed); |
} |
} |
@@ -3303,6 +3352,48 @@ |
} |
+void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
+ Register object_reg = ToRegister(instr->object()); |
+ Register new_map_reg = ToRegister(instr->new_map_reg()); |
+ |
+ Handle<Map> from_map = instr->original_map(); |
+ Handle<Map> to_map = instr->transitioned_map(); |
+ ElementsKind from_kind = from_map->elements_kind(); |
+ ElementsKind to_kind = to_map->elements_kind(); |
+ |
+ Label not_applicable; |
+ __ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map); |
+ __ j(not_equal, ¬_applicable); |
+ __ mov(new_map_reg, to_map); |
+ if (from_kind == FAST_SMI_ONLY_ELEMENTS && to_kind == FAST_ELEMENTS) { |
+ Register object_reg = ToRegister(instr->object()); |
+ __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg); |
+ // Write barrier. |
+ ASSERT_NE(instr->temp_reg(), NULL); |
+ __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, |
+ ToRegister(instr->temp_reg()), kDontSaveFPRegs); |
+ } else if (from_kind == FAST_SMI_ONLY_ELEMENTS && |
+ to_kind == FAST_DOUBLE_ELEMENTS) { |
+ Register fixed_object_reg = ToRegister(instr->temp_reg()); |
+ ASSERT(fixed_object_reg.is(edx)); |
+ ASSERT(new_map_reg.is(ebx)); |
+ __ mov(fixed_object_reg, object_reg); |
+ CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), |
+ RelocInfo::CODE_TARGET, instr); |
+ } else if (from_kind == FAST_DOUBLE_ELEMENTS && to_kind == FAST_ELEMENTS) { |
+ Register fixed_object_reg = ToRegister(instr->temp_reg()); |
+ ASSERT(fixed_object_reg.is(edx)); |
+ ASSERT(new_map_reg.is(ebx)); |
+ __ mov(fixed_object_reg, object_reg); |
+ CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(), |
+ RelocInfo::CODE_TARGET, instr); |
+ } else { |
+ UNREACHABLE(); |
+ } |
+ __ bind(¬_applicable); |
+} |
+ |
+ |
void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) { |
class DeferredStringCharCodeAt: public LDeferredCode { |
public: |
@@ -4095,11 +4186,17 @@ |
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { |
ASSERT(ToRegister(instr->context()).is(esi)); |
+ |
+ Handle<FixedArray> constant_elements = instr->hydrogen()->constant_elements(); |
+ ASSERT_EQ(2, constant_elements->length()); |
+ ElementsKind constant_elements_kind = |
+ static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value()); |
+ |
// Setup the parameters to the stub/runtime call. |
__ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); |
__ push(FieldOperand(eax, JSFunction::kLiteralsOffset)); |
__ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index()))); |
- __ push(Immediate(instr->hydrogen()->constant_elements())); |
+ __ push(Immediate(constant_elements)); |
// Pick the right runtime function or stub to call. |
int length = instr->hydrogen()->length(); |
@@ -4115,7 +4212,9 @@ |
CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr); |
} else { |
FastCloneShallowArrayStub::Mode mode = |
- FastCloneShallowArrayStub::CLONE_ELEMENTS; |
+ constant_elements_kind == FAST_DOUBLE_ELEMENTS |
+ ? FastCloneShallowArrayStub::CLONE_DOUBLE_ELEMENTS |
+ : FastCloneShallowArrayStub::CLONE_ELEMENTS; |
FastCloneShallowArrayStub stub(mode, length); |
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
} |
@@ -4214,8 +4313,7 @@ |
Handle<SharedFunctionInfo> shared_info = instr->shared_info(); |
bool pretenure = instr->hydrogen()->pretenure(); |
if (!pretenure && shared_info->num_literals() == 0) { |
- FastNewClosureStub stub( |
- shared_info->strict_mode() ? kStrictMode : kNonStrictMode); |
+ FastNewClosureStub stub(shared_info->strict_mode_flag()); |
__ push(Immediate(shared_info)); |
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
} else { |
@@ -4247,12 +4345,11 @@ |
Label* true_label = chunk_->GetAssemblyLabel(true_block); |
Label* false_label = chunk_->GetAssemblyLabel(false_block); |
- Condition final_branch_condition = EmitTypeofIs(true_label, |
- false_label, |
- input, |
- instr->type_literal()); |
- |
- EmitBranch(true_block, false_block, final_branch_condition); |
+ Condition final_branch_condition = |
+ EmitTypeofIs(true_label, false_label, input, instr->type_literal()); |
+ if (final_branch_condition != no_condition) { |
+ EmitBranch(true_block, false_block, final_branch_condition); |
+ } |
} |
@@ -4319,11 +4416,8 @@ |
final_branch_condition = zero; |
} else { |
- final_branch_condition = not_equal; |
__ jmp(false_label); |
- // A dead branch instruction will be generated after this point. |
} |
- |
return final_branch_condition; |
} |