Index: src/x64/lithium-codegen-x64.cc |
=================================================================== |
--- src/x64/lithium-codegen-x64.cc (revision 9531) |
+++ src/x64/lithium-codegen-x64.cc (working copy) |
@@ -81,6 +81,12 @@ |
HPhase phase("Code generation", chunk()); |
ASSERT(is_unused()); |
status_ = GENERATING; |
+ |
+ // Open a frame scope to indicate that there is a frame on the stack. The |
+ // MANUAL indicates that the scope shouldn't actually generate code to set up |
+ // the frame (that is done in GeneratePrologue). |
+ FrameScope frame_scope(masm_, StackFrame::MANUAL); |
+ |
return GeneratePrologue() && |
GenerateBody() && |
GenerateDeferredCode() && |
@@ -217,11 +223,8 @@ |
// Store it in the context. |
int context_offset = Context::SlotOffset(var->index()); |
__ movq(Operand(rsi, context_offset), rax); |
- // Update the write barrier. This clobbers all involved |
- // registers, so we have use a third register to avoid |
- // clobbering rsi. |
- __ movq(rcx, rsi); |
- __ RecordWrite(rcx, context_offset, rax, rbx); |
+ // Update the write barrier. This clobbers rax and rbx. |
+ __ RecordWriteContextSlot(rsi, context_offset, rax, rbx, kSaveFPRegs); |
} |
} |
Comment(";;; End allocate local context"); |
@@ -280,6 +283,9 @@ |
for (int i = 0; !is_aborted() && i < deferred_.length(); i++) { |
LDeferredCode* code = deferred_[i]; |
__ bind(code->entry()); |
+ Comment(";;; Deferred code @%d: %s.", |
+ code->instruction_index(), |
+ code->instr()->Mnemonic()); |
code->Generate(); |
__ jmp(code->exit()); |
} |
@@ -667,7 +673,7 @@ |
int deoptimization_index) { |
ASSERT(kind == expected_safepoint_kind_); |
- const ZoneList<LOperand*>* operands = pointers->operands(); |
+ const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands(); |
Safepoint safepoint = safepoints_.DefineSafepoint(masm(), |
kind, arguments, deoptimization_index); |
@@ -1577,30 +1583,33 @@ |
} |
-void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { |
+void LCodeGen::DoIsNilAndBranch(LIsNilAndBranch* instr) { |
Register reg = ToRegister(instr->InputAt(0)); |
- |
int false_block = chunk_->LookupDestination(instr->false_block_id()); |
+ // If the expression is known to be untagged or a smi, then it's definitely |
+ // not null, and it can't be a an undetectable object. |
if (instr->hydrogen()->representation().IsSpecialization() || |
instr->hydrogen()->type().IsSmi()) { |
- // If the expression is known to untagged or smi, then it's definitely |
- // not null, and it can't be a an undetectable object. |
- // Jump directly to the false block. |
EmitGoto(false_block); |
return; |
} |
int true_block = chunk_->LookupDestination(instr->true_block_id()); |
- |
- __ CompareRoot(reg, Heap::kNullValueRootIndex); |
- if (instr->is_strict()) { |
+ Heap::RootListIndex nil_value = instr->nil() == kNullValue ? |
+ Heap::kNullValueRootIndex : |
+ Heap::kUndefinedValueRootIndex; |
+ __ CompareRoot(reg, nil_value); |
+ if (instr->kind() == kStrictEquality) { |
EmitBranch(true_block, false_block, equal); |
} else { |
+ Heap::RootListIndex other_nil_value = instr->nil() == kNullValue ? |
+ Heap::kUndefinedValueRootIndex : |
+ Heap::kNullValueRootIndex; |
Label* true_label = chunk_->GetAssemblyLabel(true_block); |
Label* false_label = chunk_->GetAssemblyLabel(false_block); |
__ j(equal, true_label); |
- __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); |
+ __ CompareRoot(reg, other_nil_value); |
__ j(equal, true_label); |
__ JumpIfSmi(reg, false_label); |
// Check for undetectable objects by looking in the bit field in |
@@ -1752,30 +1761,40 @@ |
Label* is_false, |
Handle<String> class_name, |
Register input, |
- Register temp) { |
+ Register temp, |
+ Register scratch) { |
__ JumpIfSmi(input, is_false); |
- __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp); |
- __ j(below, is_false); |
- // Map is now in temp. |
- // Functions have class 'Function'. |
- __ CmpInstanceType(temp, FIRST_CALLABLE_SPEC_OBJECT_TYPE); |
if (class_name->IsEqualTo(CStrVector("Function"))) { |
- __ j(above_equal, is_true); |
+ // Assuming the following assertions, we can use the same compares to test |
+ // for both being a function type and being in the object type range. |
+ STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
+ STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE == |
+ FIRST_SPEC_OBJECT_TYPE + 1); |
+ STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == |
+ LAST_SPEC_OBJECT_TYPE - 1); |
+ STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE); |
+ __ CmpObjectType(input, FIRST_SPEC_OBJECT_TYPE, temp); |
+ __ j(below, is_false); |
+ __ j(equal, is_true); |
+ __ CmpInstanceType(temp, LAST_SPEC_OBJECT_TYPE); |
+ __ j(equal, is_true); |
} else { |
- __ j(above_equal, is_false); |
+ // Faster code path to avoid two compares: subtract lower bound from the |
+ // actual type and do a signed compare with the width of the type range. |
+ __ movq(temp, FieldOperand(input, HeapObject::kMapOffset)); |
+ __ movq(scratch, FieldOperand(temp, Map::kInstanceTypeOffset)); |
+ __ subb(scratch, Immediate(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE)); |
+ __ cmpb(scratch, |
+ Immediate(static_cast<int8_t>(LAST_NONCALLABLE_SPEC_OBJECT_TYPE - |
+ FIRST_NONCALLABLE_SPEC_OBJECT_TYPE))); |
+ __ j(above, is_false); |
} |
+ // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range. |
// Check if the constructor in the map is a function. |
__ movq(temp, FieldOperand(temp, Map::kConstructorOffset)); |
- // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last type and |
- // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after |
- // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter. |
- STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE); |
- STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE == |
- LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1); |
- |
// Objects with a non-function constructor have class 'Object'. |
__ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister); |
if (class_name->IsEqualTo(CStrVector("Object"))) { |
@@ -1804,6 +1823,7 @@ |
void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
Register input = ToRegister(instr->InputAt(0)); |
Register temp = ToRegister(instr->TempAt(0)); |
+ Register temp2 = ToRegister(instr->TempAt(1)); |
Handle<String> class_name = instr->hydrogen()->class_name(); |
int true_block = chunk_->LookupDestination(instr->true_block_id()); |
@@ -1812,7 +1832,7 @@ |
Label* true_label = chunk_->GetAssemblyLabel(true_block); |
Label* false_label = chunk_->GetAssemblyLabel(false_block); |
- EmitClassOfTest(true_label, false_label, class_name, input, temp); |
+ EmitClassOfTest(true_label, false_label, class_name, input, temp, temp2); |
EmitBranch(true_block, false_block, equal); |
} |
@@ -1853,9 +1873,8 @@ |
virtual void Generate() { |
codegen()->DoDeferredLInstanceOfKnownGlobal(instr_, &map_check_); |
} |
- |
+ virtual LInstruction* instr() { return instr_; } |
Label* map_check() { return &map_check_; } |
- |
private: |
LInstanceOfKnownGlobal* instr_; |
Label map_check_; |
@@ -1996,7 +2015,7 @@ |
__ movq(result, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); |
__ movq(result, Operand(result, 0)); |
} |
- if (instr->hydrogen()->check_hole_value()) { |
+ if (instr->hydrogen()->RequiresHoleCheck()) { |
__ CompareRoot(result, Heap::kTheHoleValueRootIndex); |
DeoptimizeIf(equal, instr->environment()); |
} |
@@ -2016,25 +2035,39 @@ |
void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) { |
+ Register object = ToRegister(instr->TempAt(0)); |
+ Register address = ToRegister(instr->TempAt(1)); |
Register value = ToRegister(instr->InputAt(0)); |
- Register temp = ToRegister(instr->TempAt(0)); |
- ASSERT(!value.is(temp)); |
- bool check_hole = instr->hydrogen()->check_hole_value(); |
- if (!check_hole && value.is(rax)) { |
- __ store_rax(instr->hydrogen()->cell().location(), |
- RelocInfo::GLOBAL_PROPERTY_CELL); |
- return; |
- } |
+ ASSERT(!value.is(object)); |
+ Handle<JSGlobalPropertyCell> cell_handle(instr->hydrogen()->cell()); |
+ |
+ __ movq(address, cell_handle, RelocInfo::GLOBAL_PROPERTY_CELL); |
+ |
// If the cell we are storing to contains the hole it could have |
// been deleted from the property dictionary. In that case, we need |
// to update the property details in the property dictionary to mark |
// it as no longer deleted. We deoptimize in that case. |
- __ movq(temp, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL); |
- if (check_hole) { |
- __ CompareRoot(Operand(temp, 0), Heap::kTheHoleValueRootIndex); |
+ if (instr->hydrogen()->RequiresHoleCheck()) { |
+ __ CompareRoot(Operand(address, 0), Heap::kTheHoleValueRootIndex); |
DeoptimizeIf(equal, instr->environment()); |
} |
- __ movq(Operand(temp, 0), value); |
+ |
+ // Store the value. |
+ __ movq(Operand(address, 0), value); |
+ |
+ Label smi_store; |
+ __ JumpIfSmi(value, &smi_store, Label::kNear); |
+ |
+ int offset = JSGlobalPropertyCell::kValueOffset - kHeapObjectTag; |
+ __ lea(object, Operand(address, -offset)); |
+ // Cells are always in the remembered set. |
+ __ RecordWrite(object, |
+ address, |
+ value, |
+ kSaveFPRegs, |
+ OMIT_REMEMBERED_SET, |
+ OMIT_SMI_CHECK); |
+ __ bind(&smi_store); |
} |
@@ -2064,7 +2097,7 @@ |
if (instr->needs_write_barrier()) { |
int offset = Context::SlotOffset(instr->slot_index()); |
Register scratch = ToRegister(instr->TempAt(0)); |
- __ RecordWrite(context, offset, value, scratch); |
+ __ RecordWriteContextSlot(context, offset, value, scratch, kSaveFPRegs); |
} |
} |
@@ -2283,17 +2316,15 @@ |
LLoadKeyedFastDoubleElement* instr) { |
XMMRegister result(ToDoubleRegister(instr->result())); |
- if (instr->hydrogen()->RequiresHoleCheck()) { |
- int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag + |
- sizeof(kHoleNanLower32); |
- Operand hole_check_operand = BuildFastArrayOperand( |
- instr->elements(), |
- instr->key(), |
- FAST_DOUBLE_ELEMENTS, |
- offset); |
- __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32)); |
- DeoptimizeIf(equal, instr->environment()); |
- } |
+ int offset = FixedDoubleArray::kHeaderSize - kHeapObjectTag + |
+ sizeof(kHoleNanLower32); |
+ Operand hole_check_operand = BuildFastArrayOperand( |
+ instr->elements(), |
+ instr->key(), |
+ FAST_DOUBLE_ELEMENTS, |
+ offset); |
+ __ cmpl(hole_check_operand, Immediate(kHoleNanUpper32)); |
+ DeoptimizeIf(equal, instr->environment()); |
Operand double_load_operand = BuildFastArrayOperand( |
instr->elements(), instr->key(), FAST_DOUBLE_ELEMENTS, |
@@ -2365,6 +2396,7 @@ |
case EXTERNAL_FLOAT_ELEMENTS: |
case EXTERNAL_DOUBLE_ELEMENTS: |
case FAST_ELEMENTS: |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: |
case DICTIONARY_ELEMENTS: |
case NON_STRICT_ARGUMENTS_ELEMENTS: |
@@ -2681,6 +2713,7 @@ |
virtual void Generate() { |
codegen()->DoDeferredMathAbsTaggedHeapNumber(instr_); |
} |
+ virtual LInstruction* instr() { return instr_; } |
private: |
LUnaryMathOperation* instr_; |
}; |
@@ -2977,7 +3010,7 @@ |
ASSERT(ToRegister(instr->result()).is(rax)); |
int arity = instr->arity(); |
- CallFunctionStub stub(arity, RECEIVER_MIGHT_BE_IMPLICIT); |
+ CallFunctionStub stub(arity, NO_CALL_FUNCTION_FLAGS); |
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr); |
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
__ Drop(1); |
@@ -3033,7 +3066,7 @@ |
if (instr->needs_write_barrier()) { |
Register temp = ToRegister(instr->TempAt(0)); |
// Update the write barrier for the object for in-object properties. |
- __ RecordWrite(object, offset, value, temp); |
+ __ RecordWriteField(object, offset, value, temp, kSaveFPRegs); |
} |
} else { |
Register temp = ToRegister(instr->TempAt(0)); |
@@ -3042,7 +3075,7 @@ |
if (instr->needs_write_barrier()) { |
// Update the write barrier for the properties array. |
// object is used as a scratch register. |
- __ RecordWrite(temp, offset, value, object); |
+ __ RecordWriteField(temp, offset, value, object, kSaveFPRegs); |
} |
} |
} |
@@ -3090,6 +3123,7 @@ |
case EXTERNAL_FLOAT_ELEMENTS: |
case EXTERNAL_DOUBLE_ELEMENTS: |
case FAST_ELEMENTS: |
+ case FAST_SMI_ONLY_ELEMENTS: |
case FAST_DOUBLE_ELEMENTS: |
case DICTIONARY_ELEMENTS: |
case NON_STRICT_ARGUMENTS_ELEMENTS: |
@@ -3125,6 +3159,13 @@ |
Register elements = ToRegister(instr->object()); |
Register key = instr->key()->IsRegister() ? ToRegister(instr->key()) : no_reg; |
+ // This instruction cannot handle the FAST_SMI_ONLY_ELEMENTS -> FAST_ELEMENTS |
+ // conversion, so it deopts in that case. |
+ if (instr->hydrogen()->ValueNeedsSmiCheck()) { |
+ Condition cc = masm()->CheckSmi(value); |
+ DeoptimizeIf(NegateCondition(cc), instr->environment()); |
+ } |
+ |
// Do the store. |
if (instr->key()->IsConstantOperand()) { |
ASSERT(!instr->hydrogen()->NeedsWriteBarrier()); |
@@ -3146,7 +3187,7 @@ |
key, |
times_pointer_size, |
FixedArray::kHeaderSize)); |
- __ RecordWrite(elements, key, value); |
+ __ RecordWrite(elements, key, value, kSaveFPRegs); |
} |
} |
@@ -3196,6 +3237,7 @@ |
DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr) |
: LDeferredCode(codegen), instr_(instr) { } |
virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); } |
+ virtual LInstruction* instr() { return instr_; } |
private: |
LStringCharCodeAt* instr_; |
}; |
@@ -3316,6 +3358,7 @@ |
DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr) |
: LDeferredCode(codegen), instr_(instr) { } |
virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); } |
+ virtual LInstruction* instr() { return instr_; } |
private: |
LStringCharFromCode* instr_; |
}; |
@@ -3392,6 +3435,7 @@ |
DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
: LDeferredCode(codegen), instr_(instr) { } |
virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
+ virtual LInstruction* instr() { return instr_; } |
private: |
LNumberTagD* instr_; |
}; |
@@ -3487,16 +3531,6 @@ |
} |
-class DeferredTaggedToI: public LDeferredCode { |
- public: |
- DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) |
- : LDeferredCode(codegen), instr_(instr) { } |
- virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } |
- private: |
- LTaggedToI* instr_; |
-}; |
- |
- |
void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) { |
Label done, heap_number; |
Register input_reg = ToRegister(instr->InputAt(0)); |
@@ -3545,6 +3579,16 @@ |
void LCodeGen::DoTaggedToI(LTaggedToI* instr) { |
+ class DeferredTaggedToI: public LDeferredCode { |
+ public: |
+ DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr) |
+ : LDeferredCode(codegen), instr_(instr) { } |
+ virtual void Generate() { codegen()->DoDeferredTaggedToI(instr_); } |
+ virtual LInstruction* instr() { return instr_; } |
+ private: |
+ LTaggedToI* instr_; |
+ }; |
+ |
LOperand* input = instr->InputAt(0); |
ASSERT(input->IsRegister()); |
ASSERT(input->Equals(instr->result())); |
@@ -3981,9 +4025,12 @@ |
final_branch_condition = not_zero; |
} else if (type_name->Equals(heap()->function_symbol())) { |
+ STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2); |
__ JumpIfSmi(input, false_label); |
- __ CmpObjectType(input, FIRST_CALLABLE_SPEC_OBJECT_TYPE, input); |
- final_branch_condition = above_equal; |
+ __ CmpObjectType(input, JS_FUNCTION_TYPE, input); |
+ __ j(equal, true_label); |
+ __ CmpInstanceType(input, JS_FUNCTION_PROXY_TYPE); |
+ final_branch_condition = equal; |
} else if (type_name->Equals(heap()->object_symbol())) { |
__ JumpIfSmi(input, false_label); |
@@ -4109,6 +4156,7 @@ |
DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr) |
: LDeferredCode(codegen), instr_(instr) { } |
virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); } |
+ virtual LInstruction* instr() { return instr_; } |
private: |
LStackCheck* instr_; |
}; |