}
+static Handle<Object> WrapType(Handle<HeapType> type) {
+ if (type->IsClass()) return Map::WeakCellForMap(type->AsClass()->Map());
+ return type;
+}
+
+
MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
Handle<Name> name,
Handle<HeapType> type,
type = HeapType::Any(isolate);
}
- DataDescriptor new_field_desc(name, index, type, attributes, representation);
+ Handle<Object> wrapped_type(WrapType(type));
+
+ DataDescriptor new_field_desc(name, index, wrapped_type, attributes,
+ representation);
Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
int unused_property_fields = new_map->unused_property_fields() - 1;
if (unused_property_fields < 0) {
void Map::UpdateFieldType(int descriptor, Handle<Name> name,
Representation new_representation,
- Handle<HeapType> new_type) {
+ Handle<Object> new_wrapped_type) {
+ DCHECK(new_wrapped_type->IsSmi() || new_wrapped_type->IsWeakCell());
DisallowHeapAllocation no_allocation;
PropertyDetails details = instance_descriptors()->GetDetails(descriptor);
if (details.type() != DATA) return;
if (HasTransitionArray()) {
TransitionArray* transitions = this->transitions();
for (int i = 0; i < transitions->number_of_transitions(); ++i) {
- transitions->GetTarget(i)
- ->UpdateFieldType(descriptor, name, new_representation, new_type);
+ transitions->GetTarget(i)->UpdateFieldType(
+ descriptor, name, new_representation, new_wrapped_type);
}
}
// It is allowed to change representation here only from None to something.
details.representation().IsNone());
// Skip if already updated the shared descriptor.
- if (instance_descriptors()->GetFieldType(descriptor) == *new_type) return;
+ if (instance_descriptors()->GetValue(descriptor) == *new_wrapped_type) return;
DataDescriptor d(name, instance_descriptors()->GetFieldIndex(descriptor),
- new_type, details.attributes(), new_representation);
+ new_wrapped_type, details.attributes(), new_representation);
instance_descriptors()->Replace(descriptor, &d);
}
PropertyDetails details = descriptors->GetDetails(modify_index);
Handle<Name> name(descriptors->GetKey(modify_index));
+
+ Handle<Object> wrapped_type(WrapType(new_field_type));
field_owner->UpdateFieldType(modify_index, name, new_representation,
- new_field_type);
+ wrapped_type);
field_owner->dependent_code()->DeoptimizeDependentCodeGroup(
isolate, DependentCode::kFieldTypeGroup);
next_field_type =
GeneralizeFieldType(target_field_type, old_field_type, isolate);
}
- DataDescriptor d(target_key, current_offset, next_field_type,
+ Handle<Object> wrapped_type(WrapType(next_field_type));
+ DataDescriptor d(target_key, current_offset, wrapped_type,
next_attributes, next_representation);
current_offset += d.GetDetails().field_width_in_words();
new_descriptors->Set(i, &d);
next_field_type = old_field_type;
}
- DataDescriptor d(old_key, current_offset, next_field_type,
- next_attributes, next_representation);
+ Handle<Object> wrapped_type(WrapType(next_field_type));
+
+ DataDescriptor d(old_key, current_offset, wrapped_type, next_attributes,
+ next_representation);
current_offset += d.GetDetails().field_width_in_words();
new_descriptors->Set(i, &d);
} else {
if (!old_details.representation().fits_into(new_details.representation())) {
return MaybeHandle<Map>();
}
- Object* new_value = new_descriptors->GetValue(i);
- Object* old_value = old_descriptors->GetValue(i);
switch (new_details.type()) {
case DATA: {
- PropertyType old_type = old_details.type();
- if (old_type == DATA) {
- if (!HeapType::cast(old_value)->NowIs(HeapType::cast(new_value))) {
+ HeapType* new_type = new_descriptors->GetFieldType(i);
+ PropertyType old_property_type = old_details.type();
+ if (old_property_type == DATA) {
+ HeapType* old_type = old_descriptors->GetFieldType(i);
+ if (!old_type->NowIs(new_type)) {
return MaybeHandle<Map>();
}
} else {
- DCHECK(old_type == DATA_CONSTANT);
- if (!HeapType::cast(new_value)->NowContains(old_value)) {
+ DCHECK(old_property_type == DATA_CONSTANT);
+ Object* old_value = old_descriptors->GetValue(i);
+ if (!new_type->NowContains(old_value)) {
return MaybeHandle<Map>();
}
}
break;
}
- case ACCESSOR:
- DCHECK(HeapType::Any()->Is(HeapType::cast(new_value)));
+ case ACCESSOR: {
+#ifdef DEBUG
+ HeapType* new_type = new_descriptors->GetFieldType(i);
+ DCHECK(HeapType::Any()->Is(new_type));
+#endif
break;
+ }
case DATA_CONSTANT:
- case ACCESSOR_CONSTANT:
+ case ACCESSOR_CONSTANT: {
+ Object* old_value = old_descriptors->GetValue(i);
+ Object* new_value = new_descriptors->GetValue(i);
if (old_details.location() == kField || old_value != new_value) {
return MaybeHandle<Map>();
}
break;
+ }
}
}
if (new_map->NumberOfOwnDescriptors() != old_nof) return MaybeHandle<Map>();
PropertyAttributes attributes, Representation representation)
: Descriptor(key, HeapType::Any(key->GetIsolate()), attributes, DATA,
representation, field_index) {}
- DataDescriptor(Handle<Name> key, int field_index, Handle<HeapType> field_type,
+ // The field type is either a simple type or a map wrapped in a weak cell.
+ DataDescriptor(Handle<Name> key, int field_index,
+ Handle<Object> wrapped_field_type,
PropertyAttributes attributes, Representation representation)
- : Descriptor(key, field_type, attributes, DATA, representation,
- field_index) {}
+ : Descriptor(key, wrapped_field_type, attributes, DATA, representation,
+ field_index) {
+ DCHECK(wrapped_field_type->IsSmi() || wrapped_field_type->IsWeakCell());
+ }
};
}
+TEST(Regress3877) {
+ CcTest::InitializeVM();
+ Isolate* isolate = CcTest::i_isolate();
+ Heap* heap = isolate->heap();
+ Factory* factory = isolate->factory();
+ HandleScope scope(isolate);
+ CompileRun("function cls() { this.x = 10; }");
+ Handle<WeakCell> weak_prototype;
+ {
+ HandleScope inner_scope(isolate);
+ v8::Local<v8::Value> result = CompileRun("cls.prototype");
+ Handle<JSObject> proto =
+ v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
+ weak_prototype = inner_scope.CloseAndEscape(factory->NewWeakCell(proto));
+ }
+ CHECK(!weak_prototype->cleared());
+ CompileRun(
+ "var a = { };"
+ "a.x = new cls();"
+ "cls.prototype = null;");
+ for (int i = 0; i < 4; i++) {
+ heap->CollectAllGarbage(Heap::kNoGCFlags);
+ }
+ // The map of a.x keeps prototype alive
+ CHECK(!weak_prototype->cleared());
+ // Change the map of a.x and make the previous map garbage collectable.
+ CompileRun("a.x.__proto__ = {};");
+ for (int i = 0; i < 4; i++) {
+ heap->CollectAllGarbage(Heap::kNoGCFlags);
+ }
+ CHECK(weak_prototype->cleared());
+}
+
+
#ifdef DEBUG
TEST(PathTracer) {
CcTest::InitializeVM();