Fix potential overwriting of debug jumps of following code.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 4 Feb 2011 14:09:03 +0000 (14:09 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 4 Feb 2011 14:09:03 +0000 (14:09 +0000)
Add JSArrayLength, CallKnownFunction, and InstanceType operations.
Remove LadGlobal and StoreGlobal again (they fail).

Review URL: http://codereview.chromium.org/6347067

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6645 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

13 files changed:
src/objects.cc
src/safepoint-table.cc
src/safepoint-table.h
src/x64/assembler-x64.cc
src/x64/assembler-x64.h
src/x64/deoptimizer-x64.cc
src/x64/frames-x64.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
test/cctest/cctest.status

index 524c0242373f719f95a74e3a3b4a280970fd919b..df8e55408b1bb294508290ebb12a5c9c8804caee 100644 (file)
@@ -5925,7 +5925,7 @@ void Code::CopyFrom(const CodeDesc& desc) {
       Handle<Object> p = it.rinfo()->target_object_handle(origin);
       it.rinfo()->set_target_object(*p);
     } else if (mode == RelocInfo::GLOBAL_PROPERTY_CELL) {
-      Handle<JSGlobalPropertyCell> cell  = it.rinfo()->target_cell_handle();
+      Handle<JSGlobalPropertyCell> cell = it.rinfo()->target_cell_handle();
       it.rinfo()->set_target_cell(*cell);
     } else if (RelocInfo::IsCodeTarget(mode)) {
       // rewrite code handles in inline cache targets to direct
index 4db3d9087595bfa68cb8b08ebbca204012390fdb..d2ec54c38874c9782c35f0ca9663482024787318 100644 (file)
@@ -230,4 +230,24 @@ uint32_t SafepointTableBuilder::EncodeExceptPC(const DeoptimizationInfo& info) {
 }
 
 
+int SafepointTableBuilder::CountShortDeoptimizationIntervals(unsigned limit) {
+  int result = 0;
+  if (!deoptimization_info_.is_empty()) {
+    unsigned previous_gap_end = deoptimization_info_[0].pc_after_gap;
+    for (int i = 1, n = deoptimization_info_.length(); i < n; i++) {
+      DeoptimizationInfo info = deoptimization_info_[i];
+      if (static_cast<int>(info.deoptimization_index) !=
+          Safepoint::kNoDeoptimizationIndex) {
+        if (previous_gap_end + limit > info.pc) {
+          result++;
+        }
+        previous_gap_end = info.pc_after_gap;
+      }
+    }
+  }
+  return result;
+}
+
+
+
 } }  // namespace v8::internal
index eeeae37fbe14e9f18f0fa9e6ca09f282cfa886aa..8803d06f5b49de72599810b1cd694c49fa56f360 100644 (file)
@@ -220,8 +220,8 @@ class SafepointTableBuilder BASE_EMBEDDED {
                             int arguments,
                             int deoptimization_index);
 
