Implement proper map checks of captured objects.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Aug 2013 14:16:57 +0000 (14:16 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 28 Aug 2013 14:16:57 +0000 (14:16 +0000)
R=verwaest@chromium.org
TEST=mjsunit/compiler/escape-analysis

Review URL: https://codereview.chromium.org/23697002

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

18 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/hydrogen-escape-analysis.cc
src/hydrogen-escape-analysis.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/mips/lithium-codegen-mips.cc
src/mips/lithium-mips.cc
src/mips/lithium-mips.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h
test/mjsunit/compiler/escape-analysis.js

index 5978fad..d0d7f5c 100644 (file)
@@ -2027,9 +2027,9 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
+LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
   LOperand* value = UseRegisterAtStart(instr->value());
-  return AssignEnvironment(new(zone()) LCheckFunction(value));
+  return AssignEnvironment(new(zone()) LCheckValue(value));
 }
 
 
index 90fb117..781dcf4 100644 (file)
@@ -62,12 +62,12 @@ class LCodeGen;
   V(CallNewArray)                               \
   V(CallRuntime)                                \
   V(CallStub)                                   \
-  V(CheckFunction)                              \
   V(CheckInstanceType)                          \
   V(CheckNonSmi)                                \
   V(CheckMaps)                                  \
   V(CheckMapValue)                              \
   V(CheckSmi)                                   \
+  V(CheckValue)                                 \
   V(ClampDToUint8)                              \
   V(ClampIToUint8)                              \
   V(ClampTToUint8)                              \
@@ -2338,16 +2338,16 @@ class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 1, 0> {
 };
 
 
