Revision: 6385
Author: [email protected]
Date: Wed Jan 19 02:17:18 2011
Log: X64 Crank: Implemented DoBranch and all *AndBranch comparisons.

Review URL: http://codereview.chromium.org/6374002
http://code.google.com/p/v8/source/detail?r=6385

Modified:
 /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/x64/assembler-x64.h
 /branches/bleeding_edge/src/x64/code-stubs-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.h
 /branches/bleeding_edge/src/x64/lithium-x64.cc
 /branches/bleeding_edge/src/x64/lithium-x64.h
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.h
 /branches/bleeding_edge/test/cctest/cctest.status

=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Tue Jan 18 06:25:05 2011 +++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Jan 19 02:17:18 2011
@@ -1285,11 +1285,11 @@

   NearLabel done;
   Condition cc = TokenToCondition(instr->op(), instr->is_double());
-  __ mov(ToRegister(result), Handle<Object>(Heap::true_value()));
+  __ mov(ToRegister(result), Factory::true_value());
   __ j(cc, &done);

   __ bind(&unordered);
-  __ mov(ToRegister(result), Handle<Object>(Heap::false_value()));
+  __ mov(ToRegister(result), Factory::false_value());
   __ bind(&done);
 }

@@ -1320,10 +1320,10 @@
   Register result = ToRegister(instr->result());

   __ cmp(left, Operand(right));
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   NearLabel done;
   __ j(equal, &done);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }

@@ -1348,10 +1348,10 @@

   __ cmp(reg, Factory::null_value());
   if (instr->is_strict()) {
-    __ mov(result, Handle<Object>(Heap::true_value()));
+    __ mov(result, Factory::true_value());
     NearLabel done;
     __ j(equal, &done);
-    __ mov(result, Handle<Object>(Heap::false_value()));
+    __ mov(result, Factory::false_value());
     __ bind(&done);
   } else {
     NearLabel true_value, false_value, done;
@@ -1368,10 +1368,10 @@
     __ test(scratch, Immediate(1 << Map::kIsUndetectable));
     __ j(not_zero, &true_value);
     __ bind(&false_value);
-    __ mov(result, Handle<Object>(Heap::false_value()));
+    __ mov(result, Factory::false_value());
     __ jmp(&done);
     __ bind(&true_value);
-    __ mov(result, Handle<Object>(Heap::true_value()));
+    __ mov(result, Factory::true_value());
     __ bind(&done);
   }
 }
@@ -1447,11 +1447,11 @@
   __ j(true_cond, &is_true);

   __ bind(&is_false);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ jmp(&done);

   __ bind(&is_true);
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());

   __ bind(&done);
 }
@@ -1479,10 +1479,10 @@

   ASSERT(instr->hydrogen()->value()->representation().IsTagged());
   __ test(input, Immediate(kSmiTagMask));
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   NearLabel done;
   __ j(zero, &done);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }

@@ -1505,7 +1505,6 @@
   ASSERT(from == to || to == LAST_TYPE);
   return from;
 }
-


 static Condition BranchCondition(HHasInstanceType* instr) {
@@ -1529,10 +1528,10 @@
   __ j(zero, &is_false);
   __ CmpObjectType(input, TestType(instr->hydrogen()), result);
   __ j(NegateCondition(BranchCondition(instr->hydrogen())), &is_false);
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   __ jmp(&done);
   __ bind(&is_false);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }

@@ -1559,12 +1558,12 @@
   Register result = ToRegister(instr->result());

   ASSERT(instr->hydrogen()->value()->representation().IsTagged());
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   __ test(FieldOperand(input, String::kHashFieldOffset),
           Immediate(String::kContainsCachedArrayIndexMask));
   NearLabel done;
   __ j(not_zero, &done);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }

@@ -1653,11 +1652,11 @@
   __ j(not_equal, &is_false);

   __ bind(&is_true);
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());
   __ jmp(&done);

   __ bind(&is_false);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ bind(&done);
 }

@@ -3292,11 +3291,11 @@
                                                   instr->type_literal());
   __ j(final_branch_condition, &true_label);
   __ bind(&false_label);
-  __ mov(result, Handle<Object>(Heap::false_value()));
+  __ mov(result, Factory::false_value());
   __ jmp(&done);

   __ bind(&true_label);
-  __ mov(result, Handle<Object>(Heap::true_value()));
+  __ mov(result, Factory::true_value());

   __ bind(&done);
 }
