Improve polymorphic loads on single slots.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 23 Mar 2012 16:37:54 +0000 (16:37 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 23 Mar 2012 16:37:54 +0000 (16:37 +0000)
If all property lookups for a polymorphic load actually result in the
same field index under all maps, we can actually emit a monomorphic load
that is guarded by a map check that verifies that the actual map is in
the set of handled maps. This also allows GVN to get rid of redundant
such map checks.

R=danno@chromium.org

Review URL: https://chromiumcodereview.appspot.com/9616014

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11132 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/ast.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
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/small-pointer-list.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-x64.cc
src/x64/lithium-x64.h

index cdc1947d4e16bfd969987bed0442da731eb05ead..ab23b1163c0ef74ec5d431154fe251a1b38245b8 100644 (file)
@@ -1753,9 +1753,9 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
+LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
   LOperand* value = UseRegisterAtStart(instr->value());
-  LInstruction* result = new(zone()) LCheckMap(value);
+  LInstruction* result = new(zone()) LCheckMaps(value);
   return AssignEnvironment(result);
 }
 
index 62cde6e249dd8f238b03d0485bbbc45f3043c0fc..a919a1d3bec6adf39acd0dac337cf32c869a3f99 100644 (file)
@@ -72,7 +72,7 @@ class LCodeGen;
   V(CheckFunction)                              \
   V(CheckInstanceType)                          \
   V(CheckNonSmi)                                \
