[VM/nnbd] Class Future may be used for type normalization before it is cached in the object store.

Class Future is resolved on the fly if not already cached.
Note that postponing type normalization until type finalization does not help
and results in the same error.

Fixes issue https://github.com/dart-lang/sdk/issues/42643

Change-Id: Id4dbeba6a246dbc952cce4168a10137a49d3ce70
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/153901
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Régis Crelier <regis@google.com>
This commit is contained in:
Regis Crelier 2020-07-14 00:42:19 +00:00 committed by commit-bot@chromium.org
parent b75df6f268
commit 994c6ba6cd
5 changed files with 107 additions and 62 deletions

View file

@ -5802,6 +5802,8 @@ intptr_t Serializer::WriteVMSnapshot(const Array& symbols) {
static const char* kObjectStoreFieldNames[] = {
#define DECLARE_OBJECT_STORE_FIELD(Type, Name) #Name,
OBJECT_STORE_FIELD_LIST(DECLARE_OBJECT_STORE_FIELD,
DECLARE_OBJECT_STORE_FIELD,
DECLARE_OBJECT_STORE_FIELD,
DECLARE_OBJECT_STORE_FIELD)
#undef DECLARE_OBJECT_STORE_FIELD
};

View file

@ -148,16 +148,9 @@ class CheckFunctionTypesVisitor : public ObjectVisitor {
static InstancePtr GetListInstance(Zone* zone, const Object& obj) {
if (obj.IsInstance()) {
ObjectStore* object_store = Isolate::Current()->object_store();
Type& list_rare_type =
const Type& list_rare_type =
Type::Handle(zone, object_store->non_nullable_list_rare_type());
if (list_rare_type.IsNull()) {
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
const Class& list_class =
Class::Handle(zone, core_lib.LookupClass(Symbols::List()));
ASSERT(!list_class.IsNull());
list_rare_type ^= list_class.RareType();
object_store->set_non_nullable_list_rare_type(list_rare_type);
}
ASSERT(!list_rare_type.IsNull());
const Instance& instance = Instance::Cast(obj);
const Class& obj_class = Class::Handle(zone, obj.clazz());
if (Class::IsSubtypeOf(obj_class, Object::null_type_arguments(),
@ -172,16 +165,9 @@ static InstancePtr GetListInstance(Zone* zone, const Object& obj) {
static InstancePtr GetMapInstance(Zone* zone, const Object& obj) {
if (obj.IsInstance()) {
ObjectStore* object_store = Isolate::Current()->object_store();
Type& map_rare_type =
const Type& map_rare_type =
Type::Handle(zone, object_store->non_nullable_map_rare_type());
if (map_rare_type.IsNull()) {
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
const Class& map_class =
Class::Handle(zone, core_lib.LookupClass(Symbols::Map()));
ASSERT(!map_class.IsNull());
map_rare_type ^= map_class.RareType();
object_store->set_non_nullable_map_rare_type(map_rare_type);
}
ASSERT(!map_rare_type.IsNull());
const Instance& instance = Instance::Cast(obj);
const Class& obj_class = Class::Handle(zone, obj.clazz());
if (Class::IsSubtypeOf(obj_class, Object::null_type_arguments(),
@ -2416,14 +2402,9 @@ DART_EXPORT bool Dart_IsFuture(Dart_Handle handle) {
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
if (obj.IsInstance()) {
ObjectStore* object_store = T->isolate()->object_store();
Type& future_rare_type =
const Type& future_rare_type =
Type::Handle(Z, object_store->non_nullable_future_rare_type());
if (future_rare_type.IsNull()) {
const Class& future_class = Class::Handle(object_store->future_class());
ASSERT(!future_class.IsNull());
future_rare_type ^= future_class.RareType();
object_store->set_non_nullable_future_rare_type(future_rare_type);
}
ASSERT(!future_rare_type.IsNull());
const Class& obj_class = Class::Handle(Z, obj.clazz());
bool is_future = Class::IsSubtypeOf(
obj_class, Object::null_type_arguments(), Nullability::kNonNullable,

View file

@ -18531,7 +18531,9 @@ AbstractTypePtr AbstractType::SetInstantiatedNullability(
AbstractTypePtr AbstractType::NormalizeFutureOrType(Heap::Space space) const {
if (IsFutureOrType()) {
const AbstractType& unwrapped_type = AbstractType::Handle(UnwrapFutureOr());
Zone* zone = Thread::Current()->zone();
const AbstractType& unwrapped_type =
AbstractType::Handle(zone, UnwrapFutureOr());
const classid_t cid = unwrapped_type.type_class_id();
if (cid == kDynamicCid || cid == kVoidCid) {
return unwrapped_type.raw();
@ -18549,38 +18551,14 @@ AbstractTypePtr AbstractType::NormalizeFutureOrType(Heap::Space space) const {
}
if (cid == kNeverCid && unwrapped_type.IsNonNullable()) {
ObjectStore* object_store = Isolate::Current()->object_store();
if (object_store->non_nullable_future_never_type() == Type::null()) {
const Class& cls = Class::Handle(object_store->future_class());
ASSERT(!cls.IsNull());
const TypeArguments& type_args =
TypeArguments::Handle(TypeArguments::New(1));
type_args.SetTypeAt(0, Type::Handle(object_store->never_type()));
Type& type =
Type::Handle(Type::New(cls, type_args, TokenPosition::kNoSource,
Nullability::kNonNullable));
type.SetIsFinalized();
type ^= type.Canonicalize();
object_store->set_non_nullable_future_never_type(type);
}
const Type& future_never_type =
Type::Handle(object_store->non_nullable_future_never_type());
Type::Handle(zone, object_store->non_nullable_future_never_type());
ASSERT(!future_never_type.IsNull());
return future_never_type.ToNullability(nullability(), space);
}
if (cid == kNullCid) {
ObjectStore* object_store = Isolate::Current()->object_store();
if (object_store->nullable_future_null_type() == Type::null()) {
const Class& cls = Class::Handle(object_store->future_class());
ASSERT(!cls.IsNull());
const TypeArguments& type_args =
TypeArguments::Handle(TypeArguments::New(1));
Type& type = Type::Handle(object_store->null_type());
type_args.SetTypeAt(0, type);
type = Type::New(cls, type_args, TokenPosition::kNoSource,
Nullability::kNullable);
type.SetIsFinalized();
type ^= type.Canonicalize();
object_store->set_nullable_future_null_type(type);
}
ASSERT(object_store->nullable_future_null_type() != Type::null());
return object_store->nullable_future_null_type();
}
if (IsNullable() && unwrapped_type.IsNullable()) {

View file

@ -103,7 +103,7 @@ ErrorPtr IsolateObjectStore::PreallocateObjects() {
ObjectStore::ObjectStore() {
#define INIT_FIELD(Type, name) name##_ = Type::null();
OBJECT_STORE_FIELD_LIST(INIT_FIELD, INIT_FIELD)
OBJECT_STORE_FIELD_LIST(INIT_FIELD, INIT_FIELD, INIT_FIELD, INIT_FIELD)
#undef INIT_FIELD
for (ObjectPtr* current = from(); current <= to(); current++) {
@ -136,7 +136,8 @@ void ObjectStore::PrintToJSONObject(JSONObject* jsobj) {
#define PRINT_OBJECT_STORE_FIELD(type, name) \
value = name##_; \
fields.AddProperty(#name "_", value);
OBJECT_STORE_FIELD_LIST(PRINT_OBJECT_STORE_FIELD, PRINT_OBJECT_STORE_FIELD);
OBJECT_STORE_FIELD_LIST(PRINT_OBJECT_STORE_FIELD, PRINT_OBJECT_STORE_FIELD,
PRINT_OBJECT_STORE_FIELD, PRINT_OBJECT_STORE_FIELD);
#undef PRINT_OBJECT_STORE_FIELD
}
}
@ -333,4 +334,60 @@ void ObjectStore::InitKnownObjects() {
#endif
}
void ObjectStore::LazyInitCoreTypes() {
if (non_nullable_list_rare_type_ == Type::null()) {
ASSERT(non_nullable_map_rare_type_ == Type::null());
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
Class& cls = Class::Handle(zone, core_lib.LookupClass(Symbols::List()));
ASSERT(!cls.IsNull());
Type& type = Type::Handle(zone);
type ^= cls.RareType();
set_non_nullable_list_rare_type(type);
cls = core_lib.LookupClass(Symbols::Map());
ASSERT(!cls.IsNull());
type ^= cls.RareType();
set_non_nullable_map_rare_type(type);
}
}
void ObjectStore::LazyInitFutureTypes() {
if (non_nullable_future_rare_type_ == Type::null()) {
ASSERT(non_nullable_future_never_type_ == Type::null() &&
nullable_future_null_type_ == Type::null());
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
Class& cls = Class::Handle(zone, future_class());
if (cls.IsNull()) {
const Library& async_lib = Library::Handle(zone, async_library());
ASSERT(!async_lib.IsNull());
cls = async_lib.LookupClass(Symbols::Future());
ASSERT(!cls.IsNull());
}
TypeArguments& type_args = TypeArguments::Handle(zone);
Type& type = Type::Handle(zone);
type = never_type();
ASSERT(!type.IsNull());
type_args = TypeArguments::New(1);
type_args.SetTypeAt(0, type);
type = Type::New(cls, type_args, TokenPosition::kNoSource,
Nullability::kNonNullable);
type.SetIsFinalized();
type ^= type.Canonicalize();
set_non_nullable_future_never_type(type);
type = null_type();
ASSERT(!type.IsNull());
type_args = TypeArguments::New(1);
type_args.SetTypeAt(0, type);
type = Type::New(cls, type_args, TokenPosition::kNoSource,
Nullability::kNullable);
type.SetIsFinalized();
type ^= type.Canonicalize();
set_nullable_future_null_type(type);
type ^= cls.RareType();
set_non_nullable_future_rare_type(type);
}
}
} // namespace dart

View file

@ -37,7 +37,9 @@ class ObjectPointerVisitor;
//
// R_ - needs getter only
// RW - needs getter and setter
#define OBJECT_STORE_FIELD_LIST(R_, RW) \
// CW - needs lazy Core init getter and setter
// FW - needs lazy Future init getter and setter
#define OBJECT_STORE_FIELD_LIST(R_, RW, CW, FW) \
RW(Class, object_class) \
RW(Type, object_type) \
RW(Type, legacy_object_type) \
@ -80,9 +82,11 @@ class ObjectPointerVisitor;
RW(Type, string_type) \
RW(Type, legacy_string_type) \
RW(Type, non_nullable_string_type) \
RW(Type, non_nullable_list_rare_type) /* maybe be null, lazily built */ \
RW(Type, non_nullable_map_rare_type) /* maybe be null, lazily built */ \
RW(Type, non_nullable_future_rare_type) /* maybe be null, lazily built */ \
CW(Type, non_nullable_list_rare_type) /* maybe be null, lazily built */ \
CW(Type, non_nullable_map_rare_type) /* maybe be null, lazily built */ \
FW(Type, non_nullable_future_rare_type) /* maybe be null, lazily built */ \
FW(Type, non_nullable_future_never_type) /* maybe be null, lazily built */ \
FW(Type, nullable_future_null_type) /* maybe be null, lazily built */ \
RW(TypeArguments, type_argument_int) \
RW(TypeArguments, type_argument_legacy_int) \
RW(TypeArguments, type_argument_non_nullable_int) \
@ -103,8 +107,6 @@ class ObjectPointerVisitor;
RW(Field, pragma_name) \
RW(Field, pragma_options) \
RW(Class, future_class) \
RW(Type, non_nullable_future_never_type) /* maybe be null, lazily built */ \
RW(Type, nullable_future_null_type) /* maybe be null, lazily built */ \
RW(Class, completer_class) \
RW(Class, symbol_class) \
RW(Class, one_byte_string_class) \
@ -354,9 +356,29 @@ class ObjectStore {
#define DECLARE_GETTER_AND_SETTER(Type, name) \
DECLARE_GETTER(Type, name) \
void set_##name(const Type& value) { name##_ = value.raw(); }
OBJECT_STORE_FIELD_LIST(DECLARE_GETTER, DECLARE_GETTER_AND_SETTER)
#define DECLARE_LAZY_INIT_GETTER(Type, name, init) \
Type##Ptr name() { \
if (name##_ == Type::null()) { \
init(); \
} \
return name##_; \
} \
static intptr_t name##_offset() { return OFFSET_OF(ObjectStore, name##_); }
#define DECLARE_LAZY_INIT_CORE_GETTER_AND_SETTER(Type, name) \
DECLARE_LAZY_INIT_GETTER(Type, name, LazyInitCoreTypes) \
void set_##name(const Type& value) { name##_ = value.raw(); }
#define DECLARE_LAZY_INIT_FUTURE_GETTER_AND_SETTER(Type, name) \
DECLARE_LAZY_INIT_GETTER(Type, name, LazyInitFutureTypes) \
void set_##name(const Type& value) { name##_ = value.raw(); }
OBJECT_STORE_FIELD_LIST(DECLARE_GETTER,
DECLARE_GETTER_AND_SETTER,
DECLARE_LAZY_INIT_CORE_GETTER_AND_SETTER,
DECLARE_LAZY_INIT_FUTURE_GETTER_AND_SETTER)
#undef DECLARE_GETTER
#undef DECLARE_GETTER_AND_SETTER
#undef DECLARE_LAZY_INIT_GETTER
#undef DECLARE_LAZY_INIT_CORE_GETTER_AND_SETTER
#undef DECLARE_LAZY_INIT_FUTURE_GETTER_AND_SETTER
LibraryPtr bootstrap_library(BootstrapLibraryId index) {
switch (index) {
@ -404,12 +426,17 @@ class ObjectStore {
#endif
private:
void LazyInitCoreTypes();
void LazyInitFutureTypes();
// Finds a core library private method in Object.
FunctionPtr PrivateObjectLookup(const String& name);
ObjectPtr* from() { return reinterpret_cast<ObjectPtr*>(&object_class_); }
#define DECLARE_OBJECT_STORE_FIELD(type, name) type##Ptr name##_;
OBJECT_STORE_FIELD_LIST(DECLARE_OBJECT_STORE_FIELD,
DECLARE_OBJECT_STORE_FIELD,
DECLARE_OBJECT_STORE_FIELD,
DECLARE_OBJECT_STORE_FIELD)
#undef DECLARE_OBJECT_STORE_FIELD
ObjectPtr* to() {