@@ -3341,9 +3340,9 @@
     final_branch_condition = below;

   } else if (type_name->Equals(Heap::boolean_symbol())) {
-    __ cmp(input, Handle<Object>(Heap::true_value()));
+    __ cmp(input, Factory::true_value());
     __ j(equal, true_label);
-    __ cmp(input, Handle<Object>(Heap::false_value()));
+    __ cmp(input, Factory::false_value());
     final_branch_condition = equal;

   } else if (type_name->Equals(Heap::undefined_symbol())) {
=======================================
--- /branches/bleeding_edge/src/objects.h       Wed Jan 19 00:04:48 2011
+++ /branches/bleeding_edge/src/objects.h       Wed Jan 19 02:17:18 2011
@@ -523,7 +523,8 @@
   JS_BUILTINS_OBJECT_TYPE,
   JS_GLOBAL_PROXY_TYPE,
   JS_ARRAY_TYPE,
-  JS_REGEXP_TYPE,  // LAST_JS_OBJECT_TYPE
+
+  JS_REGEXP_TYPE,  // LAST_JS_OBJECT_TYPE, FIRST_FUNCTION_CLASS_TYPE

   JS_FUNCTION_TYPE,

@@ -541,7 +542,10 @@
   // function objects are not counted as objects, even though they are
// implemented as such; only values whose typeof is "object" are included.
   FIRST_JS_OBJECT_TYPE = JS_VALUE_TYPE,
-  LAST_JS_OBJECT_TYPE = JS_REGEXP_TYPE
+  LAST_JS_OBJECT_TYPE = JS_REGEXP_TYPE,
+  // RegExp objects have [[Class]] "function" because they are callable.
+ // All types from this type and above are objects with [[Class]] "function".
+  FIRST_FUNCTION_CLASS_TYPE = JS_REGEXP_TYPE
 };


=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.h     Wed Jan 19 00:20:42 2011
+++ /branches/bleeding_edge/src/x64/assembler-x64.h     Wed Jan 19 02:17:18 2011
@@ -706,6 +706,10 @@
   void sbbl(Register dst, Register src) {
     arithmetic_op_32(0x1b, dst, src);
   }
+
+  void sbbq(Register dst, Register src) {
+    arithmetic_op(0x1b, dst, src);
+  }

   void cmpb(Register dst, Immediate src) {
     immediate_arithmetic_op_8(0x7, dst, src);
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Wed Jan 5 04:28:47 2011 +++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Wed Jan 19 02:17:18 2011
@@ -3246,6 +3246,12 @@
   __ bind(&slow);
   __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
 }