-  V(CheckMap                                  \
+  V(CheckMaps)                                  \
   V(CheckPrototypeMaps)                         \
   V(CheckSmi)                                   \
   V(ClampDToUint8)                              \
@@ -1889,14 +1889,14 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> {
 };
 
 
-class LCheckMap: public LTemplateInstruction<0, 1, 0> {
+class LCheckMaps: public LTemplateInstruction<0, 1, 0> {
  public:
-  explicit LCheckMap(LOperand* value) {
+  explicit LCheckMaps(LOperand* value) {
     inputs_[0] = value;
   }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map")
-  DECLARE_HYDROGEN_ACCESSOR(CheckMap)
+  DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps")
+  DECLARE_HYDROGEN_ACCESSOR(CheckMaps)
 };
 
 
index 82b80a2b802d685c5c8ba400bf9a1bb58da7b3ba..7a099ccb32c8c286eac4bdcc32e8860305ba3af8 100644 (file)
@@ -4338,14 +4338,22 @@ void LCodeGen::DoCheckMapCommon(Register reg,
 }
 
 
-void LCodeGen::DoCheckMap(LCheckMap* instr) {
+void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
   Register scratch = scratch0();
   LOperand* input = instr->InputAt(0);
   ASSERT(input->IsRegister());
   Register reg = ToRegister(input);
-  Handle<Map> map = instr->hydrogen()->map();
-  DoCheckMapCommon(reg, scratch, map, instr->hydrogen()->mode(),
-                   instr->environment());
+
+  Label success;
+  SmallMapList* map_set = instr->hydrogen()->map_set();
+  for (int i = 0; i < map_set->length() - 1; i++) {
+    Handle<Map> map = map_set->at(i);
+    __ CompareMap(reg, scratch, map, &success, REQUIRE_EXACT_MAP);
+    __ b(eq, &success);
+  }
+  Handle<Map> map = map_set->last();
+  DoCheckMapCommon(reg, scratch, map, REQUIRE_EXACT_MAP, instr->environment());
+  __ bind(&success);
 }
 
 
index b827302ebd82da0878281f69fce2ffb490110494..d6c47e2be3bd54bb5b184b1de43e38af34e9d96f 100644 (file)
--- a/src/ast.h
+++ b/src/ast.h
@@ -270,6 +270,7 @@ class SmallMapList {
 
   void Reserve(int capacity) { list_.Reserve(capacity); }
   void Clear() { list_.Clear(); }
+  void Sort() { list_.Sort(); }
 
   bool is_empty() const { return list_.is_empty(); }
   int length() const { return list_.length(); }
index f698da46d41f078aad24b2a1a1ec5eabc6acaa0b..f81f5f0667f83289c946547758452e852e24ba5c 100644 (file)
@@ -965,16 +965,13 @@ void HCheckInstanceType::GetCheckMaskAndTag(uint8_t* mask, uint8_t* tag) {
 }
 
 
-void HCheckMap::PrintDataTo(StringStream* stream) {
+void HCheckMaps::PrintDataTo(StringStream* stream) {
   value()->PrintNameTo(stream);
-  stream->Add(" %p", *map());
-  if (mode() == REQUIRE_EXACT_MAP) {
-    stream->Add(" [EXACT]");
-  } else if (!has_element_transitions_) {
-    stream->Add(" [EXACT*]");
-  } else {
-    stream->Add(" [MATCH ELEMENTS]");
+  stream->Add(" [%p", *map_set()->first());
+  for (int i = 1; i < map_set()->length(); ++i) {
+    stream->Add(",%p", *map_set()->at(i));
   }
+  stream->Add("]");
 }
 
 
@@ -1879,7 +1876,7 @@ HType HValue::CalculateInferredType() {
 }
 
 
-HType HCheckMap::CalculateInferredType() {
+HType HCheckMaps::CalculateInferredType() {
   return value()->type();
 }
 
index fb5879fd90c15cedcbe0ed45dee448ec5d420af7..970f621ba124dd235ef86de5daab7e1349cf9962 100644 (file)
@@ -85,7 +85,7 @@ class LChunkBuilder;
   V(Change)                                    \
   V(CheckFunction)                             \
   V(CheckInstanceType)                         \
-  V(CheckMap                                 \
+  V(CheckMaps)                                 \
   V(CheckNonSmi)                               \
   V(CheckPrototypeMaps)                        \
   V(CheckSmi)                                  \
@@ -1998,14 +1998,9 @@ class HLoadExternalArrayPointer: public HUnaryOperation {
 };
 
 
-class HCheckMap: public HTemplateInstruction<2> {
+class HCheckMaps: public HTemplateInstruction<2> {
  public:
-  HCheckMap(HValue* value,
-            Handle<Map> map,
-            HValue* typecheck = NULL,
-            CompareMapMode mode = REQUIRE_EXACT_MAP)
-      : map_(map),
-        mode_(mode) {
+  HCheckMaps(HValue* value, Handle<Map> map, HValue* typecheck = NULL) {
     SetOperandAt(0, value);
     // If callers don't depend on a typecheck, they can pass in NULL. In that
     // case we use a copy of the |value| argument as a dummy value.
@@ -2013,14 +2008,49 @@ class HCheckMap: public HTemplateInstruction<2> {
     set_representation(Representation::Tagged());
     SetFlag(kUseGVN);
     SetGVNFlag(kDependsOnMaps);
-    // If the map to check doesn't have the untransitioned elements, it must not
-    // be hoisted above TransitionElements instructions.
-    if (mode == REQUIRE_EXACT_MAP || !map->has_fast_smi_only_elements()) {
-      SetGVNFlag(kDependsOnElementsKind);
+    SetGVNFlag(kDependsOnElementsKind);
+    map_set()->Add(map);
+  }
+  HCheckMaps(HValue* value, SmallMapList* maps) {
+    SetOperandAt(0, value);
+    SetOperandAt(1, value);
+    set_representation(Representation::Tagged());
+    SetFlag(kUseGVN);
+    SetGVNFlag(kDependsOnMaps);
+    SetGVNFlag(kDependsOnElementsKind);
+    for (int i = 0; i < maps->length(); i++) {
+      map_set()->Add(maps->at(i));
+    }
+    map_set()->Sort();
+  }
+
+  static HCheckMaps* NewWithTransitions(HValue* object, Handle<Map> map) {
+    HCheckMaps* check_map = new HCheckMaps(object, map);
+    SmallMapList* map_set = check_map->map_set();
+
+    // If the map to check has the untransitioned elements, it can be hoisted
+    // above TransitionElements instructions.
+    if (map->has_fast_smi_only_elements()) {
+      check_map->ClearGVNFlag(kDependsOnElementsKind);
+    }
+
+    Map* transitioned_fast_element_map =
+        map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL);
+    ASSERT(transitioned_fast_element_map == NULL ||
+           map->elements_kind() != FAST_ELEMENTS);
+    if (transitioned_fast_element_map != NULL) {
+      map_set->Add(Handle<Map>(transitioned_fast_element_map));
+    }
+    Map* transitioned_double_map =
+        map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL);
+    ASSERT(transitioned_double_map == NULL ||
+           map->elements_kind() == FAST_SMI_ONLY_ELEMENTS);
+    if (transitioned_double_map != NULL) {
+      map_set->Add(Handle<Map>(transitioned_double_map));
     }
-    has_element_transitions_ =
-        map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, NULL) != NULL ||
-        map->LookupElementsTransitionMap(FAST_ELEMENTS, NULL) != NULL;
+    map_set->Sort();
+
+    return check_map;
   }
 
   virtual Representation RequiredInputRepresentation(int index) {
@@ -2030,25 +2060,23 @@ class HCheckMap: public HTemplateInstruction<2> {
   virtual HType CalculateInferredType();
 
   HValue* value() { return OperandAt(0); }
-  Handle<Map> map() const { return map_; }
-  CompareMapMode mode() const { return mode_; }
+  SmallMapList* map_set() { return &map_set_; }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckMap)
+  DECLARE_CONCRETE_INSTRUCTION(CheckMaps)
 
  protected:
   virtual bool DataEquals(HValue* other) {
-    HCheckMap* b = HCheckMap::cast(other);
-    // Two CheckMaps instructions are DataEqual if their maps are identical and
-    // they have the same mode. The mode comparison can be ignored if the map
-    // has no elements transitions.
-    return map_.is_identical_to(b->map()) &&
-        (b->mode() == mode() || !has_element_transitions_);
+    HCheckMaps* b = HCheckMaps::cast(other);
+    // Relies on the fact that map_set has been sorted before.
+    if (map_set()->length() != b->map_set()->length()) return false;
+    for (int i = 0; i < map_set()->length(); i++) {
+      if (!map_set()->at(i).is_identical_to(b->map_set()->at(i))) return false;
+    }
+    return true;
   }
 
  private:
-  bool has_element_transitions_;
-  Handle<Map> map_;
-  CompareMapMode mode_;
+  SmallMapList map_set_;
 };
 
 
index 9b774082327ee145c0ff19914cf09f4f79f94cfe..4da1609842b3d2efb454d36c1576822fffec8ac7 100644 (file)
@@ -3910,21 +3910,22 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) {
 }
 
 
-// Sets the lookup result and returns true if the store can be inlined.
-static bool ComputeStoredField(Handle<Map> type,
-                               Handle<String> name,
-                               LookupResult* lookup) {
+// Sets the lookup result and returns true if the load/store can be inlined.
+static bool ComputeLoadStoreField(Handle<Map> type,
+                                  Handle<String> name,
+                                  LookupResult* lookup,
+                                  bool is_store) {
   type->LookupInDescriptors(NULL, *name, lookup);
   if (!lookup->IsFound()) return false;
   if (lookup->type() == FIELD) return true;
-  return (lookup->type() == MAP_TRANSITION) &&
+  return is_store && (lookup->type() == MAP_TRANSITION) &&
       (type->unused_property_fields() > 0);
 }
 
 
-static int ComputeStoredFieldIndex(Handle<Map> type,
-                                   Handle<String> name,
-                                   LookupResult* lookup) {
+static int ComputeLoadStoreFieldIndex(Handle<Map> type,
+                                      Handle<String> name,
+                                      LookupResult* lookup) {
   ASSERT(lookup->type() == FIELD || lookup->type() == MAP_TRANSITION);
   if (lookup->type() == FIELD) {
     return lookup->GetLocalFieldIndexFromMap(*type);
@@ -3943,11 +3944,10 @@ HInstruction* HGraphBuilder::BuildStoreNamedField(HValue* object,
                                                   bool smi_and_map_check) {
   if (smi_and_map_check) {
     AddInstruction(new(zone()) HCheckNonSmi(object));
-    AddInstruction(new(zone()) HCheckMap(object, type, NULL,
-                                         ALLOW_ELEMENT_TRANSITION_MAPS));
+    AddInstruction(HCheckMaps::NewWithTransitions(object, type));
   }
 
-  int index = ComputeStoredFieldIndex(type, name, lookup);
+  int index = ComputeLoadStoreFieldIndex(type, name, lookup);
   bool is_in_object = index < 0;
   int offset = index * kPointerSize;
   if (index < 0) {
@@ -3993,7 +3993,7 @@ HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
   LookupResult lookup(isolate());
   Handle<Map> type = prop->GetReceiverType();
   bool is_monomorphic = prop->IsMonomorphic() &&
-      ComputeStoredField(type, name, &lookup);
+      ComputeLoadStoreField(type, name, &lookup, true);
 
   return is_monomorphic
       ? BuildStoreNamedField(object, name, value, type, &lookup,
@@ -4015,7 +4015,7 @@ HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
   LookupResult lookup(isolate());
   SmallMapList* types = expr->GetReceiverTypes();
   bool is_monomorphic = expr->IsMonomorphic() &&
-      ComputeStoredField(types->first(), name, &lookup);
+      ComputeLoadStoreField(types->first(), name, &lookup, true);
 
   return is_monomorphic
       ? BuildStoreNamedField(object, name, value, types->first(), &lookup,
@@ -4024,6 +4024,47 @@ HInstruction* HGraphBuilder::BuildStoreNamed(HValue* object,
 }
 
 
+void HGraphBuilder::HandlePolymorphicLoadNamedField(Property* expr,
+                                                    HValue* object,
+                                                    SmallMapList* types,
+                                                    Handle<String> name) {
+  int count = 0;
+  int previous_field_index = 0;
+  bool is_monomorphic_field = true;
+  Handle<Map> map;
+  LookupResult lookup(isolate());
+  for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) {
+    map = types->at(i);
+    if (ComputeLoadStoreField(map, name, &lookup, false)) {
+      int index = ComputeLoadStoreFieldIndex(map, name, &lookup);
+      if (count == 0) {
+        previous_field_index = index;
+      } else if (is_monomorphic_field) {
+        is_monomorphic_field = (index == previous_field_index);
+      }
+      ++count;
+    }
+  }
+
+  // Use monomorphic load if property lookup results in the same field index
+  // for all maps.  Requires special map check on the set of all handled maps.
+  HInstruction* instr;
+  if (count == types->length() && is_monomorphic_field) {
+    AddInstruction(new(zone()) HCheckMaps(object, types));
+    instr = BuildLoadNamedField(object, expr, map, &lookup, false);
+  } else {
+    HValue* context = environment()->LookupContext();
+    instr = new(zone()) HLoadNamedFieldPolymorphic(context,
+                                                   object,
+                                                   types,
+                                                   name);
+  }
+
+  instr->set_position(expr->position());
+  return ast_context()->ReturnInstruction(instr, expr->id());
+}
+
+
 void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
                                                      HValue* object,
                                                      HValue* value,
@@ -4037,7 +4078,7 @@ void HGraphBuilder::HandlePolymorphicStoreNamedField(Assignment* expr,
   for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) {
     Handle<Map> map = types->at(i);
     LookupResult lookup(isolate());
-    if (ComputeStoredField(map, name, &lookup)) {
+    if (ComputeLoadStoreField(map, name, &lookup, true)) {
       if (count == 0) {
         AddInstruction(new(zone()) HCheckNonSmi(object));  // Only needed once.
         join = graph()->CreateBasicBlock();
@@ -4508,8 +4549,7 @@ HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
                                                     bool smi_and_map_check) {
   if (smi_and_map_check) {
     AddInstruction(new(zone()) HCheckNonSmi(object));
-    AddInstruction(new(zone()) HCheckMap(object, type, NULL,
-                                         ALLOW_ELEMENT_TRANSITION_MAPS));
+    AddInstruction(HCheckMaps::NewWithTransitions(object, type));
   }
 
   int index = lookup->GetLocalFieldIndexFromMap(*type);
@@ -4553,8 +4593,7 @@ HInstruction* HGraphBuilder::BuildLoadNamed(HValue* obj,
                                true);
   } else if (lookup.IsFound() && lookup.type() == CONSTANT_FUNCTION) {
     AddInstruction(new(zone()) HCheckNonSmi(obj));
-    AddInstruction(new(zone()) HCheckMap(obj, map, NULL,
-                                         ALLOW_ELEMENT_TRANSITION_MAPS));
+    AddInstruction(HCheckMaps::NewWithTransitions(obj, map));
     Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*map));
     return new(zone()) HConstant(function, Representation::Tagged());
   } else {
@@ -4656,12 +4695,12 @@ HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object,
                                                            HValue* val,
                                                            Handle<Map> map,
                                                            bool is_store) {
-  HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMap(object, map));
+  HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMaps(object, map));
   bool fast_smi_only_elements = map->has_fast_smi_only_elements();
   bool fast_elements = map->has_fast_elements();
   HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object));
   if (is_store && (fast_elements || fast_smi_only_elements)) {
-    AddInstruction(new(zone()) HCheckMap(
+    AddInstruction(new(zone()) HCheckMaps(
         elements, isolate()->factory()->fixed_array_map()));
   }
   HInstruction* length = NULL;
@@ -4811,7 +4850,7 @@ HValue* HGraphBuilder::HandlePolymorphicElementAccess(HValue* object,
           elements_kind == FAST_ELEMENTS ||
           elements_kind == FAST_DOUBLE_ELEMENTS) {
         if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) {
-          AddInstruction(new(zone()) HCheckMap(
+          AddInstruction(new(zone()) HCheckMaps(
               elements, isolate()->factory()->fixed_array_map(),
               elements_kind_branch));
         }
@@ -5015,8 +5054,8 @@ void HGraphBuilder::VisitProperty(Property* expr) {
       instr = BuildLoadNamed(obj, expr, types->first(), name);
     } else if (types != NULL && types->length() > 1) {
       AddInstruction(new(zone()) HCheckNonSmi(obj));
-      HValue* context = environment()->LookupContext();
-      instr = new(zone()) HLoadNamedFieldPolymorphic(context, obj, types, name);
+      HandlePolymorphicLoadNamedField(expr, obj, types, name);
+      return;
     } else {
       instr = BuildLoadNamedGeneric(obj, expr);
     }
@@ -5057,8 +5096,7 @@ void HGraphBuilder::AddCheckConstantFunction(Call* expr,
   // its prototypes.
   if (smi_and_map_check) {
     AddInstruction(new(zone()) HCheckNonSmi(receiver));
-    AddInstruction(new(zone()) HCheckMap(receiver, receiver_map, NULL,
-                                         ALLOW_ELEMENT_TRANSITION_MAPS));
+    AddInstruction(HCheckMaps::NewWithTransitions(receiver, receiver_map));
   }
   if (!expr->holder().is_null()) {
     AddInstruction(new(zone()) HCheckPrototypeMaps(
@@ -6869,11 +6907,9 @@ void HGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
         Handle<Map> map = oracle()->GetCompareMap(expr);
         if (!map.is_null()) {
           AddInstruction(new(zone()) HCheckNonSmi(left));
-          AddInstruction(new(zone()) HCheckMap(left, map, NULL,
-                                               ALLOW_ELEMENT_TRANSITION_MAPS));
+          AddInstruction(HCheckMaps::NewWithTransitions(left, map));
           AddInstruction(new(zone()) HCheckNonSmi(right));
-          AddInstruction(new(zone()) HCheckMap(right, map, NULL,
-                                               ALLOW_ELEMENT_TRANSITION_MAPS));
+          AddInstruction(HCheckMaps::NewWithTransitions(right, map));
           HCompareObjectEqAndBranch* result =
               new(zone()) HCompareObjectEqAndBranch(left, right);
           result->set_position(expr->position());
index e2779bb2260d10cfed8b0a048dd641b685e4cba6..bc9bc9de05ecd9046eed2677bc0d14f861eae885 100644 (file)
@@ -1029,6 +1029,10 @@ class HGraphBuilder: public AstVisitor {
 
   void HandlePropertyAssignment(Assignment* expr);
   void HandleCompoundAssignment(Assignment* expr);
+  void HandlePolymorphicLoadNamedField(Property* expr,
+                                       HValue* object,
+                                       SmallMapList* types,
+                                       Handle<String> name);
   void HandlePolymorphicStoreNamedField(Assignment* expr,
                                         HValue* object,
                                         HValue* value,
index 8fb4c79196fdc2c9c2161b62ea4fab8c5c509aeb..67e2dca56336f10ff1818dc146e82e381750f78a 100644 (file)
@@ -4181,12 +4181,21 @@ void LCodeGen::DoCheckMapCommon(Register reg,
 }
 
 
-void LCodeGen::DoCheckMap(LCheckMap* instr) {
+void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
   LOperand* input = instr->InputAt(0);
   ASSERT(input->IsRegister());
   Register reg = ToRegister(input);
-  Handle<Map> map = instr->hydrogen()->map();
-  DoCheckMapCommon(reg, map, instr->hydrogen()->mode(), instr->environment());
+
+  Label success;
+  SmallMapList* map_set = instr->hydrogen()->map_set();
+  for (int i = 0; i < map_set->length() - 1; i++) {
+    Handle<Map> map = map_set->at(i);
+    __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
+    __ j(equal, &success);
+  }
+  Handle<Map> map = map_set->last();
+  DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment());
+  __ bind(&success);
 }
 
 
index 2bfbb67bce1525e2affa766c1ed727c51c800b61..a408bdf08aa5236960b6683b62e0041ceeb52e5b 100644 (file)
@@ -1800,9 +1800,9 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
+LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
   LOperand* value = UseRegisterAtStart(instr->value());
-  LCheckMap* result = new(zone()) LCheckMap(value);
+  LCheckMaps* result = new(zone()) LCheckMaps(value);
   return AssignEnvironment(result);
 }
 
index 4ecce96d0f230598b88dcb94d024bb52ad54fc61..0cfed121b6f3905fdef8b473cdcf92f578e236d0 100644 (file)
@@ -65,7 +65,7 @@ class LCodeGen;
   V(CallStub)                                   \
   V(CheckFunction)                              \
   V(CheckInstanceType)                          \
-  V(CheckMap                                  \
+  V(CheckMaps)                                  \
   V(CheckNonSmi)                                \
   V(CheckPrototypeMaps)                         \
   V(CheckSmi)                                   \
@@ -1949,14 +1949,14 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 1> {
 };
 
 
-class LCheckMap: public LTemplateInstruction<0, 1, 0> {
+class LCheckMaps: public LTemplateInstruction<0, 1, 0> {
  public:
-  explicit LCheckMap(LOperand* value) {
+  explicit LCheckMaps(LOperand* value) {
     inputs_[0] = value;
   }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map")
-  DECLARE_HYDROGEN_ACCESSOR(CheckMap)
+  DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps")
+  DECLARE_HYDROGEN_ACCESSOR(CheckMaps)
 };
 
 
index 94e8979ba3abe6d30842e7ffd0453af4a3ca38f4..1b36d5b5c25ff386d80e2a9ab7ec3a495cd48bce 100644 (file)
@@ -4237,7 +4237,7 @@ void LCodeGen::DoCheckMapCommon(Register reg,
 }
 
 
-void LCodeGen::DoCheckMap(LCheckMap* instr) {
+void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
   Register scratch = scratch0();
   LOperand* input = instr->InputAt(0);
   ASSERT(input->IsRegister());
index 1e0c2160aaf25ef356ab7a73a14392d4d727664c..4585a4e20e9cc0c81395cfa70dddf91d9c88fa1d 100644 (file)
@@ -1755,9 +1755,9 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
+LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
   LOperand* value = UseRegisterAtStart(instr->value());
-  LInstruction* result = new(zone()) LCheckMap(value);
+  LInstruction* result = new(zone()) LCheckMaps(value);
   return AssignEnvironment(result);
 }
 
index 5a7bf4d941b577dd8a9a7d7268a5b67891bc46e4..952df990722f96a5a96684ef42ad119139e83814 100644 (file)
@@ -71,7 +71,7 @@ class LCodeGen;
   V(CallStub)                                   \
   V(CheckFunction)                              \
   V(CheckInstanceType)                          \
-  V(CheckMap                                  \
+  V(CheckMaps)                                  \
   V(CheckNonSmi)                                \
   V(CheckPrototypeMaps)                         \
   V(CheckSmi)                                   \
@@ -1869,14 +1869,14 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> {
 };
 
 
-class LCheckMap: public LTemplateInstruction<0, 1, 0> {
+class LCheckMaps: public LTemplateInstruction<0, 1, 0> {
  public:
-  explicit LCheckMap(LOperand* value) {
+  explicit LCheckMaps(LOperand* value) {
     inputs_[0] = value;
   }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map")
-  DECLARE_HYDROGEN_ACCESSOR(CheckMap)
+  DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps")
+  DECLARE_HYDROGEN_ACCESSOR(CheckMaps)
 };
 
 
index 6c5ce890d2cb64fe8c437bf99c96efb144786357..75fea061ad74b4209271e2d7982baa75f100d705 100644 (file)
@@ -69,6 +69,12 @@ class SmallPointerList {
     data_ = kEmptyTag;
   }
 
+  void Sort() {
+    if ((data_ & kTagMask) == kListTag) {
+      list()->Sort(compare_value);
+    }
+  }
+
   bool is_empty() const { return length() == 0; }
 
   int length() const {
@@ -159,6 +165,10 @@ class SmallPointerList {
  private:
   typedef ZoneList<T*> PointerList;
 
+  static int compare_value(T* const* a, T* const* b) {
+    return Compare<T>(**a, **b);
+  }
+
   static const intptr_t kEmptyTag = 1;
   static const intptr_t kSingletonTag = 0;
   static const intptr_t kListTag = 2;
index 2ba2c57f40b4304bb8dd515b31b6731e5cd1fe7a..1f5ec4b907baf51105a9da12819dda6ad49a9cae 100644 (file)
@@ -3953,12 +3953,21 @@ void LCodeGen::DoCheckMapCommon(Register reg,
 }
 
 
-void LCodeGen::DoCheckMap(LCheckMap* instr) {
+void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
   LOperand* input = instr->InputAt(0);
   ASSERT(input->IsRegister());
   Register reg = ToRegister(input);
-  Handle<Map> map = instr->hydrogen()->map();
-  DoCheckMapCommon(reg, map, instr->hydrogen()->mode(), instr->environment());
+
+  Label success;
+  SmallMapList* map_set = instr->hydrogen()->map_set();
+  for (int i = 0; i < map_set->length() - 1; i++) {
+    Handle<Map> map = map_set->at(i);
+    __ CompareMap(reg, map, &success, REQUIRE_EXACT_MAP);
+    __ j(equal, &success);
+  }
+  Handle<Map> map = map_set->last();
+  DoCheckMapCommon(reg, map, REQUIRE_EXACT_MAP, instr->environment());
+  __ bind(&success);
 }
 
 
index d3e4cddf749c76e7717da38e4d081b9ba3ec780d..7c47df6a59e471fb1e6163d1aa36505cd8fd1e9e 100644 (file)
@@ -1737,9 +1737,9 @@ LInstruction* LChunkBuilder::DoCheckFunction(HCheckFunction* instr) {
 }
 
 
-LInstruction* LChunkBuilder::DoCheckMap(HCheckMap* instr) {
+LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
   LOperand* value = UseRegisterAtStart(instr->value());
-  LCheckMap* result = new(zone()) LCheckMap(value);
+  LCheckMaps* result = new(zone()) LCheckMaps(value);
   return AssignEnvironment(result);
 }
 
index 2d8fd2ecce26ccddc958c3ac07ff1d3a9b50ae58..99f28f0b692a115487b42f02a63d7ff847eef78a 100644 (file)
@@ -71,7 +71,7 @@ class LCodeGen;
   V(CallStub)                                   \
   V(CheckFunction)                              \
   V(CheckInstanceType)                          \
-  V(CheckMap                                  \
+  V(CheckMaps)                                  \
   V(CheckNonSmi)                                \
   V(CheckPrototypeMaps)                         \
   V(CheckSmi)                                   \
@@ -1857,14 +1857,14 @@ class LCheckInstanceType: public LTemplateInstruction<0, 1, 0> {
 };
 
 
-class LCheckMap: public LTemplateInstruction<0, 1, 0> {
+class LCheckMaps: public LTemplateInstruction<0, 1, 0> {
  public:
-  explicit LCheckMap(LOperand* value) {
+  explicit LCheckMaps(LOperand* value) {
     inputs_[0] = value;
   }
 
-  DECLARE_CONCRETE_INSTRUCTION(CheckMap, "check-map")
-  DECLARE_HYDROGEN_ACCESSOR(CheckMap)
+  DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps")
+  DECLARE_HYDROGEN_ACCESSOR(CheckMaps)
 };