-class LCheckFunction V8_FINAL : public LTemplateInstruction<0, 1, 0> {
+class LCheckValue V8_FINAL : public LTemplateInstruction<0, 1, 0> {
  public:
-  explicit LCheckFunction(LOperand* value) {
+  explicit LCheckValue(LOperand* value) {
     inputs_[0] = value;
   }
 
   LOperand* value() { return inputs_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function")
-  DECLARE_HYDROGEN_ACCESSOR(CheckFunction)
+  DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value")
+  DECLARE_HYDROGEN_ACCESSOR(CheckValue)
 };
 
 
index e34e15b..9cb92e8 100644 (file)
@@ -5131,18 +5131,18 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
 }
 
 
-void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
+void LCodeGen::DoCheckValue(LCheckValue* instr) {
   Register reg = ToRegister(instr->value());
-  Handle<JSFunction> target = instr->hydrogen()->target();
+  Handle<HeapObject> object = instr->hydrogen()->object();
   AllowDeferredHandleDereference smi_check;
-  if (isolate()->heap()->InNewSpace(*target)) {
+  if (isolate()->heap()->InNewSpace(*object)) {
     Register reg = ToRegister(instr->value());
-    Handle<Cell> cell = isolate()->factory()->NewCell(target);
+    Handle<Cell> cell = isolate()->factory()->NewCell(object);
     __ mov(ip, Operand(Handle<Object>(cell)));
     __ ldr(ip, FieldMemOperand(ip, Cell::kValueOffset));
     __ cmp(reg, ip);
   } else {
-    __ cmp(reg, Operand(target));
+    __ cmp(reg, Operand(object));
   }
   DeoptimizeIf(ne, instr->environment());
 }
index b508644..145a779 100644 (file)
@@ -86,7 +86,8 @@ HCapturedObject* HEscapeAnalysisPhase::NewStateForAllocation(
 
 // Create a new state full of phis for loop header entries.
 HCapturedObject* HEscapeAnalysisPhase::NewStateForLoopHeader(
-    HInstruction* previous, HCapturedObject* old_state) {
+    HInstruction* previous,
+    HCapturedObject* old_state) {
   HBasicBlock* block = previous->block();
   HCapturedObject* state = NewState(previous);
   for (int index = 0; index < number_of_values_; index++) {
@@ -100,7 +101,8 @@ HCapturedObject* HEscapeAnalysisPhase::NewStateForLoopHeader(
 
 // Create a new state by copying an existing one.
 HCapturedObject* HEscapeAnalysisPhase::NewStateCopy(
-    HInstruction* previous, HCapturedObject* old_state) {
+    HInstruction* previous,
+    HCapturedObject* old_state) {
   HCapturedObject* state = NewState(previous);
   for (int index = 0; index < number_of_values_; index++) {
     HValue* operand = old_state->OperandAt(index);
@@ -112,8 +114,9 @@ HCapturedObject* HEscapeAnalysisPhase::NewStateCopy(
 
 // Insert a newly created phi into the given block and fill all incoming
 // edges with the given value.
-HPhi* HEscapeAnalysisPhase::NewPhiAndInsert(
-    HBasicBlock* block, HValue* incoming_value, int index) {
+HPhi* HEscapeAnalysisPhase::NewPhiAndInsert(HBasicBlock* block,
+                                            HValue* incoming_value,
+                                            int index) {
   Zone* zone = graph()->zone();
   HPhi* phi = new(zone) HPhi(HPhi::kInvalidMergedIndex, zone);
   for (int i = 0; i < block->predecessors()->length(); i++) {
@@ -124,6 +127,21 @@ HPhi* HEscapeAnalysisPhase::NewPhiAndInsert(
 }
 
 
+// Insert a newly created value check as a replacement for map checks.
+HValue* HEscapeAnalysisPhase::NewMapCheckAndInsert(HCapturedObject* state,
+                                                   HCheckMaps* mapcheck) {
+  Zone* zone = graph()->zone();
+  HValue* value = state->map_value();
+  // TODO(mstarzinger): This will narrow a map check against a set of maps
+  // down to the first element in the set. Revisit and fix this.
+  Handle<Map> map_object = mapcheck->map_set()->first();
+  UniqueValueId map_id = mapcheck->map_unique_ids()->first();
+  HCheckValue* check = HCheckValue::New(zone, NULL, value, map_object, map_id);
+  check->InsertBefore(mapcheck);
+  return check;
+}
+
+
 // Performs a forward data-flow analysis of all loads and stores on the
 // given captured allocation. This uses a reverse post-order iteration
 // over affected basic blocks. All non-escaping instructions are handled
@@ -180,7 +198,7 @@ void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) {
           if (store->HasObservableSideEffects()) {
             state->ReuseSideEffectsFromStore(store);
           }
-          store->DeleteAndReplaceWith(NULL);
+          store->DeleteAndReplaceWith(store->ActualValue());
           if (FLAG_trace_escape_analysis) {
             PrintF("Replacing store #%d%s\n", instr->id(),
                    store->has_transition() ? " (with transition)" : "");
@@ -199,15 +217,13 @@ void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) {
         case HValue::kCheckHeapObject: {
           HCheckHeapObject* check = HCheckHeapObject::cast(instr);
           if (check->value() != allocate) continue;
-          check->DeleteAndReplaceWith(NULL);
+          check->DeleteAndReplaceWith(check->ActualValue());
           break;
         }
         case HValue::kCheckMaps: {
           HCheckMaps* mapcheck = HCheckMaps::cast(instr);
           if (mapcheck->value() != allocate) continue;
-          // TODO(mstarzinger): This approach breaks if the tracked map value
-          // is not a HConstant. Find a repro test case and fix this.
-          ASSERT(mapcheck->ActualValue() == allocate);
+          NewMapCheckAndInsert(state, mapcheck);
           mapcheck->DeleteAndReplaceWith(mapcheck->ActualValue());
           break;
         }
index 2d425e2..9db46cb 100644 (file)
@@ -63,6 +63,8 @@ class HEscapeAnalysisPhase : public HPhase {
 
   HPhi* NewPhiAndInsert(HBasicBlock* block, HValue* incoming_value, int index);
 
+  HValue* NewMapCheckAndInsert(HCapturedObject* state, HCheckMaps* mapcheck);
+
   HCapturedObject* StateAt(HBasicBlock* block) {
     return block_states_.at(block->block_id());
   }
index a9adfc1..f6ee8dc 100644 (file)
@@ -1451,15 +1451,16 @@ void HCheckMaps::PrintDataTo(StringStream* stream) {
 }
 
 
-void HCheckFunction::PrintDataTo(StringStream* stream) {
+void HCheckValue::PrintDataTo(StringStream* stream) {
   value()->PrintNameTo(stream);
-  stream->Add(" %p", *target());
+  stream->Add(" ");
+  object()->ShortPrint(stream);
 }
 
 
-HValue* HCheckFunction::Canonicalize() {
+HValue* HCheckValue::Canonicalize() {
   return (value()->IsConstant() &&
-          HConstant::cast(value())->UniqueValueIdsMatch(target_unique_id_))
+          HConstant::cast(value())->UniqueValueIdsMatch(object_unique_id_))
       ? NULL
       : this;
 }
@@ -4052,7 +4053,7 @@ void HCheckHeapObject::Verify() {
 }
 
 
-void HCheckFunction::Verify() {
+void HCheckValue::Verify() {
   HInstruction::Verify();
   ASSERT(HasNoUses());
 }
index 773ba3b..2e9aa00 100644 (file)
@@ -88,12 +88,12 @@ class LChunkBuilder;
   V(CallStub)                                  \
   V(CapturedObject)                            \
   V(Change)                                    \
-  V(CheckFunction)                             \
   V(CheckHeapObject)                           \
   V(CheckInstanceType)                         \
   V(CheckMaps)                                 \
   V(CheckMapValue)                             \
   V(CheckSmi)                                  \
+  V(CheckValue)                                \
   V(ClampToUint8)                              \
   V(ClassOfTestAndBranch)                      \
   V(CompareNumericAndBranch)                   \
@@ -2562,6 +2562,7 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
 
   HValue* value() { return OperandAt(0); }
   SmallMapList* map_set() { return &map_set_; }
+  ZoneList<UniqueValueId>* map_unique_ids() { return &map_unique_ids_; }
 
   bool has_migration_target() {
     return has_migration_target_;
@@ -2630,9 +2631,20 @@ class HCheckMaps V8_FINAL : public HTemplateInstruction<2> {
 };
 
 
-class HCheckFunction V8_FINAL : public HUnaryOperation {
+class HCheckValue V8_FINAL : public HUnaryOperation {
  public:
-  DECLARE_INSTRUCTION_FACTORY_P2(HCheckFunction, HValue*, Handle<JSFunction>);
+  static HCheckValue* New(Zone* zone, HValue* context,
+                          HValue* value, Handle<JSFunction> target) {
+    bool in_new_space = Isolate::Current()->heap()->InNewSpace(*target);
+    HCheckValue* check = new(zone) HCheckValue(value, target, in_new_space);
+    return check;
+  }
+  static HCheckValue* New(Zone* zone, HValue* context,
+                          HValue* value, Handle<Map> map, UniqueValueId id) {
+    HCheckValue* check = new(zone) HCheckValue(value, map, false);
+    check->object_unique_id_ = id;
+    return check;
+  }
 
   virtual Representation RequiredInputRepresentation(int index) V8_OVERRIDE {
     return Representation::Tagged();
@@ -2646,32 +2658,31 @@ class HCheckFunction V8_FINAL : public HUnaryOperation {
 #endif
 
   virtual void FinalizeUniqueValueId() V8_OVERRIDE {
-    target_unique_id_ = UniqueValueId(target_);
+    object_unique_id_ = UniqueValueId(object_);
   }
 
-  Handle<JSFunction> target() const { return target_; }
-  bool target_in_new_space() const { return target_in_new_space_; }
+  Handle<HeapObject> object() const { return object_; }
+  bool object_in_new_space() const { return object_in_new_space_; }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckFunction)
+  DECLARE_CONCRETE_INSTRUCTION(CheckValue)
 
  protected:
   virtual bool DataEquals(HValue* other) V8_OVERRIDE {
-    HCheckFunction* b = HCheckFunction::cast(other);
-    return target_unique_id_ == b->target_unique_id_;
+    HCheckValue* b = HCheckValue::cast(other);
+    return object_unique_id_ == b->object_unique_id_;
   }
 
  private:
-  HCheckFunction(HValue* value, Handle<JSFunction> function)
+  HCheckValue(HValue* value, Handle<HeapObject> object, bool in_new_space)
       : HUnaryOperation(value, value->type()),
-        target_(function), target_unique_id_() {
+        object_(object), object_in_new_space_(in_new_space) {
     set_representation(Representation::Tagged());
     SetFlag(kUseGVN);
-    target_in_new_space_ = Isolate::Current()->heap()->InNewSpace(*function);
   }
 
-  Handle<JSFunction> target_;
-  UniqueValueId target_unique_id_;
-  bool target_in_new_space_;
+  Handle<HeapObject> object_;
+  UniqueValueId object_unique_id_;
+  bool object_in_new_space_;
 };
 
 
@@ -3230,6 +3241,9 @@ class HCapturedObject V8_FINAL : public HDematerializedObject {
   int length() const { return values_.length(); }
   int capture_id() const { return capture_id_; }
 
+  // Shortcut for the map value of this captured object.
+  HValue* map_value() const { return values()->first(); }
+
   void ReuseSideEffectsFromStore(HInstruction* store) {
     ASSERT(store->HasObservableSideEffects());
     ASSERT(store->IsStoreNamedField());
index bffbcce..445a0a0 100644 (file)
@@ -7110,7 +7110,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
 
         CHECK_ALIVE(VisitForValue(expr->expression()));
         HValue* function = Pop();
-        Add<HCheckFunction>(function, expr->target());
+        Add<HCheckValue>(function, expr->target());
 
         // Replace the global object with the global receiver.
         HGlobalReceiver* global_receiver = Add<HGlobalReceiver>(global_object);
@@ -7162,7 +7162,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
       HGlobalReceiver* receiver = New<HGlobalReceiver>(global);
       PushAndAdd(receiver);
       CHECK_ALIVE(VisitExpressions(expr->arguments()));
-      Add<HCheckFunction>(function, expr->target());
+      Add<HCheckValue>(function, expr->target());
 
       if (TryInlineBuiltinFunctionCall(expr, true)) {  // Drop the function.
         if (FLAG_trace_inlining) {
@@ -7225,7 +7225,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
     HValue* function = Top();
     CHECK_ALIVE(VisitExpressions(expr->arguments()));
     Handle<JSFunction> constructor = expr->target();
-    HValue* check = Add<HCheckFunction>(function, constructor);
+    HValue* check = Add<HCheckValue>(function, constructor);
 
     // Force completion of inobject slack tracking before generating
     // allocation code to finalize instance size.
@@ -7317,7 +7317,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
     HBinaryCall* call;
     if (expr->target().is_identical_to(array_function)) {
       Handle<Cell> cell = expr->allocation_info_cell();
-      Add<HCheckFunction>(constructor, array_function);
+      Add<HCheckValue>(constructor, array_function);
       call = new(zone()) HCallNewArray(context, constructor, argument_count,
                                        cell, expr->elements_kind());
     } else {
@@ -8149,7 +8149,7 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
       result->set_position(expr->position());
       return ast_context()->ReturnInstruction(result, expr->id());
     } else {
-      Add<HCheckFunction>(right, target);
+      Add<HCheckValue>(right, target);
       HInstanceOfKnownGlobal* result =
           new(zone()) HInstanceOfKnownGlobal(context, left, target);
       result->set_position(expr->position());
index ccd623c..e7e0327 100644 (file)
@@ -5800,15 +5800,15 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
 }
 
 
-void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
-  Handle<JSFunction> target = instr->hydrogen()->target();
-  if (instr->hydrogen()->target_in_new_space()) {
+void LCodeGen::DoCheckValue(LCheckValue* instr) {
+  Handle<HeapObject> object = instr->hydrogen()->object();
+  if (instr->hydrogen()->object_in_new_space()) {
     Register reg = ToRegister(instr->value());
-    Handle<Cell> cell = isolate()->factory()->NewCell(target);
+    Handle<Cell> cell = isolate()->factory()->NewCell(object);
     __ cmp(reg, Operand::ForCell(cell));
   } else {
     Operand operand = ToOperand(instr->value());
-    __ cmp(operand, target);
+    __ cmp(operand, object);
   }
   DeoptimizeIf(not_equal, instr->environment());
 }
index 7ec1258..c2ffc50 100644 (file)
@@ -2060,14 +2060,14 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
-  // If the target is in new space, we'll emit a global cell compare and so
-  // want the value in a register.  If the target gets promoted before we
+LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
+  // If the object is in new space, we'll emit a global cell compare and so
+  // want the value in a register.  If the object gets promoted before we
   // emit code, we will still get the register but will do an immediate
   // compare instead of the cell compare.  This is safe.
-  LOperand* value = instr->target_in_new_space()
+  LOperand* value = instr->object_in_new_space()
       ? UseRegisterAtStart(instr->value()) : UseAtStart(instr->value());
-  return AssignEnvironment(new(zone()) LCheckFunction(value));
+  return AssignEnvironment(new(zone()) LCheckValue(value));
 }
 
 
index e8a3baf..e795926 100644 (file)
@@ -62,12 +62,12 @@ class LCodeGen;
   V(CallNewArray)                               \
   V(CallRuntime)                                \
   V(CallStub)                                   \
-  V(CheckFunction)                              \
   V(CheckInstanceType)                          \
   V(CheckMaps)                                  \
   V(CheckMapValue)                              \
   V(CheckNonSmi)                                \
   V(CheckSmi)                                   \
+  V(CheckValue)                                 \
   V(ClampDToUint8)                              \
   V(ClampIToUint8)                              \
   V(ClampTToUint8)                              \
@@ -2437,16 +2437,16 @@ class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 2, 0> {
 };
 
 
-class LCheckFunction V8_FINAL : public LTemplateInstruction<0, 1, 0> {
+class LCheckValue V8_FINAL : public LTemplateInstruction<0, 1, 0> {
  public:
-  explicit LCheckFunction(LOperand* value) {
+  explicit LCheckValue(LOperand* value) {
     inputs_[0] = value;
   }
 
   LOperand* value() { return inputs_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function")
-  DECLARE_HYDROGEN_ACCESSOR(CheckFunction)
+  DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value")
+  DECLARE_HYDROGEN_ACCESSOR(CheckValue)
 };
 
 
index 80794c8..d2ab06a 100644 (file)
@@ -5116,20 +5116,20 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
 }
 
 
-void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
+void LCodeGen::DoCheckValue(LCheckValue* instr) {
   Register reg = ToRegister(instr->value());
-  Handle<JSFunction> target = instr->hydrogen()->target();
+  Handle<HeapObject> object = instr->hydrogen()->object();
   AllowDeferredHandleDereference smi_check;
-  if (isolate()->heap()->InNewSpace(*target)) {
+  if (isolate()->heap()->InNewSpace(*object)) {
     Register reg = ToRegister(instr->value());
-    Handle<Cell> cell = isolate()->factory()->NewCell(target);
+    Handle<Cell> cell = isolate()->factory()->NewCell(object);
     __ li(at, Operand(Handle<Object>(cell)));
     __ lw(at, FieldMemOperand(at, Cell::kValueOffset));
     DeoptimizeIf(ne, instr->environment(), reg,
                  Operand(at));
   } else {
     DeoptimizeIf(ne, instr->environment(), reg,
-                 Operand(target));
+                 Operand(object));
   }
 }
 
index b11c9c2..d71c32b 100644 (file)
@@ -1951,9 +1951,9 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
+LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
   LOperand* value = UseRegisterAtStart(instr->value());
-  return AssignEnvironment(new(zone()) LCheckFunction(value));
+  return AssignEnvironment(new(zone()) LCheckValue(value));
 }
 
 
index 6498943..dfdf63c 100644 (file)
@@ -62,12 +62,12 @@ class LCodeGen;
   V(CallNewArray)                               \
   V(CallRuntime)                                \
   V(CallStub)                                   \
-  V(CheckFunction)                              \
   V(CheckInstanceType)                          \
   V(CheckMaps)                                  \
   V(CheckMapValue)                              \
   V(CheckNonSmi)                                \
   V(CheckSmi)                                   \
+  V(CheckValue)                                 \
   V(ClampDToUint8)                              \
   V(ClampIToUint8)                              \
   V(ClampTToUint8)                              \
@@ -2321,16 +2321,16 @@ class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 1, 0> {
 };
 
 
-class LCheckFunction V8_FINAL : public LTemplateInstruction<0, 1, 0> {
+class LCheckValue V8_FINAL : public LTemplateInstruction<0, 1, 0> {
  public:
-  explicit LCheckFunction(LOperand* value) {
+  explicit LCheckValue(LOperand* value) {
     inputs_[0] = value;
   }
 
   LOperand* value() { return inputs_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function")
-  DECLARE_HYDROGEN_ACCESSOR(CheckFunction)
+  DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value")
+  DECLARE_HYDROGEN_ACCESSOR(CheckValue)
 };
 
 
index 094d239..ce66285 100644 (file)
@@ -4915,10 +4915,10 @@ void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
 }
 
 
-void LCodeGen::DoCheckFunction(LCheckFunction* instr) {
+void LCodeGen::DoCheckValue(LCheckValue* instr) {
   Register reg = ToRegister(instr->value());
-  Handle<JSFunction> target = instr->hydrogen()->target();
-  __ CmpHeapObject(reg, target);
+  Handle<HeapObject> object = instr->hydrogen()->object();
+  __ CmpHeapObject(reg, object);
   DeoptimizeIf(not_equal, instr->environment());
 }
 
index 57938b2..85181c0 100644 (file)
@@ -1940,9 +1940,9 @@ LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
+LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
   LOperand* value = UseRegisterAtStart(instr->value());
-  return AssignEnvironment(new(zone()) LCheckFunction(value));
+  return AssignEnvironment(new(zone()) LCheckValue(value));
 }
 
 
index 00642ff..e95713d 100644 (file)
@@ -62,12 +62,12 @@ class LCodeGen;
   V(CallNewArray)                               \
   V(CallRuntime)                                \
   V(CallStub)                                   \
-  V(CheckFunction)                              \
   V(CheckInstanceType)                          \
   V(CheckMaps)                                  \
   V(CheckMapValue)                              \
   V(CheckNonSmi)                                \
   V(CheckSmi)                                   \
+  V(CheckValue)                                 \
   V(ClampDToUint8)                              \
   V(ClampIToUint8)                              \
   V(ClampTToUint8)                              \
@@ -2260,16 +2260,16 @@ class LStringCharFromCode V8_FINAL : public LTemplateInstruction<1, 1, 0> {
 };
 
 
-class LCheckFunction V8_FINAL : public LTemplateInstruction<0, 1, 0> {
+class LCheckValue V8_FINAL : public LTemplateInstruction<0, 1, 0> {
  public:
-  explicit LCheckFunction(LOperand* value) {
+  explicit LCheckValue(LOperand* value) {
     inputs_[0] = value;
   }
 
   LOperand* value() { return inputs_[0]; }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckFunction, "check-function")
-  DECLARE_HYDROGEN_ACCESSOR(CheckFunction)
+  DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value")
+  DECLARE_HYDROGEN_ACCESSOR(CheckValue)
 };
 
 
index 9b9341b..f32069c 100644 (file)
   delete deopt.deopt;
   func(); func();
 })();
+
+
+// Test map checks on captured objects.
+(function testMapCheck() {
+  var sum = 0;
+  function getter() { return 27; }
+  function setter(v) { sum += v; }
+  function constructor() {
+    this.x = 23;
+    this.y = 42;
+  }
+  function check(x, y) {
+    var o = new constructor();
+    assertEquals(x, o.x);
+    assertEquals(y, o.y);
+  }
+  var monkey = Object.create(null, {
+    x: { get:getter, set:setter },
+    y: { get:getter, set:setter }
+  });
+  check(23, 42); check(23, 42);
+  %OptimizeFunctionOnNextCall(check);
+  check(23, 42); check(23, 42);
+  constructor.prototype = monkey;
+  check(27, 27); check(27, 27);
+  assertEquals(130, sum);
+})();