+
+
+Register InstanceofStub::left() { return rax; }
+
+
+Register InstanceofStub::right() { return rdx; }


 int CompareStub::MinorKey() {
@@ -4272,22 +4278,119 @@
 }

 void ICCompareStub::GenerateSmis(MacroAssembler* masm) {
-  UNIMPLEMENTED();
+  ASSERT(state_ == CompareIC::SMIS);
+  NearLabel miss;
+  __ JumpIfNotBothSmi(rdx, rax, &miss);
+
+  if (GetCondition() == equal) {
+    // For equality we do not care about the sign of the result.
+    __ SmiSub(rax, rax, rdx);
+  } else {
+    NearLabel done;
+    __ SmiSub(rdx, rdx, rax);
+    __ j(no_overflow, &done);
+    // Correct sign of result in case of overflow.
+    __ SmiNot(rdx, rdx);
+    __ bind(&done);
+    __ movq(rax, rdx);
+  }
+  __ ret(0);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }


 void ICCompareStub::GenerateHeapNumbers(MacroAssembler* masm) {
-  UNIMPLEMENTED();
+  ASSERT(state_ == CompareIC::HEAP_NUMBERS);
+
+  NearLabel generic_stub;
+  NearLabel unordered;
+  NearLabel miss;
+  Condition either_smi = masm->CheckEitherSmi(rax, rdx);
+  __ j(either_smi, &generic_stub);
+
+  __ CmpObjectType(rax, HEAP_NUMBER_TYPE, rcx);
+  __ j(not_equal, &miss);
+  __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
+  __ j(not_equal, &miss);
+
+  // Load left and right operand
+  __ movsd(xmm0, FieldOperand(rdx, HeapNumber::kValueOffset));
+  __ movsd(xmm1, FieldOperand(rax, HeapNumber::kValueOffset));
+
+  // Compare operands
+  __ ucomisd(xmm0, xmm1);
+
+  // Don't base result on EFLAGS when a NaN is involved.
+  __ j(parity_even, &unordered);
+
+  // Return a result of -1, 0, or 1, based on EFLAGS.
+  // Performing mov, because xor would destroy the flag register.
+  __ movl(rax, Immediate(0));
+  __ movl(rcx, Immediate(0));
+  __ setcc(above, rax);  // Add one to zero if carry clear and not equal.
+  __ sbbq(rax, rcx);  // Subtract one if below (aka. carry set).
+  __ ret(0);
+
+  __ bind(&unordered);
+
+  CompareStub stub(GetCondition(), strict(), NO_COMPARE_FLAGS);
+  __ bind(&generic_stub);
+  __ jmp(stub.GetCode(), RelocInfo::CODE_TARGET);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }


 void ICCompareStub::GenerateObjects(MacroAssembler* masm) {
-  UNIMPLEMENTED();
+  ASSERT(state_ == CompareIC::OBJECTS);
+  NearLabel miss;
+  Condition either_smi = masm->CheckEitherSmi(rdx, rax);
+  __ j(either_smi, &miss);
+
+  __ CmpObjectType(rax, JS_OBJECT_TYPE, rcx);
+  __ j(not_equal, &miss, not_taken);
+  __ CmpObjectType(rdx, JS_OBJECT_TYPE, rcx);
+  __ j(not_equal, &miss, not_taken);
+
+  ASSERT(GetCondition() == equal);
+  __ subq(rax, rdx);
+  __ ret(0);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
 }


 void ICCompareStub::GenerateMiss(MacroAssembler* masm) {
-  UNIMPLEMENTED();
+  // Save the registers.
+  __ pop(rcx);
+  __ push(rdx);
+  __ push(rax);
+  __ push(rcx);
+
+  // Call the runtime system in a fresh internal frame.
+ ExternalReference miss = ExternalReference(IC_Utility(IC::kCompareIC_Miss));
+  __ EnterInternalFrame();
+  __ push(rdx);
+  __ push(rax);
+  __ Push(Smi::FromInt(op_));
+  __ CallExternalReference(miss, 3);
+  __ LeaveInternalFrame();
+
+  // Compute the entry point of the rewritten stub.
+  __ lea(rdi, FieldOperand(rax, Code::kHeaderSize));
+
+  // Restore registers.
+  __ pop(rcx);
+  __ pop(rax);
+  __ pop(rdx);
+  __ push(rcx);
+
+  // Do a tail call to the rewritten stub.
+  __ jmp(rdi);
 }

 #undef __
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Tue Jan 18 06:32:13 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Jan 19 02:17:18 2011
@@ -930,12 +930,86 @@


 void LCodeGen::EmitBranch(int left_block, int right_block, Condition cc) {
-  Abort("Unimplemented: %s", "EmitBranch");
+  int next_block = GetNextEmittedBlock(current_block_);
+  right_block = chunk_->LookupDestination(right_block);
+  left_block = chunk_->LookupDestination(left_block);
+
+  if (right_block == left_block) {
+    EmitGoto(left_block);
+  } else if (left_block == next_block) {
+    __ j(NegateCondition(cc), chunk_->GetAssemblyLabel(right_block));
+  } else if (right_block == next_block) {
+    __ j(cc, chunk_->GetAssemblyLabel(left_block));
+  } else {
+    __ j(cc, chunk_->GetAssemblyLabel(left_block));
+    if (cc != always) {
+      __ jmp(chunk_->GetAssemblyLabel(right_block));
+    }
+  }
 }


 void LCodeGen::DoBranch(LBranch* instr) {
-  Abort("Unimplemented: %s", "DoBranch");
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  Representation r = instr->hydrogen()->representation();
+  if (r.IsInteger32()) {
+    Register reg = ToRegister(instr->InputAt(0));
+    __ testl(reg, reg);
+    EmitBranch(true_block, false_block, not_zero);
+  } else if (r.IsDouble()) {
+    XMMRegister reg = ToDoubleRegister(instr->InputAt(0));
+    __ xorpd(xmm0, xmm0);
+    __ ucomisd(reg, xmm0);
+    EmitBranch(true_block, false_block, not_equal);
+  } else {
+    ASSERT(r.IsTagged());
+    Register reg = ToRegister(instr->InputAt(0));
+    HType type = instr->hydrogen()->type();
+    if (type.IsBoolean()) {
+      __ Cmp(reg, Factory::true_value());
+      EmitBranch(true_block, false_block, equal);
+    } else if (type.IsSmi()) {
+      __ SmiCompare(reg, Smi::FromInt(0));
+      EmitBranch(true_block, false_block, not_equal);
+    } else {
+      Label* true_label = chunk_->GetAssemblyLabel(true_block);
+      Label* false_label = chunk_->GetAssemblyLabel(false_block);
+
+      __ Cmp(reg, Factory::undefined_value());
+      __ j(equal, false_label);
+      __ Cmp(reg, Factory::true_value());
+      __ j(equal, true_label);
+      __ Cmp(reg, Factory::false_value());
+      __ j(equal, false_label);
+      __ SmiCompare(reg, Smi::FromInt(0));
+      __ j(equal, false_label);
+      __ JumpIfSmi(reg, true_label);
+
+      // Test for double values. Plus/minus zero are false. NaN is handled
+      // in the stub.
+      NearLabel call_stub;
+      __ Cmp(FieldOperand(reg, HeapObject::kMapOffset),
+             Factory::heap_number_map());
+      __ j(not_equal, &call_stub);
+ __ movq(kScratchRegister, FieldOperand(reg, HeapNumber::kValueOffset));
+      __ shl(kScratchRegister, Immediate(1));  // Shift out the sign bit.
+      __ j(zero, false_label);  // Zero or negative zero.
+      __ jmp(true_label);
+
+      // The conversion stub doesn't cause garbage collections so it's
+      // safe to not record a safepoint after the call.
+      __ bind(&call_stub);
+      ToBooleanStub stub;
+      __ Pushad();
+      __ push(reg);
+      __ CallStub(&stub);
+      __ testq(rax, rax);
+      __ Popad();
+      EmitBranch(true_block, false_block, not_zero);
+    }
+  }
 }


@@ -979,7 +1053,7 @@
 }


-Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
+inline Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
   Condition cond = no_condition;
   switch (op) {
     case Token::EQ:
@@ -1008,17 +1082,64 @@


 void LCodeGen::EmitCmpI(LOperand* left, LOperand* right) {
-  Abort("Unimplemented: %s", "EmitCmpI");
+  if (right->IsConstantOperand()) {
+    int32_t value = ToInteger32(LConstantOperand::cast(right));
+    if (left->IsRegister()) {
+      __ cmpl(ToRegister(left), Immediate(value));
+    } else {
+      __ cmpl(ToOperand(left), Immediate(value));
+    }
+  } else if (right->IsRegister()) {
+    __ cmpq(ToRegister(left), ToRegister(right));
+  } else {
+    __ cmpq(ToRegister(left), ToOperand(right));
+  }
 }


 void LCodeGen::DoCmpID(LCmpID* instr) {
-  Abort("Unimplemented: %s", "DoCmpID");
+  LOperand* left = instr->InputAt(0);
+  LOperand* right = instr->InputAt(1);
+  LOperand* result = instr->result();
+
+  NearLabel unordered;
+  if (instr->is_double()) {
+    // Don't base result on EFLAGS when a NaN is involved. Instead
+    // jump to the unordered case, which produces a false value.
+    __ ucomisd(ToDoubleRegister(left), ToDoubleRegister(right));
+    __ j(parity_even, &unordered);
+  } else {
+    EmitCmpI(left, right);
+  }
+
+  NearLabel done;
+  Condition cc = TokenToCondition(instr->op(), instr->is_double());
+  __ LoadRoot(ToRegister(result), Heap::kTrueValueRootIndex);
+  __ j(cc, &done);
+
+  __ bind(&unordered);
+  __ LoadRoot(ToRegister(result), Heap::kFalseValueRootIndex);
+  __ bind(&done);
 }


 void LCodeGen::DoCmpIDAndBranch(LCmpIDAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoCmpIDAndBranch");
+  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());
+
+  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 {
+    EmitCmpI(left, right);
+  }
+
+  Condition cc = TokenToCondition(instr->op(), instr->is_double());
+  EmitBranch(true_block, false_block, cc);
 }


@@ -1028,7 +1149,13 @@


 void LCodeGen::DoCmpJSObjectEqAndBranch(LCmpJSObjectEqAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoCmpJSObjectAndBranch");
+  Register left = ToRegister(instr->InputAt(0));
+  Register right = ToRegister(instr->InputAt(1));
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+
+  __ cmpq(left, right);
+  EmitBranch(true_block, false_block, equal);
 }


@@ -1038,7 +1165,39 @@


 void LCodeGen::DoIsNullAndBranch(LIsNullAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoIsNullAndBranch");
+  Register reg = ToRegister(instr->InputAt(0));
+
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  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());
+
+  __ Cmp(reg, Factory::null_value());
+  if (instr->is_strict()) {
+    EmitBranch(true_block, false_block, equal);
+  } else {
+    Label* true_label = chunk_->GetAssemblyLabel(true_block);
+    Label* false_label = chunk_->GetAssemblyLabel(false_block);
+    __ j(equal, true_label);
+    __ Cmp(reg, Factory::undefined_value());
+    __ j(equal, true_label);
+    __ JumpIfSmi(reg, false_label);
+    // Check for undetectable objects by looking in the bit field in
+    // the map. The object has already been smi checked.
+    Register scratch = ToRegister(instr->TempAt(0));
+    __ movq(scratch, FieldOperand(reg, HeapObject::kMapOffset));
+    __ testb(FieldOperand(scratch, Map::kBitFieldOffset),
+             Immediate(1 << Map::kIsUndetectable));
+    EmitBranch(true_block, false_block, not_zero);
+  }
 }


@@ -1047,7 +1206,25 @@
                                  Register temp2,
                                  Label* is_not_object,
                                  Label* is_object) {
-  Abort("Unimplemented: %s", "EmitIsObject");
+  ASSERT(!input.is(temp1));
+  ASSERT(!input.is(temp2));
+  ASSERT(!temp1.is(temp2));
+
+  __ JumpIfSmi(input, is_not_object);
+
+  __ Cmp(input, Factory::null_value());
+  __ j(equal, is_object);
+
+  __ movq(temp1, FieldOperand(input, HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined.
+  __ testb(FieldOperand(temp1, 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));
+  __ j(below, is_not_object);
+  __ cmpb(temp2, Immediate(LAST_JS_OBJECT_TYPE));
   return below_equal;
 }

@@ -1058,7 +1235,18 @@


 void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoIsObjectAndBranch");
+  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);
+
+  EmitBranch(true_block, false_block, true_cond);
 }


@@ -1068,7 +1256,38 @@


 void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoIsSmiAndBranch");
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  Condition is_smi;
+  if (instr->InputAt(0)->IsRegister()) {
+    Register input = ToRegister(instr->InputAt(0));
+    is_smi = masm()->CheckSmi(input);
+  } else {
+    Operand input = ToOperand(instr->InputAt(0));
+    is_smi = masm()->CheckSmi(input);
+  }
+  EmitBranch(true_block, false_block, is_smi);
+}
+
+
+static InstanceType TestType(HHasInstanceType* instr) {
+  InstanceType from = instr->from();
+  InstanceType to = instr->to();
+  if (from == FIRST_TYPE) return to;
+  ASSERT(from == to || to == LAST_TYPE);
+  return from;
+}
+
+
+static Condition BranchCondition(HHasInstanceType* instr) {
+  InstanceType from = instr->from();
+  InstanceType to = instr->to();
+  if (from == to) return equal;
+  if (to == LAST_TYPE) return above_equal;
+  if (from == FIRST_TYPE) return below_equal;
+  UNREACHABLE();
+  return equal;
 }