-  // Update the last safepoint with the size of the code generated for the gap
-  // following it.
+  // Update the last safepoint with the size of the code generated until the
+  // end of the gap following it.
   void SetPcAfterGap(int pc) {
     ASSERT(!deoptimization_info_.is_empty());
     int index = deoptimization_info_.length() - 1;
@@ -232,6 +232,11 @@ class SafepointTableBuilder BASE_EMBEDDED {
   // entry must be enough to hold all the pointer indexes.
   void Emit(Assembler* assembler, int bits_per_entry);
 
+  // Count the number of deoptimization points where the next
+  // following deoptimization point comes less than limit bytes
+  // after the end of this point's gap.
+  int CountShortDeoptimizationIntervals(unsigned limit);
+
  private:
   struct DeoptimizationInfo {
     unsigned pc;
@@ -247,8 +252,8 @@ class SafepointTableBuilder BASE_EMBEDDED {
   ZoneList<ZoneList<int>*> indexes_;
   ZoneList<ZoneList<int>*> registers_;
 
-  bool emitted_;
   unsigned offset_;
+  bool emitted_;
 
   DISALLOW_COPY_AND_ASSIGN(SafepointTableBuilder);
 };
index 601f99e453070693c1dd29136a669be9f31fb780..ef069a98bc1f5eb493347a5423efb73189cf20d6 100644 (file)
@@ -916,6 +916,23 @@ void Assembler::call(const Operand& op) {
 }
 
 
+// Calls directly to the given address using a relative offset.
+// Should only ever be used in Code objects for calls within the
+// same Code object. Should not be used when generating new code (use labels),
+// but only when patching existing code.
+void Assembler::call(Address target) {
+  positions_recorder()->WriteRecordedPositions();
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  // 1110 1000 #32-bit disp.
+  emit(0xE8);
+  Address source = pc_ + 4;
+  intptr_t displacement = target - source;
+  ASSERT(is_int32(displacement));
+  emitl(static_cast<int32_t>(displacement));
+}
+
+
 void Assembler::clc() {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
index 73bdc97ec5d1acce873fadb726d4df07fce6b673..c597783b5e0d323060b8f896e3da25c529691fc0 100644 (file)
@@ -553,10 +553,12 @@ class Assembler : public Malloced {
   // TODO(X64): Rename this, removing the "Real", after changing the above.
   static const int kRealPatchReturnSequenceAddressOffset = 2;
 
-  // The x64 JS return sequence is padded with int3 to make it large
-  // enough to hold a call instruction when the debugger patches it.
+  // Some x64 JS code is padded with int3 to make it large
+  // enough to hold an instruction when the debugger patches it.
+  static const int kJumpInstructionLength = 13;
   static const int kCallInstructionLength = 13;
   static const int kJSReturnSequenceLength = 13;
+  static const int kShortCallInstructionLength = 5;
 
   // The debug break slot must be able to contain a call instruction.
   static const int kDebugBreakSlotLength = kCallInstructionLength;
@@ -585,7 +587,7 @@ class Assembler : public Malloced {
 
   // Insert the smallest number of nop instructions
   // possible to align the pc offset to a multiple
-  // of m. m must be a power of 2.
+  // of m, where m must be a power of 2.
   void Align(int m);
   // Aligns code to something that's optimal for a jump target for the platform.
   void CodeTargetAlign();
@@ -1127,6 +1129,12 @@ class Assembler : public Malloced {
   void call(Label* L);
   void call(Handle<Code> target, RelocInfo::Mode rmode);
 
+  // Calls directly to the given address using a relative offset.
+  // Should only ever be used in Code objects for calls within the
+  // same Code object. Should not be used when generating new code (use labels),
+  // but only when patching existing code.
+  void call(Address target);
+
   // Call near absolute indirect, address in register
   void call(Register adr);
 
index ee70785f2673811244391599c93547f95bf80383..ed6c47bf998ccaebf0522a9fbfc117988db7723e 100644 (file)
@@ -42,10 +42,65 @@ int Deoptimizer::table_entry_size_ = 10;
 
 
 int Deoptimizer::patch_size() {
-  return Assembler::kCallInstructionLength;
+  return MacroAssembler::kCallInstructionLength;
 }
 
 
+#ifdef DEBUG
+// Overwrites code with int3 instructions.
+static void ZapCodeRange(Address from, Address to) {
+  CHECK(from <= to);
+  int length = static_cast<int>(to - from);
+  CodePatcher destroyer(from, length);
+  while (length-- > 0) {
+    destroyer.masm()->int3();
+  }
+}
+#endif
+
+
+// Iterate through the entries of a SafepointTable that corresponds to
+// deoptimization points.
+class SafepointTableDeoptimiztionEntryIterator {
+ public:
+  explicit SafepointTableDeoptimiztionEntryIterator(Code* code)
+      : code_(code), table_(code), index_(-1), limit_(table_.length()) {
+    FindNextIndex();
+  }
+
+  SafepointEntry Next(Address* pc) {
+    if (index_ >= limit_) {
+      *pc = NULL;
+      return SafepointEntry();  // Invalid entry.
+    }
+    *pc = code_->instruction_start() + table_.GetPcOffset(index_);
+    SafepointEntry entry = table_.GetEntry(index_);
+    FindNextIndex();
+    return entry;
+  }
+
+ private:
+  void FindNextIndex() {
+    ASSERT(index_ < limit_);
+    while (++index_ < limit_) {
+      if (table_.GetEntry(index_).deoptimization_index() !=
+          Safepoint::kNoDeoptimizationIndex) {
+        return;
+      }
+    }
+  }
+
+  Code* code_;
+  SafepointTable table_;
+  // Index of next deoptimization entry. If negative after calling
+  // FindNextIndex, there are no more, and Next will return an invalid
+  // SafepointEntry.
+  int index_;
+  // Table length.
+  int limit_;
+};
+
+
 void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
   AssertNoAllocation no_allocation;
 
@@ -59,42 +114,74 @@ void Deoptimizer::DeoptimizeFunction(JSFunction* function) {
   code->InvalidateRelocation();
 
   // For each return after a safepoint insert a absolute call to the
-  // corresponding deoptimization entry.
-  unsigned last_pc_offset = 0;
-  SafepointTable table(function->code());
-  for (unsigned i = 0; i < table.length(); i++) {
-    unsigned pc_offset = table.GetPcOffset(i);
-    SafepointEntry safepoint_entry = table.GetEntry(i);
-    int deoptimization_index = safepoint_entry.deoptimization_index();
-    int gap_code_size = safepoint_entry.gap_code_size();
+  // corresponding deoptimization entry, or a short call to an absolute
+  // jump if space is short. The absolute jumps are put in a table just
+  // before the safepoint table (space was allocated there when the Code
+  // object was created, if necessary).
+
+  Address instruction_start = function->code()->instruction_start();
+  Address jump_table_address =
+      instruction_start + function->code()->safepoint_table_offset();
+  Address previous_pc = instruction_start;
+
+  SafepointTableDeoptimiztionEntryIterator deoptimizations(function->code());
+  Address entry_pc = NULL;
+
+  SafepointEntry current_entry = deoptimizations.Next(&entry_pc);
+  while (current_entry.is_valid()) {
+    int gap_code_size = current_entry.gap_code_size();
+    unsigned deoptimization_index = current_entry.deoptimization_index();
+
 #ifdef DEBUG
     // Destroy the code which is not supposed to run again.
-    unsigned instructions = pc_offset - last_pc_offset;
-    CodePatcher destroyer(code->instruction_start() + last_pc_offset,
-                          instructions);
-    for (unsigned i = 0; i < instructions; i++) {
-      destroyer.masm()->int3();
-    }
+    ZapCodeRange(previous_pc, entry_pc);
 #endif
-    last_pc_offset = pc_offset;
-    if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
-      last_pc_offset += gap_code_size;
-      CodePatcher patcher(code->instruction_start() + last_pc_offset,
-                          patch_size());
+    // Position where Call will be patched in.
+    Address call_address = entry_pc + gap_code_size;
+    // End of call instruction, if using a direct call to a 64-bit address.
+    Address call_end_address =
+        call_address + MacroAssembler::kCallInstructionLength;
+
+    // Find next deoptimization entry, if any.
+    Address next_pc = NULL;
+    SafepointEntry next_entry = deoptimizations.Next(&next_pc);
+
+    if (!next_entry.is_valid() || next_pc >= call_end_address) {
+      // Room enough to write a long call instruction.
+      CodePatcher patcher(call_address, Assembler::kCallInstructionLength);
       patcher.masm()->Call(GetDeoptimizationEntry(deoptimization_index, LAZY),
                            RelocInfo::NONE);
-      last_pc_offset += patch_size();
+      previous_pc = call_end_address;
+    } else {
+      // Not room enough for a long Call instruction. Write a short call
+      // instruction to a long jump placed elsewhere in the code.
+      Address short_call_end_address =
+          call_address + MacroAssembler::kShortCallInstructionLength;
+      ASSERT(next_pc >= short_call_end_address);
+
+      // Write jump in jump-table.
+      jump_table_address -= MacroAssembler::kJumpInstructionLength;
+      CodePatcher jump_patcher(jump_table_address,
+                               MacroAssembler::kJumpInstructionLength);
+      jump_patcher.masm()->Jump(
+          GetDeoptimizationEntry(deoptimization_index, LAZY),
+          RelocInfo::NONE);
+
+      // Write call to jump at call_offset.
+      CodePatcher call_patcher(call_address,
+                               MacroAssembler::kShortCallInstructionLength);
+      call_patcher.masm()->call(jump_table_address);
+      previous_pc = short_call_end_address;
     }
+
+    // Continue with next deoptimization entry.
+    current_entry = next_entry;
+    entry_pc = next_pc;
   }
+
 #ifdef DEBUG
   // Destroy the code which is not supposed to run again.
-  CHECK(code->safepoint_table_offset() >= last_pc_offset);
-  unsigned instructions = code->safepoint_table_offset() - last_pc_offset;
-  CodePatcher destroyer(code->instruction_start() + last_pc_offset,
-                        instructions);
-  for (unsigned i = 0; i < instructions; i++) {
-    destroyer.masm()->int3();
-  }
+  ZapCodeRange(previous_pc, jump_table_address);
 #endif
 
   // Add the deoptimizing code to the list.
@@ -390,7 +477,7 @@ void Deoptimizer::EntryGenerator::Generate() {
     __ pop(Operand(rbx, offset));
   }
 
-    // Fill in the double input registers.
+  // Fill in the double input registers.
   int double_regs_offset = FrameDescription::double_registers_offset();
   for (int i = 0; i < XMMRegister::kNumAllocatableRegisters; i++) {
     int dst_offset = i * kDoubleSize + double_regs_offset;
@@ -404,7 +491,7 @@ void Deoptimizer::EntryGenerator::Generate() {
     __ addq(rsp, Immediate(2 * kPointerSize));
   }
 
-  // Compute a pointer to the unwinding limit in register ecx; that is
+  // Compute a pointer to the unwinding limit in register rcx; that is
   // the first stack slot not part of the input frame.
   __ movq(rcx, Operand(rbx, FrameDescription::frame_size_offset()));
   __ addq(rcx, rsp);
index a2a0e7e9ff520c25ecae88e32f5157527411ac10..998b3e9fc92173c9bd03875e070880b100f2d61f 100644 (file)
@@ -31,7 +31,7 @@
 namespace v8 {
 namespace internal {
 
-static const int kNumRegs = 8;
+static const int kNumRegs = 16;
 static const RegList kJSCallerSaved =
     1 << 0 |  // rax
     1 << 1 |  // rcx
@@ -44,8 +44,7 @@ static const int kNumJSCallerSaved = 5;
 typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
 
 // Number of registers for which space is reserved in safepoints.
-// TODO(x64): This should not be 0.
-static const int kNumSafepointRegisters = 8;
+static const int kNumSafepointRegisters = 16;
 
 // ----------------------------------------------------
 
index 2a65fda90ceaeabad53194bc1358787cf04f2ae7..48d413016bc1957c3404a22f9388a920462e7b9e 100644 (file)
@@ -188,9 +188,19 @@ bool LCodeGen::GenerateDeferredCode() {
 
 bool LCodeGen::GenerateSafepointTable() {
   ASSERT(is_done());
-  // Ensure that patching a deoptimization point won't overwrite the table.
-  for (int i = 0; i < Assembler::kCallInstructionLength; i++) {
-    masm()->int3();
+  // Ensure that there is space at the end of the code to write a number
+  // of jump instructions, as well as to afford writing a call near the end
+  // of the code.
+  // The jumps are used when there isn't room in the code stream to write
+  // a long call instruction. Instead it writes a shorter call to a
+  // jump instruction in the same code object.
+  // The calls are used when lazy deoptimizing a function and calls to a
+  // deoptimization function.
+  int short_deopts = safepoints_.CountShortDeoptimizationIntervals(
+      static_cast<unsigned>(MacroAssembler::kJumpInstructionLength));
+  int byte_count = (short_deopts) * MacroAssembler::kJumpInstructionLength;
+  while (byte_count-- > 0) {
+    __ int3();
   }
   safepoints_.Emit(masm(), StackSlotCount());
   return !is_aborted();
@@ -505,6 +515,7 @@ void LCodeGen::RecordSafepoint(
     int arguments,
     int deoptimization_index) {
   const ZoneList<LOperand*>* operands = pointers->operands();
+
   Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
       kind, arguments, deoptimization_index);
   for (int i = 0; i < operands->length(); i++) {
@@ -773,7 +784,9 @@ void LCodeGen::DoConstantT(LConstantT* instr) {
 
 
 void LCodeGen::DoJSArrayLength(LJSArrayLength* instr) {
-  Abort("Unimplemented: %s", "DoJSArrayLength");
+  Register result = ToRegister(instr->result());
+  Register array = ToRegister(instr->InputAt(0));
+  __ movq(result, FieldOperand(array, JSArray::kLengthOffset));
 }
 
 
@@ -1503,32 +1516,32 @@ void LCodeGen::DoReturn(LReturn* instr) {
 
 
 void LCodeGen::DoLoadGlobal(LLoadGlobal* instr) {
-  Register result = ToRegister(instr->result());
-  if (result.is(rax)) {
-    __ load_rax(instr->hydrogen()->cell().location(),
-                RelocInfo::GLOBAL_PROPERTY_CELL);
-  } else {
-    __ movq(result, instr->hydrogen()->cell(), RelocInfo::GLOBAL_PROPERTY_CELL);
-    __ movq(result, Operand(result, 0));
-  }
-  if (instr->hydrogen()->check_hole_value()) {
-    __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
-    DeoptimizeIf(equal, instr->environment());
-  }
+  Abort("Unimplemented: %s", "DoLoadGlobal");
 }
 
 
 void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
   Register value = ToRegister(instr->InputAt(0));
-  if (value.is(rax)) {
+  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);
-  } else {
-    __ movq(kScratchRegister,
-            Handle<Object>::cast(instr->hydrogen()->cell()),
-            RelocInfo::GLOBAL_PROPERTY_CELL);
-    __ movq(Operand(kScratchRegister, 0), value);
+    return;
   }
+  // 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,
+          Handle<Object>::cast(instr->hydrogen()->cell()),
+          RelocInfo::GLOBAL_PROPERTY_CELL);
+  if (check_hole) {
+    __ CompareRoot(Operand(temp, 0), Heap::kTheHoleValueRootIndex);
+    DeoptimizeIf(equal, instr->environment());
+  }
+  __ movq(Operand(temp, 0), value);
 }
 
 
@@ -1775,7 +1788,9 @@ void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
 
 
 void LCodeGen::DoCallKnownGlobal(LCallKnownGlobal* instr) {
-  Abort("Unimplemented: %s", "DoCallKnownGlobal");
+  ASSERT(ToRegister(instr->result()).is(rax));
+  __ Move(rdi, instr->target());
+  CallKnownFunction(instr->target(), instr->arity(), instr);
 }
 
 
@@ -2046,7 +2061,33 @@ void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
 
 
 void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
-  Abort("Unimplemented: %s", "DoCheckInstanceType");
+  Register input = ToRegister(instr->InputAt(0));
+  InstanceType first = instr->hydrogen()->first();
+  InstanceType last = instr->hydrogen()->last();
+
+  __ movq(kScratchRegister, FieldOperand(input, HeapObject::kMapOffset));
+
+  // If there is only one type in the interval check for equality.
+  if (first == last) {
+    __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
+            Immediate(static_cast<int8_t>(first)));
+    DeoptimizeIf(not_equal, instr->environment());
+  } else if (first == FIRST_STRING_TYPE && last == LAST_STRING_TYPE) {
+    // String has a dedicated bit in instance type.
+    __ testb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
+             Immediate(kIsNotStringMask));
+    DeoptimizeIf(not_zero, instr->environment());
+  } else {
+    __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
+            Immediate(static_cast<int8_t>(first)));
+    DeoptimizeIf(below, instr->environment());
+    // Omit check for the last type.
+    if (last != LAST_TYPE) {
+      __ cmpb(FieldOperand(kScratchRegister, Map::kInstanceTypeOffset),
+              Immediate(static_cast<int8_t>(last)));
+      DeoptimizeIf(above, instr->environment());
+    }
+  }
 }
 
 
index 77a931179e41865773e6a7441472eca5fd021128..12b952d22643eda8e3b328853da673ef57a78934 100644 (file)
@@ -1185,8 +1185,8 @@ LInstruction* LChunkBuilder::DoCallKeyed(HCallKeyed* instr) {
 
 
 LInstruction* LChunkBuilder::DoCallNamed(HCallNamed* instr) {
-  Abort("Unimplemented: %s", "DoCallNamed");
-  return NULL;
+  argument_count_ -= instr->argument_count();
+  return MarkAsCall(DefineFixed(new LCallNamed, rax), instr);
 }
 
 
@@ -1197,8 +1197,8 @@ LInstruction* LChunkBuilder::DoCallGlobal(HCallGlobal* instr) {
 
 
 LInstruction* LChunkBuilder::DoCallKnownGlobal(HCallKnownGlobal* instr) {
-  Abort("Unimplemented: %s", "DoCallKnownGlobal");
-  return NULL;
+  argument_count_ -= instr->argument_count();
+  return MarkAsCall(DefineFixed(new LCallKnownGlobal, rax), instr);
 }
 
 
@@ -1408,8 +1408,8 @@ LInstruction* LChunkBuilder::DoClassOfTest(HClassOfTest* instr) {
 
 
 LInstruction* LChunkBuilder::DoJSArrayLength(HJSArrayLength* instr) {
-  Abort("Unimplemented: %s", "DoJSArrayLength");
-  return NULL;
+  LOperand* array = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new LJSArrayLength(array));
 }
 
 
@@ -1512,8 +1512,9 @@ LInstruction* LChunkBuilder::DoCheckNonSmi(HCheckNonSmi* instr) {
 
 
 LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
-  Abort("Unimplemented: %s", "DoCheckInstanceType");
-  return NULL;
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LCheckInstanceType* result = new LCheckInstanceType(value);
+  return AssignEnvironment(result);
 }
 
 
@@ -1575,7 +1576,9 @@ LInstruction* LChunkBuilder::DoLoadGlobal(HLoadGlobal* instr) {
 
 
 LInstruction* LChunkBuilder::DoStoreGlobal(HStoreGlobal* instr) {
-  return new LStoreGlobal(UseRegisterAtStart(instr->value()));
+  LStoreGlobal* result = new LStoreGlobal(UseRegister(instr->value()),
+                                          TempRegister());
+  return instr->check_hole_value() ? AssignEnvironment(result) : result;
 }
 
 
index dd0dcea98e3dcd4484672f232a04fc4446a77765..64d141e33536c28d09d617b002645bd585ca4764 100644 (file)
@@ -1300,10 +1300,11 @@ class LLoadGlobal: public LTemplateInstruction<1, 0, 0> {
 };
 
 
-class LStoreGlobal: public LTemplateInstruction<0, 1, 0> {
+class LStoreGlobal: public LTemplateInstruction<0, 1, 1> {
  public:
-  explicit LStoreGlobal(LOperand* value) {
+  explicit LStoreGlobal(LOperand* value, LOperand* temp) {
     inputs_[0] = value;
+    temps_[0] = temp;
   }
 
   DECLARE_CONCRETE_INSTRUCTION(StoreGlobal, "store-global")
@@ -1637,11 +1638,10 @@ class LCheckFunction: public LTemplateInstruction<0, 1, 0> {
 };
 
 
-class LCheckInstanceType: public LTemplateInstruction<0, 1, 1> {
+class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> {
  public:
-  LCheckInstanceType(LOperand* value, LOperand* temp) {
+  explicit LCheckInstanceType(LOperand* value) {
     inputs_[0] = value;
-    temps_[0] = temp;
   }
 
   DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type")
index e104e5bb91c3b9949ad41f615400dd26ae798aa3..50b689b23f383b3723cb95e6323dfb4e820aaea2 100644 (file)
@@ -68,7 +68,9 @@ void MacroAssembler::CompareRoot(Register with, Heap::RootListIndex index) {
 }
 
 
-void MacroAssembler::CompareRoot(Operand with, Heap::RootListIndex index) {
+void MacroAssembler::CompareRoot(const Operand& with,
+                                 Heap::RootListIndex index) {
+  ASSERT(!with.AddressUsesRegister(kScratchRegister));
   LoadRoot(kScratchRegister, index);
   cmpq(with, kScratchRegister);
 }
index 0ee3933708a2a662d573b51c4036ea5675043194..8bb3190448fdc16f0b31107b70551d0a664a2712 100644 (file)
@@ -74,7 +74,7 @@ class MacroAssembler: public Assembler {
 
   void LoadRoot(Register destination, Heap::RootListIndex index);
   void CompareRoot(Register with, Heap::RootListIndex index);
-  void CompareRoot(Operand with, Heap::RootListIndex index);
+  void CompareRoot(const Operand& with, Heap::RootListIndex index);
   void PushRoot(Heap::RootListIndex index);
   void StoreRoot(Register source, Heap::RootListIndex index);
 
@@ -607,7 +607,7 @@ class MacroAssembler: public Assembler {
   // Emit call to the code we are currently generating.
   void CallSelf() {
     Handle<Code> self(reinterpret_cast<Code**>(CodeObject().location()));
-    call(self, RelocInfo::CODE_TARGET);
+    Call(self, RelocInfo::CODE_TARGET);
   }
 
   // Non-x64 instructions.
index d7e446d1c39201d5de0b64e6d414c839198552da..9b070d20642d587f2eaa4c88c559bf1e05514fba 100644 (file)
@@ -66,7 +66,7 @@ test-deoptimization/DeoptimizeBinaryOperationMOD: FAIL
 test-deoptimization/DeoptimizeBinaryOperationDIV: FAIL
 test-deoptimization/DeoptimizeLoadICStoreIC: FAIL
 test-deoptimization/DeoptimizeLoadICStoreICNested: FAIL
-test-deoptimization/DeoptimizeCompare: FAIL
+test-deoptimization/DeoptimizeCompare: PASS || FAIL
 
 # Tests that time out with crankshaft.
 test-api/Threading: SKIP