From 779e87b87a286f3fdd495716ff5441122e8d9456 Mon Sep 17 00:00:00 2001 From: "bmeurer@chromium.org" Date: Thu, 17 Apr 2014 08:22:22 +0000 Subject: [PATCH] Track up to 5 stable maps as field type. 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 | 42 ++++++++++++++++++++++++++++++------------ src/arm64/stub-cache-arm64.cc | 42 ++++++++++++++++++++++++++++++------------ src/ia32/stub-cache-ia32.cc | 40 ++++++++++++++++++++++++++++------------ src/objects-debug.cc | 9 +++------ src/objects.cc | 37 ++++++++++++++++++++++++------------- src/objects.h | 4 ++-- src/types.cc | 11 +++++++++++ src/types.h | 2 ++ src/x64/stub-cache-x64.cc | 40 ++++++++++++++++++++++++++++------------ 9 files changed, 158 insertions(+), 69 deletions(-) diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 6875dcf..3d07d56 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -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 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 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. diff --git a/src/arm64/stub-cache-arm64.cc b/src/arm64/stub-cache-arm64.cc index bf12840..b46d813 100644 --- a/src/arm64/stub-cache-arm64.cc +++ b/src/arm64/stub-cache-arm64.cc @@ -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 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 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); diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 9c82692..b3bc71c 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -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 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 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. diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 40132cb..aa82614 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -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)); } } } diff --git a/src/objects.cc b/src/objects.cc index 4a3b542..c0c896a 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -63,15 +63,16 @@ namespace internal { Handle 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(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(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 Map::GeneralizeFieldType(Handle old_field_type, - Handle new_field_type, +Handle Map::GeneralizeFieldType(Handle type1, + Handle 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 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); } diff --git a/src/objects.h b/src/objects.h index 831e013..6aaf6f2 100644 --- a/src/objects.h +++ b/src/objects.h @@ -6252,8 +6252,8 @@ class Map: public HeapObject { int target_inobject, int target_unused); static Handle GeneralizeAllFieldRepresentations(Handle map); - static Handle GeneralizeFieldType(Handle old_field_type, - Handle new_field_type, + static Handle GeneralizeFieldType(Handle type1, + Handle type2, Isolate* isolate) V8_WARN_UNUSED_RESULT; static void GeneralizeFieldType(Handle map, diff --git a/src/types.cc b/src/types.cc index f359362..394f772 100644 --- a/src/types.cc +++ b/src/types.cc @@ -359,6 +359,17 @@ bool TypeImpl::NowIs(TypeImpl* that) { } +// Check if this contains only (currently) stable classes. +template +bool TypeImpl::NowStable() { + DisallowHeapAllocation no_allocation; + for (Iterator it = this->Classes(); !it.Done(); it.Advance()) { + if (!it.Current()->is_stable()) return false; + } + return true; +} + + // Check this overlaps that. template bool TypeImpl::Maybe(TypeImpl* that) { diff --git a/src/types.h b/src/types.h index 3fb5927..5ca3a81 100644 --- a/src/types.h +++ b/src/types.h @@ -321,6 +321,8 @@ class TypeImpl : public Config::Base { inline bool NowContains(i::Object* val); bool NowContains(i::Handle 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); } diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 0981114..93121a0 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -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 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 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. -- 2.7.4