@@ -1078,7 +1297,17 @@


void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoHasInstanceTypeAndBranch");
+  Register input = ToRegister(instr->InputAt(0));
+
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  Label* false_label = chunk_->GetAssemblyLabel(false_block);
+
+  __ JumpIfSmi(input, false_label);
+
+  __ CmpObjectType(input, TestType(instr->hydrogen()), kScratchRegister);
+  EmitBranch(true_block, false_block, BranchCondition(instr->hydrogen()));
 }


@@ -1089,19 +1318,68 @@

 void LCodeGen::DoHasCachedArrayIndexAndBranch(
     LHasCachedArrayIndexAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoHasCachedArrayIndexAndBranch");
+    Register input = ToRegister(instr->InputAt(0));
+
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  __ testl(FieldOperand(input, String::kHashFieldOffset),
+           Immediate(String::kContainsCachedArrayIndexMask));
+  EmitBranch(true_block, false_block, not_equal);
 }


-// Branches to a label or falls through with the answer in the z flag. Trashes
-// the temp registers, but not the input.  Only input and temp2 may alias.
+// Branches to a label or falls through with the answer in the z flag.
+// Trashes the temp register and possibly input (if it and temp are aliased).
 void LCodeGen::EmitClassOfTest(Label* is_true,
                                Label* is_false,
-                               Handle<String>class_name,
+                               Handle<String> class_name,
                                Register input,
-                               Register temp,
-                               Register temp2) {
-  Abort("Unimplemented: %s", "EmitClassOfTest");
+                               Register temp) {
+  __ JumpIfSmi(input, is_false);
+  __ CmpObjectType(input, FIRST_JS_OBJECT_TYPE, temp);
+  __ j(below, is_false);
+
+  // Map is now in temp.
+  // Functions have class 'Function'.
+  __ CmpInstanceType(temp, JS_FUNCTION_TYPE);
+  if (class_name->IsEqualTo(CStrVector("Function"))) {
+    __ j(equal, is_true);
+  } else {
+    __ j(equal, is_false);
+  }
+
+  // Check if the constructor in the map is a function.
+  __ movq(temp, FieldOperand(temp, Map::kConstructorOffset));
+
+  // As long as JS_FUNCTION_TYPE is the last instance type and it is
+  // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
+  // LAST_JS_OBJECT_TYPE.
+  ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
+  ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
+
+  // Objects with a non-function constructor have class 'Object'.
+  __ CmpObjectType(temp, JS_FUNCTION_TYPE, kScratchRegister);
+  if (class_name->IsEqualTo(CStrVector("Object"))) {
+    __ j(not_equal, is_true);
+  } else {
+    __ j(not_equal, is_false);
+  }
+
+  // temp now contains the constructor function. Grab the
+  // instance class name from there.
+  __ movq(temp, FieldOperand(temp, JSFunction::kSharedFunctionInfoOffset));
+  __ movq(temp, FieldOperand(temp,
+ SharedFunctionInfo::kInstanceClassNameOffset)); + // The class name we are testing against is a symbol because it's a literal. + // The name in the constructor is a symbol because of the way the context is
+  // booted.  This routine isn't expected to work for random API-created
+ // classes and it doesn't have to because you can't access it with natives + // syntax. Since both sides are symbols it is sufficient to use an identity
+  // comparison.
+  ASSERT(class_name->IsSymbol());
+  __ Cmp(temp, class_name);
+  // End with the answer in the z flag.
 }


@@ -1111,7 +1389,19 @@


 void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoClassOfTestAndBranch");
+  Register input = ToRegister(instr->InputAt(0));
+  Register temp = ToRegister(instr->TempAt(0));
+  Handle<String> class_name = instr->hydrogen()->class_name();
+
+  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);
+
+  EmitClassOfTest(true_label, false_label, class_name, input, temp);
+
+  EmitBranch(true_block, false_block, equal);
 }


@@ -1126,7 +1416,13 @@


 void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoInstanceOfAndBranch");
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  InstanceofStub stub(InstanceofStub::kArgsInRegisters);
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+  __ testq(rax, rax);
+  EmitBranch(true_block, false_block, zero);
 }


