Track up to 5 stable maps as field type.
authorbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 17 Apr 2014 08:22:22 +0000 (08:22 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 17 Apr 2014 08:22:22 +0000 (08:22 +0000)
R=svenpanne@chromium.org

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

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

src/arm/stub-cache-arm.cc
src/arm64/stub-cache-arm64.cc
src/ia32/stub-cache-ia32.cc
src/objects-debug.cc
src/objects.cc
src/objects.h
src/types.cc
src/types.h
src/x64/stub-cache-x64.cc

index 6875dcf..3d07d56 100644 (file)
@@ -430,13 +430,22 @@ void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
   } else if (representation.IsSmi()) {
     __ JumpIfNotSmi(value_reg, miss_label);
   } else if (representation.IsHeapObject()) {
+    __ JumpIfSmi(value_reg, miss_label);
     HeapType* field_type = descriptors->GetFieldType(descriptor);
-    if (field_type->IsClass()) {
-      __ CheckMap(value_reg, scratch1, field_type->AsClass()->Map(),
-                  miss_label, DO_SMI_CHECK);
-    } else {
-      ASSERT(HeapType::Any()->Is(field_type));
-      __ JumpIfSmi(value_reg, miss_label);
+    HeapType::Iterator<Map> it = field_type->Classes();
+    if (!it.Done()) {
+      __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
+      Label do_store;
+      while (true) {
+        __ CompareMap(scratch1, it.Current(), &do_store);
+        it.Advance();
+        if (it.Done()) {
+          __ b(ne, miss_label);
+          break;
+        }
+        __ b(eq, &do_store);
+      }
+      __ bind(&do_store);
     }
   } else if (representation.IsDouble()) {
     Label do_store, heap_number;
@@ -599,13 +608,22 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   if (representation.IsSmi()) {
     __ JumpIfNotSmi(value_reg, miss_label);
   } else if (representation.IsHeapObject()) {
+    __ JumpIfSmi(value_reg, miss_label);
     HeapType* field_type = lookup->GetFieldType();
-    if (field_type->IsClass()) {
-      __ CheckMap(value_reg, scratch1, field_type->AsClass()->Map(),
-                  miss_label, DO_SMI_CHECK);
-    } else {
-      ASSERT(HeapType::Any()->Is(field_type));
-      __ JumpIfSmi(value_reg, miss_label);
+    HeapType::Iterator<Map> it = field_type->Classes();
+    if (!it.Done()) {
+      __ ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
+      Label do_store;
+      while (true) {
+        __ CompareMap(scratch1, it.Current(), &do_store);
+        it.Advance();
+        if (it.Done()) {
+          __ b(ne, miss_label);
+          break;
+        }
+        __ b(eq, &do_store);
+      }
+      __ bind(&do_store);
     }
   } else if (representation.IsDouble()) {
     // Load the double storage.
index bf12840..b46d813 100644 (file)
@@ -392,13 +392,22 @@ void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
   } else if (representation.IsSmi()) {
     __ JumpIfNotSmi(value_reg, miss_label);
   } else if (representation.IsHeapObject()) {
+    __ JumpIfSmi(value_reg, miss_label);
     HeapType* field_type = descriptors->GetFieldType(descriptor);
-    if (field_type->IsClass()) {
-      __ CheckMap(value_reg, scratch1, field_type->AsClass()->Map(),
-                  miss_label, DO_SMI_CHECK);
-    } else {
-      ASSERT(HeapType::Any()->Is(field_type));
-      __ JumpIfSmi(value_reg, miss_label);
+    HeapType::Iterator<Map> it = field_type->Classes();
+    if (!it.Done()) {
+      __ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
+      Label do_store;
+      while (true) {
+        __ CompareMap(scratch1, it.Current());
+        it.Advance();
+        if (it.Done()) {
+          __ B(ne, miss_label);
+          break;
+        }
+        __ B(eq, &do_store);
+      }
+      __ Bind(&do_store);
     }
   } else if (representation.IsDouble()) {
     UseScratchRegisterScope temps(masm);
@@ -548,13 +557,22 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   if (representation.IsSmi()) {
     __ JumpIfNotSmi(value_reg, miss_label);
   } else if (representation.IsHeapObject()) {
+    __ JumpIfSmi(value_reg, miss_label);
     HeapType* field_type = lookup->GetFieldType();
-    if (field_type->IsClass()) {
-      __ CheckMap(value_reg, scratch1, field_type->AsClass()->Map(),
-                  miss_label, DO_SMI_CHECK);
-    } else {
-      ASSERT(HeapType::Any()->Is(field_type));
-      __ JumpIfSmi(value_reg, miss_label);
+    HeapType::Iterator<Map> it = field_type->Classes();
+    if (!it.Done()) {
+      __ Ldr(scratch1, FieldMemOperand(value_reg, HeapObject::kMapOffset));
+      Label do_store;
+      while (true) {
+        __ CompareMap(scratch1, it.Current());
+        it.Advance();
+        if (it.Done()) {
+          __ B(ne, miss_label);
+          break;
+        }
+        __ B(eq, &do_store);
+      }
+      __ Bind(&do_store);
     }
   } else if (representation.IsDouble()) {
     UseScratchRegisterScope temps(masm);
index 9c82692..b3bc71c 100644 (file)
@@ -528,13 +528,21 @@ void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
   } else if (representation.IsSmi()) {
       __ JumpIfNotSmi(value_reg, miss_label);
   } else if (representation.IsHeapObject()) {
+    __ JumpIfSmi(value_reg, miss_label);
     HeapType* field_type = descriptors->GetFieldType(descriptor);
-    if (field_type->IsClass()) {
-      __ CheckMap(value_reg, field_type->AsClass()->Map(),
-                  miss_label, DO_SMI_CHECK);
-    } else {
-      ASSERT(HeapType::Any()->Is(field_type));
-      __ JumpIfSmi(value_reg, miss_label);
+    HeapType::Iterator<Map> it = field_type->Classes();
+    if (!it.Done()) {
+      Label do_store;
+      while (true) {
+        __ CompareMap(value_reg, it.Current());
+        it.Advance();
+        if (it.Done()) {
+          __ j(not_equal, miss_label);
+          break;
+        }
+        __ j(equal, &do_store, Label::kNear);
+      }
+      __ bind(&do_store);
     }
   } else if (representation.IsDouble()) {
     Label do_store, heap_number;
@@ -705,13 +713,21 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   if (representation.IsSmi()) {
     __ JumpIfNotSmi(value_reg, miss_label);
   } else if (representation.IsHeapObject()) {
+    __ JumpIfSmi(value_reg, miss_label);
     HeapType* field_type = lookup->GetFieldType();
-    if (field_type->IsClass()) {
-      __ CheckMap(value_reg, field_type->AsClass()->Map(),
-                  miss_label, DO_SMI_CHECK);
-    } else {
-      ASSERT(HeapType::Any()->Is(field_type));
-      __ JumpIfSmi(value_reg, miss_label);
+    HeapType::Iterator<Map> it = field_type->Classes();
+    if (!it.Done()) {
+      Label do_store;
+      while (true) {
+        __ CompareMap(value_reg, it.Current());
+        it.Advance();
+        if (it.Done()) {
+          __ j(not_equal, miss_label);
+          break;
+        }
+        __ j(equal, &do_store, Label::kNear);
+      }
+      __ bind(&do_store);
     }
   } else if (representation.IsDouble()) {
     // Load the double storage.
index 40132cb..aa82614 100644 (file)
@@ -300,13 +300,10 @@ void JSObject::JSObjectVerify() {
         if (r.IsSmi()) ASSERT(value->IsSmi());
         if (r.IsHeapObject()) ASSERT(value->IsHeapObject());
         HeapType* field_type = descriptors->GetFieldType(i);
-        if (field_type->IsClass()) {
-          Map* map = *field_type->AsClass()->Map();
-          CHECK(!map->is_stable() || HeapObject::cast(value)->map() == map);
-        } else if (r.IsNone()) {
+        if (r.IsNone()) {
           CHECK(field_type->Is(HeapType::None()));
-        } else {
-          CHECK(HeapType::Any()->Is(field_type));
+        } else if (!HeapType::Any()->Is(field_type)) {
+          CHECK(!field_type->NowStable() || field_type->NowContains(value));
         }
       }
     }
index 4a3b542..c0c896a 100644 (file)
@@ -63,15 +63,16 @@ namespace internal {
 
 Handle<HeapType> Object::OptimalType(Isolate* isolate,
                                      Representation representation) {
-  if (!FLAG_track_field_types) return HeapType::Any(isolate);
-  if (representation.IsNone()) return HeapType::None(isolate);
-  if (representation.IsHeapObject() && IsHeapObject()) {
-    // We can track only JavaScript objects with stable maps.
-    Handle<Map> map(HeapObject::cast(this)->map(), isolate);
-    if (map->is_stable() &&
-        map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
-        map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
-      return HeapType::Class(map, isolate);
+  if (FLAG_track_field_types) {
+    if (representation.IsNone()) return HeapType::None(isolate);
+    if (representation.IsHeapObject() && IsHeapObject()) {
+      // We can track only JavaScript objects with stable maps.
+      Handle<Map> map(HeapObject::cast(this)->map(), isolate);
+      if (map->is_stable() &&
+          map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
+          map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE) {
+        return HeapType::Class(map, isolate);
+      }
     }
   }
   return HeapType::Any(isolate);
@@ -2526,11 +2527,21 @@ void Map::UpdateDescriptor(int descriptor_number, Descriptor* desc) {
 
 
 // static
-Handle<HeapType> Map::GeneralizeFieldType(Handle<HeapType> old_field_type,
-                                          Handle<HeapType> new_field_type,
+Handle<HeapType> Map::GeneralizeFieldType(Handle<HeapType> type1,
+                                          Handle<HeapType> type2,
                                           Isolate* isolate) {
-  if (new_field_type->NowIs(old_field_type)) return old_field_type;
-  if (old_field_type->NowIs(new_field_type)) return new_field_type;
+  static const int kMaxClassesPerFieldType = 5;
+  if (type1->NowIs(type2)) return type2;
+  if (type2->NowIs(type1)) return type1;
+  if (type1->NowStable() && type2->NowStable()) {
+    Handle<HeapType> type = HeapType::Union(type1, type2, isolate);
+    if (type->NumClasses() <= kMaxClassesPerFieldType) {
+      ASSERT(type->NowStable());
+      ASSERT(type1->NowIs(type));
+      ASSERT(type2->NowIs(type));
+      return type;
+    }
+  }
   return HeapType::Any(isolate);
 }
 
index 831e013..6aaf6f2 100644 (file)
@@ -6252,8 +6252,8 @@ class Map: public HeapObject {
                               int target_inobject,
                               int target_unused);
   static Handle<Map> GeneralizeAllFieldRepresentations(Handle<Map> map);
-  static Handle<HeapType> GeneralizeFieldType(Handle<HeapType> old_field_type,
-                                              Handle<HeapType> new_field_type,
+  static Handle<HeapType> GeneralizeFieldType(Handle<HeapType> type1,
+                                              Handle<HeapType> type2,
                                               Isolate* isolate)
       V8_WARN_UNUSED_RESULT;
   static void GeneralizeFieldType(Handle<Map> map,
index f359362..394f772 100644 (file)
@@ -359,6 +359,17 @@ bool TypeImpl<Config>::NowIs(TypeImpl* that) {
 }
 
 
+// Check if this contains only (currently) stable classes.
+template<class Config>
+bool TypeImpl<Config>::NowStable() {
+  DisallowHeapAllocation no_allocation;
+  for (Iterator<i::Map> it = this->Classes(); !it.Done(); it.Advance()) {
+    if (!it.Current()->is_stable()) return false;
+  }
+  return true;
+}
+
+
 // Check this overlaps that.
 template<class Config>
 bool TypeImpl<Config>::Maybe(TypeImpl* that) {
index 3fb5927..5ca3a81 100644 (file)
@@ -321,6 +321,8 @@ class TypeImpl : public Config::Base {
   inline bool NowContains(i::Object* val);
   bool NowContains(i::Handle<i::Object> val) { return this->NowContains(*val); }
 
+  bool NowStable();
+
   bool IsClass() { return Config::is_class(this); }
   bool IsConstant() { return Config::is_constant(this); }
   bool IsArray() { return Config::is_struct(this, StructuralType::kArrayTag); }
index 0981114..93121a0 100644 (file)
@@ -494,13 +494,21 @@ void StoreStubCompiler::GenerateStoreTransition(MacroAssembler* masm,
   } else if (representation.IsSmi()) {
     __ JumpIfNotSmi(value_reg, miss_label);
   } else if (representation.IsHeapObject()) {
+    __ JumpIfSmi(value_reg, miss_label);
     HeapType* field_type = descriptors->GetFieldType(descriptor);
-    if (field_type->IsClass()) {
-      __ CheckMap(value_reg, field_type->AsClass()->Map(),
-                  miss_label, DO_SMI_CHECK);
-    } else {
-      ASSERT(HeapType::Any()->Is(field_type));
-      __ JumpIfSmi(value_reg, miss_label);
+    HeapType::Iterator<Map> it = field_type->Classes();
+    if (!it.Done()) {
+      Label do_store;
+      while (true) {
+        __ CompareMap(value_reg, it.Current());
+        it.Advance();
+        if (it.Done()) {
+          __ j(not_equal, miss_label);
+          break;
+        }
+        __ j(equal, &do_store, Label::kNear);
+      }
+      __ bind(&do_store);
     }
   } else if (representation.IsDouble()) {
     Label do_store, heap_number;
@@ -645,13 +653,21 @@ void StoreStubCompiler::GenerateStoreField(MacroAssembler* masm,
   if (representation.IsSmi()) {
     __ JumpIfNotSmi(value_reg, miss_label);
   } else if (representation.IsHeapObject()) {
+    __ JumpIfSmi(value_reg, miss_label);
     HeapType* field_type = lookup->GetFieldType();
-    if (field_type->IsClass()) {
-      __ CheckMap(value_reg, field_type->AsClass()->Map(),
-                  miss_label, DO_SMI_CHECK);
-    } else {
-      ASSERT(HeapType::Any()->Is(field_type));
-      __ JumpIfSmi(value_reg, miss_label);
+    HeapType::Iterator<Map> it = field_type->Classes();
+    if (!it.Done()) {
+      Label do_store;
+      while (true) {
+        __ CompareMap(value_reg, it.Current());
+        it.Advance();
+        if (it.Done()) {
+          __ j(not_equal, miss_label);
+          break;
+        }
+        __ j(equal, &do_store, Label::kNear);
+      }
+      __ bind(&do_store);
     }
   } else if (representation.IsDouble()) {
     // Load the double storage.