Index: src/x64/lithium-codegen-x64.cc |
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc |
index f30e56208c614bebeee629f4a4ec016086c983e1..15c1aae463f2ebeb900e05b358fb1bcc8efbbbea 100644 |
--- a/src/x64/lithium-codegen-x64.cc |
+++ b/src/x64/lithium-codegen-x64.cc |
@@ -1160,7 +1160,18 @@ void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) { |
void LCodeGen::DoCmpJSObjectEq(LCmpJSObjectEq* instr) { |
- Abort("Unimplemented: %s", "DoCmpJSObjectEq"); |
+ Register left = ToRegister(instr->InputAt(0)); |
+ Register right = ToRegister(instr->InputAt(1)); |
+ Register result = ToRegister(instr->result()); |
+ |
+ NearLabel different, done; |
+ __ cmpq(left, right); |
+ __ j(not_equal, &different); |
+ __ LoadRoot(result, Heap::kTrueValueRootIndex); |
+ __ jmp(&done); |
+ __ bind(&different); |
+ __ LoadRoot(result, Heap::kFalseValueRootIndex); |
+ __ bind(&done); |
} |
@@ -1176,7 +1187,45 @@ void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) { |
void LCodeGen::DoIsNull(LIsNull* instr) { |
- Abort("Unimplemented: %s", "DoIsNull"); |
+ Register reg = ToRegister(instr->InputAt(0)); |
+ Register result = ToRegister(instr->result()); |
+ |
+ // If the expression is known to be a smi, then it's |
+ // definitely not null. Materialize false. |
+ // Consider adding other type and representation tests too. |
+ if (instr->hydrogen()->value()->type().IsSmi()) { |
+ __ LoadRoot(result, Heap::kFalseValueRootIndex); |
+ return; |
+ } |
+ |
+ __ CompareRoot(reg, Heap::kNullValueRootIndex); |
+ if (instr->is_strict()) { |
+ __ movl(result, Immediate(Heap::kTrueValueRootIndex)); |
+ NearLabel load; |
+ __ j(equal, &load); |
+ __ movl(result, Immediate(Heap::kFalseValueRootIndex)); |
+ __ bind(&load); |
+ __ movq(result, Operand(kRootRegister, result, times_pointer_size, 0)); |
+ } else { |
+ NearLabel true_value, false_value, done; |
+ __ j(equal, &true_value); |
+ __ CompareRoot(reg, Heap::kUndefinedValueRootIndex); |
+ __ j(equal, &true_value); |
+ __ JumpIfSmi(reg, &false_value); |
+ // Check for undetectable objects by looking in the bit field in |
+ // the map. The object has already been smi checked. |
+ Register scratch = result; |
+ __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset)); |
+ __ testb(FieldOperand(scratch, Map::kBitFieldOffset), |
+ Immediate(1 << Map::kIsUndetectable)); |
+ __ j(not_zero, &true_value); |
+ __ bind(&false_value); |
+ __ LoadRoot(result, Heap::kFalseValueRootIndex); |
+ __ jmp(&done); |
+ __ bind(&true_value); |
+ __ LoadRoot(result, Heap::kTrueValueRootIndex); |
+ __ bind(&done); |
+ } |
} |
@@ -1218,56 +1267,77 @@ void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) { |
Condition LCodeGen::EmitIsObject(Register input, |
- Register temp1, |
- Register temp2, |
Label* is_not_object, |
Label* is_object) { |
- ASSERT(!input.is(temp1)); |
- ASSERT(!input.is(temp2)); |
- ASSERT(!temp1.is(temp2)); |
+ ASSERT(!input.is(kScratchRegister)); |
__ JumpIfSmi(input, is_not_object); |
- __ Cmp(input, Factory::null_value()); |
+ __ CompareRoot(input, Heap::kNullValueRootIndex); |
__ j(equal, is_object); |
- __ movq(temp1, FieldOperand(input, HeapObject::kMapOffset)); |
+ __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset)); |
// Undetectable objects behave like undefined. |
- __ testb(FieldOperand(temp1, Map::kBitFieldOffset), |
+ __ testb(FieldOperand(kScratchRegister, Map::kBitFieldOffset), |
Immediate(1 << Map::kIsUndetectable)); |
__ j(not_zero, is_not_object); |
- __ movzxbl(temp2, FieldOperand(temp1, Map::kInstanceTypeOffset)); |
- __ cmpb(temp2, Immediate(FIRST_JS_OBJECT_TYPE)); |
+ __ movzxbl(kScratchRegister, |
+ FieldOperand(kScratchRegister, Map::kInstanceTypeOffset)); |
+ __ cmpb(kScratchRegister, Immediate(FIRST_JS_OBJECT_TYPE)); |
__ j(below, is_not_object); |
- __ cmpb(temp2, Immediate(LAST_JS_OBJECT_TYPE)); |
+ __ cmpb(kScratchRegister, Immediate(LAST_JS_OBJECT_TYPE)); |
return below_equal; |
} |
void LCodeGen::DoIsObject(LIsObject* instr) { |
- Abort("Unimplemented: %s", "DoIsObject"); |
+ Register reg = ToRegister(instr->InputAt(0)); |
+ Register result = ToRegister(instr->result()); |
+ Label is_false, is_true, done; |
+ |
+ Condition true_cond = EmitIsObject(reg, &is_false, &is_true); |
+ __ j(true_cond, &is_true); |
+ |
+ __ bind(&is_false); |
+ __ LoadRoot(result, Heap::kFalseValueRootIndex); |
+ __ jmp(&done); |
+ |
+ __ bind(&is_true); |
+ __ LoadRoot(result, Heap::kTrueValueRootIndex); |
+ |
+ __ bind(&done); |
} |
void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) { |
Register reg = ToRegister(instr->InputAt(0)); |
- Register temp = ToRegister(instr->TempAt(0)); |
- Register temp2 = ToRegister(instr->TempAt(1)); |
int true_block = chunk_->LookupDestination(instr->true_block_id()); |
int false_block = chunk_->LookupDestination(instr->false_block_id()); |
Label* true_label = chunk_->GetAssemblyLabel(true_block); |
Label* false_label = chunk_->GetAssemblyLabel(false_block); |
- Condition true_cond = EmitIsObject(reg, temp, temp2, false_label, true_label); |
+ Condition true_cond = EmitIsObject(reg, false_label, true_label); |
EmitBranch(true_block, false_block, true_cond); |
} |
void LCodeGen::DoIsSmi(LIsSmi* instr) { |
- Abort("Unimplemented: %s", "DoIsSmi"); |
+ LOperand* input_operand = instr->InputAt(0); |
+ Register result = ToRegister(instr->result()); |
+ if (input_operand->IsRegister()) { |
+ Register input = ToRegister(input_operand); |
+ __ CheckSmiToIndicator(result, input); |
+ } else { |
+ Operand input = ToOperand(instr->InputAt(0)); |
+ __ CheckSmiToIndicator(result, input); |
+ } |
+ // result is zero if input is a smi, and one otherwise. |
+ ASSERT(Heap::kFalseValueRootIndex == Heap::kTrueValueRootIndex + 1); |
+ __ movq(result, Operand(kRootRegister, result, times_pointer_size, |
+ Heap::kTrueValueRootIndex * kPointerSize)); |
} |
@@ -1400,7 +1470,25 @@ void LCodeGen::EmitClassOfTest(Label* is_true, |
void LCodeGen::DoClassOfTest(LClassOfTest* instr) { |
- Abort("Unimplemented: %s", "DoClassOfTest"); |
+ Register input = ToRegister(instr->InputAt(0)); |
+ Register result = ToRegister(instr->result()); |
+ ASSERT(input.is(result)); |
+ Register temp = ToRegister(instr->TempAt(0)); |
+ Handle<String> class_name = instr->hydrogen()->class_name(); |
+ NearLabel done; |
+ Label is_true, is_false; |
+ |
+ EmitClassOfTest(&is_true, &is_false, class_name, input, temp); |
+ |
+ __ j(not_equal, &is_false); |
+ |
+ __ bind(&is_true); |
+ __ LoadRoot(result, Heap::kTrueValueRootIndex); |
+ __ jmp(&done); |
+ |
+ __ bind(&is_false); |
+ __ LoadRoot(result, Heap::kFalseValueRootIndex); |
+ __ bind(&done); |
} |
@@ -1422,7 +1510,12 @@ void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) { |
void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) { |
- Abort("Unimplemented: %s", "DoCmpMapAndBranch"); |
+ Register reg = ToRegister(instr->InputAt(0)); |
+ int true_block = instr->true_block_id(); |
+ int false_block = instr->false_block_id(); |
+ |
+ __ Cmp(FieldOperand(reg, HeapObject::kMapOffset), instr->map()); |
+ EmitBranch(true_block, false_block, equal); |
} |
@@ -1714,27 +1807,63 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) { |
- Abort("Unimplemented: %s", "DoInteger32ToDouble"); |
+ LOperand* input = instr->InputAt(0); |
+ ASSERT(input->IsRegister() || input->IsStackSlot()); |
+ LOperand* output = instr->result(); |
+ ASSERT(output->IsDoubleRegister()); |
+ __ cvtlsi2sd(ToDoubleRegister(output), ToOperand(input)); |
} |
void LCodeGen::DoNumberTagI(LNumberTagI* instr) { |
- Abort("Unimplemented: %s", "DoNumberTagI"); |
-} |
+ LOperand* input = instr->InputAt(0); |
+ ASSERT(input->IsRegister() && input->Equals(instr->result())); |
+ Register reg = ToRegister(input); |
- |
-void LCodeGen::DoDeferredNumberTagI(LNumberTagI* instr) { |
- Abort("Unimplemented: %s", "DoDeferredNumberTagI"); |
+ __ Integer32ToSmi(reg, reg); |
} |
void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
- Abort("Unimplemented: %s", "DoNumberTagD"); |
+ class DeferredNumberTagD: public LDeferredCode { |
+ public: |
+ DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr) |
+ : LDeferredCode(codegen), instr_(instr) { } |
+ virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); } |
+ private: |
+ LNumberTagD* instr_; |
+ }; |
+ |
+ XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); |
+ Register reg = ToRegister(instr->result()); |
+ Register tmp = ToRegister(instr->TempAt(0)); |
+ |
+ DeferredNumberTagD* deferred = new DeferredNumberTagD(this, instr); |
+ if (FLAG_inline_new) { |
+ __ AllocateHeapNumber(reg, tmp, deferred->entry()); |
+ } else { |
+ __ jmp(deferred->entry()); |
+ } |
+ __ bind(deferred->exit()); |
+ __ movsd(FieldOperand(reg, HeapNumber::kValueOffset), input_reg); |
} |
void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) { |
- Abort("Unimplemented: %s", "DoDeferredNumberTagD"); |
+ // TODO(3095996): Get rid of this. For now, we need to make the |
+ // result register contain a valid pointer because it is already |
+ // contained in the register pointer map. |
+ Register reg = ToRegister(instr->result()); |
+ __ Move(reg, Smi::FromInt(0)); |
+ |
+ __ PushSafepointRegisters(); |
+ __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber); |
+ RecordSafepointWithRegisters( |
+ instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex); |
+ // Ensure that value in rax survives popping registers. |
+ __ movq(kScratchRegister, rax); |
+ __ PopSafepointRegisters(); |
+ __ movq(reg, kScratchRegister); |
} |
@@ -1751,7 +1880,34 @@ void LCodeGen::DoSmiUntag(LSmiUntag* instr) { |
void LCodeGen::EmitNumberUntagD(Register input_reg, |
XMMRegister result_reg, |
LEnvironment* env) { |
- Abort("Unimplemented: %s", "EmitNumberUntagD"); |
+ NearLabel load_smi, heap_number, done; |
+ |
+ // Smi check. |
+ __ JumpIfSmi(input_reg, &load_smi); |
+ |
+ // Heap number map check. |
+ __ CompareRoot(FieldOperand(input_reg, HeapObject::kMapOffset), |
+ Heap::kHeapNumberMapRootIndex); |
+ __ j(equal, &heap_number); |
+ |
+ __ CompareRoot(input_reg, Heap::kUndefinedValueRootIndex); |
+ DeoptimizeIf(not_equal, env); |
+ |
+ // Convert undefined to NaN. Compute NaN as 0/0. |
+ __ xorpd(result_reg, result_reg); |
+ __ divsd(result_reg, result_reg); |
+ __ jmp(&done); |
+ |
+ // Heap number to XMM conversion. |
+ __ bind(&heap_number); |
+ __ movsd(result_reg, FieldOperand(input_reg, HeapNumber::kValueOffset)); |
+ __ jmp(&done); |
+ |
+ // Smi to XMM conversion |
+ __ bind(&load_smi); |
+ __ SmiToInteger32(kScratchRegister, input_reg); // Untag smi first. |
+ __ cvtlsi2sd(result_reg, kScratchRegister); |
+ __ bind(&done); |
} |