@@ -1142,12 +1438,42 @@


 void LCodeGen::DoCmpT(LCmpT* instr) {
-  Abort("Unimplemented: %s", "DoCmpT");
+  Token::Value op = instr->op();
+
+  Handle<Code> ic = CompareIC::GetUninitialized(op);
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+
+  Condition condition = TokenToCondition(op, false);
+  if (op == Token::GT || op == Token::LTE) {
+    condition = ReverseCondition(condition);
+  }
+  NearLabel true_value, done;
+  __ testq(rax, rax);
+  __ j(condition, &true_value);
+  __ LoadRoot(ToRegister(instr->result()), Heap::kFalseValueRootIndex);
+  __ jmp(&done);
+  __ bind(&true_value);
+  __ LoadRoot(ToRegister(instr->result()), Heap::kTrueValueRootIndex);
+  __ bind(&done);
 }


 void LCodeGen::DoCmpTAndBranch(LCmpTAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoCmpTAndBranch");
+  Token::Value op = instr->op();
+  int true_block = chunk_->LookupDestination(instr->true_block_id());
+  int false_block = chunk_->LookupDestination(instr->false_block_id());
+
+  Handle<Code> ic = CompareIC::GetUninitialized(op);
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+
+  // The compare stub expects compare condition and the input operands
+  // reversed for GT and LTE.
+  Condition condition = TokenToCondition(op, false);
+  if (op == Token::GT || op == Token::LTE) {
+    condition = ReverseCondition(condition);
+  }
+  __ testq(rax, rax);
+  EmitBranch(true_block, false_block, condition);
 }


@@ -1494,7 +1820,18 @@


 void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
-  Abort("Unimplemented: %s", "DoTypeofIsAndBranch");
+  Register input = ToRegister(instr->InputAt(0));
+  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 final_branch_condition = EmitTypeofIs(true_label,
+                                                  false_label,
+                                                  input,
+                                                  instr->type_literal());
+
+  EmitBranch(true_block, false_block, final_branch_condition);
 }


@@ -1502,8 +1839,63 @@
                                  Label* false_label,
                                  Register input,
                                  Handle<String> type_name) {
-  Abort("Unimplemented: %s", "EmitTypeofIs");
-  return no_condition;
+  Condition final_branch_condition = no_condition;
+  if (type_name->Equals(Heap::number_symbol())) {
+    __ JumpIfSmi(input, true_label);
+    __ Cmp(FieldOperand(input, HeapObject::kMapOffset),
+           Factory::heap_number_map());
+    final_branch_condition = equal;
+
+  } else if (type_name->Equals(Heap::string_symbol())) {
+    __ JumpIfSmi(input, false_label);
+    __ movq(input, FieldOperand(input, HeapObject::kMapOffset));
+    __ testb(FieldOperand(input, Map::kBitFieldOffset),
+             Immediate(1 << Map::kIsUndetectable));
+    __ j(not_zero, false_label);
+    __ CmpInstanceType(input, FIRST_NONSTRING_TYPE);
+    final_branch_condition = below;
+
+  } else if (type_name->Equals(Heap::boolean_symbol())) {
+    __ CompareRoot(input, Heap::kTrueValueRootIndex);
+    __ j(equal, true_label);
+    __ CompareRoot(input, Heap::kFalseValueRootIndex);
+    final_branch_condition = equal;
+
+  } else if (type_name->Equals(Heap::undefined_symbol())) {
+    __ CompareRoot(input, Heap::kUndefinedValueRootIndex);
+    __ j(equal, true_label);
+    __ JumpIfSmi(input, false_label);
+    // Check for undetectable objects => true.
+    __ movq(input, FieldOperand(input, HeapObject::kMapOffset));
+    __ testb(FieldOperand(input, Map::kBitFieldOffset),
+             Immediate(1 << Map::kIsUndetectable));
+    final_branch_condition = not_zero;
+
+  } else if (type_name->Equals(Heap::function_symbol())) {
+    __ JumpIfSmi(input, false_label);
+    __ CmpObjectType(input, FIRST_FUNCTION_CLASS_TYPE, input);
+    final_branch_condition = above_equal;
+
+  } else if (type_name->Equals(Heap::object_symbol())) {
+    __ JumpIfSmi(input, false_label);
+    __ Cmp(input, Factory::null_value());
+    __ j(equal, true_label);
+    // Check for undetectable objects => false.
+    __ testb(FieldOperand(input, Map::kBitFieldOffset),
+             Immediate(1 << Map::kIsUndetectable));
+    __ j(not_zero, false_label);
+    // Check for JS objects that are not RegExp or Function => true.
+    __ CmpInstanceType(input, FIRST_JS_OBJECT_TYPE);
+    __ j(below, false_label);
+    __ CmpInstanceType(input, FIRST_FUNCTION_CLASS_TYPE);
+    final_branch_condition = below_equal;
+
+  } else {
+    final_branch_condition = never;
+    __ jmp(false_label);
+  }
+
+  return final_branch_condition;
 }


=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Mon Jan 17 00:11:03 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.h Wed Jan 19 02:17:18 2011
@@ -138,8 +138,7 @@
                        Label* if_false,
                        Handle<String> class_name,
                        Register input,
-                       Register temporary,
-                       Register temporary2);
+                       Register temporary);

   int StackSlotCount() const { return chunk()->spill_slot_count(); }
   int ParameterCount() const { return scope()->num_parameters(); }
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc      Tue Jan 18 06:32:13 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc      Wed Jan 19 02:17:18 2011
@@ -913,8 +913,103 @@


 LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
-  Abort("Unimplemented: %s", "DoBranch");
-  return NULL;
+  HValue* v = instr->value();
+  if (v->EmitAtUses()) {
+    if (v->IsClassOfTest()) {
+      HClassOfTest* compare = HClassOfTest::cast(v);
+      ASSERT(compare->value()->representation().IsTagged());
+
+      return new LClassOfTestAndBranch(UseTempRegister(compare->value()),
+                                       TempRegister());
+    } else if (v->IsCompare()) {
+      HCompare* compare = HCompare::cast(v);
+      Token::Value op = compare->token();
+      HValue* left = compare->left();
+      HValue* right = compare->right();
+      Representation r = compare->GetInputRepresentation();
+      if (r.IsInteger32()) {
+        ASSERT(left->representation().IsInteger32());
+        ASSERT(right->representation().IsInteger32());
+
+        return new LCmpIDAndBranch(UseRegisterAtStart(left),
+                                   UseOrConstantAtStart(right));
+      } else if (r.IsDouble()) {
+        ASSERT(left->representation().IsDouble());
+        ASSERT(right->representation().IsDouble());
+
+        return new LCmpIDAndBranch(UseRegisterAtStart(left),
+                                   UseRegisterAtStart(right));
+      } else {
+        ASSERT(left->representation().IsTagged());
+        ASSERT(right->representation().IsTagged());
+        bool reversed = op == Token::GT || op == Token::LTE;
+        LOperand* left_operand = UseFixed(left, reversed ? rax : rdx);
+        LOperand* right_operand = UseFixed(right, reversed ? rdx : rax);
+        LCmpTAndBranch* result = new LCmpTAndBranch(left_operand,
+                                                    right_operand);
+        return MarkAsCall(result, instr);
+      }
+    } else if (v->IsIsSmi()) {
+      HIsSmi* compare = HIsSmi::cast(v);
+      ASSERT(compare->value()->representation().IsTagged());
+
+      return new LIsSmiAndBranch(Use(compare->value()));
+    } else if (v->IsHasInstanceType()) {
+      HHasInstanceType* compare = HHasInstanceType::cast(v);
+      ASSERT(compare->value()->representation().IsTagged());
+
+      return new LHasInstanceTypeAndBranch(
+          UseRegisterAtStart(compare->value()));
+    } else if (v->IsHasCachedArrayIndex()) {
+      HHasCachedArrayIndex* compare = HHasCachedArrayIndex::cast(v);
+      ASSERT(compare->value()->representation().IsTagged());
+
+      return new LHasCachedArrayIndexAndBranch(
+          UseRegisterAtStart(compare->value()));
+    } else if (v->IsIsNull()) {
+      HIsNull* compare = HIsNull::cast(v);
+      ASSERT(compare->value()->representation().IsTagged());
+
+      // We only need a temp register for non-strict compare.
+      LOperand* temp = compare->is_strict() ? NULL : TempRegister();
+      return new LIsNullAndBranch(UseRegisterAtStart(compare->value()),
+                                  temp);
+    } else if (v->IsIsObject()) {
+      HIsObject* compare = HIsObject::cast(v);
+      ASSERT(compare->value()->representation().IsTagged());
+
+      LOperand* temp1 = TempRegister();
+      LOperand* temp2 = TempRegister();
+      return new LIsObjectAndBranch(UseRegisterAtStart(compare->value()),
+                                    temp1,
+                                    temp2);
+    } else if (v->IsCompareJSObjectEq()) {
+      HCompareJSObjectEq* compare = HCompareJSObjectEq::cast(v);
+ return new LCmpJSObjectEqAndBranch(UseRegisterAtStart(compare->left()), + UseRegisterAtStart(compare->right()));
+    } else if (v->IsInstanceOf()) {
+      HInstanceOf* instance_of = HInstanceOf::cast(v);
+      LInstanceOfAndBranch* result =
+          new LInstanceOfAndBranch(
+              UseFixed(instance_of->left(), InstanceofStub::left()),
+              UseFixed(instance_of->right(), InstanceofStub::right()));
+      return MarkAsCall(result, instr);
+    } else if (v->IsTypeofIs()) {
+      HTypeofIs* typeof_is = HTypeofIs::cast(v);
+      return new LTypeofIsAndBranch(UseTempRegister(typeof_is->value()));
+    } else {
+      if (v->IsConstant()) {
+        if (HConstant::cast(v)->handle()->IsTrue()) {
+          return new LGoto(instr->FirstSuccessor()->block_id());
+        } else if (HConstant::cast(v)->handle()->IsFalse()) {
+          return new LGoto(instr->SecondSuccessor()->block_id());
+        }
+      }
+      Abort("Undefined compare before branch");
+      return NULL;
+    }
+  }
+  return new LBranch(UseRegisterAtStart(v));
 }


@@ -1124,8 +1219,29 @@


 LInstruction* LChunkBuilder::DoCompare(HCompare* instr) {
-  Abort("Unimplemented: %s", "DoCompare");
-  return NULL;
+  Token::Value op = instr->token();
+  Representation r = instr->GetInputRepresentation();
+  if (r.IsInteger32()) {
+    ASSERT(instr->left()->representation().IsInteger32());
+    ASSERT(instr->right()->representation().IsInteger32());
+    LOperand* left = UseRegisterAtStart(instr->left());
+    LOperand* right = UseOrConstantAtStart(instr->right());
+    return DefineAsRegister(new LCmpID(left, right));
+  } else if (r.IsDouble()) {
+    ASSERT(instr->left()->representation().IsDouble());
+    ASSERT(instr->right()->representation().IsDouble());
+    LOperand* left = UseRegisterAtStart(instr->left());
+    LOperand* right = UseRegisterAtStart(instr->right());
+    return DefineAsRegister(new LCmpID(left, right));
+  } else {
+    ASSERT(instr->left()->representation().IsTagged());
+    ASSERT(instr->right()->representation().IsTagged());
+    bool reversed = (op == Token::GT || op == Token::LTE);
+    LOperand* left = UseFixed(instr->left(), reversed ? rax : rdx);
+    LOperand* right = UseFixed(instr->right(), reversed ? rdx : rax);
+    LCmpT* result = new LCmpT(left, right);
+    return MarkAsCall(DefineFixed(result, rax), instr);
+  }
 }


=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h       Mon Jan 17 05:51:59 2011
+++ /branches/bleeding_edge/src/x64/lithium-x64.h       Wed Jan 19 02:17:18 2011
@@ -788,11 +788,10 @@
 };


-class LHasInstanceTypeAndBranch: public LControlInstruction<1, 1> {
+class LHasInstanceTypeAndBranch: public LControlInstruction<1, 0> {
  public:
-  LHasInstanceTypeAndBranch(LOperand* value, LOperand* temp) {
+  explicit LHasInstanceTypeAndBranch(LOperand* value) {
     inputs_[0] = value;
-    temps_[0] = temp;
   }

   DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
@@ -840,12 +839,11 @@
 };


-class LClassOfTestAndBranch: public LControlInstruction<1, 2> {
+class LClassOfTestAndBranch: public LControlInstruction<1, 1> {
  public:
-  LClassOfTestAndBranch(LOperand* value, LOperand* temp, LOperand* temp2) {
+  LClassOfTestAndBranch(LOperand* value, LOperand* temp) {
     inputs_[0] = value;
     temps_[0] = temp;
-    temps_[1] = temp2;
   }

   DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch,
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Fri Jan 14 02:27:25 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Wed Jan 19 02:17:18 2011
@@ -883,6 +883,13 @@
   testb(src, Immediate(kSmiTagMask));
   return zero;
 }
+
+
+Condition MacroAssembler::CheckSmi(const Operand& src) {
+  ASSERT_EQ(0, kSmiTag);
+  testb(src, Immediate(kSmiTagMask));
+  return zero;
+}


 Condition MacroAssembler::CheckNonNegativeSmi(Register src) {
@@ -1384,6 +1391,40 @@
   ASSERT(RelocInfo::IsCodeTarget(rmode));
   call(code_object, rmode);
 }
+
+
+void MacroAssembler::Pushad() {
+  push(rax);
+  push(rcx);
+  push(rdx);
+  push(rbx);
+  // Not pushing rsp or rbp.
+  push(rsi);
+  push(rdi);
+  push(r8);
+  push(r9);
+  // r10 is kScratchRegister.
+  push(r11);
+  push(r12);
+  // r13 is kRootRegister.
+  push(r14);
+  // r15 is kSmiConstantRegister
+}
+
+
+void MacroAssembler::Popad() {
+  pop(r14);
+  pop(r12);
+  pop(r11);
+  pop(r9);
+  pop(r8);
+  pop(rdi);
+  pop(rsi);
+  pop(rbx);
+  pop(rdx);
+  pop(rcx);
+  pop(rax);
+}


 void MacroAssembler::PushTryHandler(CodeLocation try_location,
=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Mon Jan 3 03:39:22 2011 +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Wed Jan 19 02:17:18 2011
@@ -272,6 +272,7 @@

   // Is the value a tagged smi.
   Condition CheckSmi(Register src);
+  Condition CheckSmi(const Operand& src);

   // Is the value a non-negative tagged smi.
   Condition CheckNonNegativeSmi(Register src);
@@ -590,6 +591,13 @@
   void Call(ExternalReference ext);
   void Call(Handle<Code> code_object, RelocInfo::Mode rmode);

+  // Non-x64 instructions.
+  // Push/pop all general purpose registers.
+ // Does not push rsp/rbp nor any of the assembler's special purpose registers
+  // (kScratchRegister, kSmiConstantRegister, kRootRegister).
+  void Pushad();
+  void Popad();
+
   // Compare object type for heap object.
// Always use unsigned comparisons: above and below, not less and greater.
   // Incoming register is heap_object and outgoing register is map.
=======================================
--- /branches/bleeding_edge/test/cctest/cctest.status Mon Jan 17 05:27:16 2011 +++ /branches/bleeding_edge/test/cctest/cctest.status Wed Jan 19 02:17:18 2011
@@ -82,7 +82,7 @@
 test-serialize/ContextDeserialization: SKIP
 test-debug/BreakPointReturn: SKIP
 test-debug/DebugStepLinearMixedICs: SKIP
-
+test-debug/DebugConditional: SKIP

##############################################################################
 [ $arch == arm ]

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to