Version 2.12.0-204.0.dev

Merge commit 'b3bca1821c8fa1dd84012443843bb900aeba61a0' into 'dev'
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index f0ccd17..967a4ef 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -248,8 +248,7 @@
                                arguments->NativeArgAt(1));
 
   ASSERT(type_arg.IsInstantiated() && type_arg.IsFunctionType());
-  const Function& native_signature =
-      Function::Handle(zone, Type::Cast(type_arg).signature());
+  const FunctionType& native_signature = FunctionType::Cast(type_arg);
   Function& func = Function::Handle(zone, closure.function());
 
   // The FE verifies that the target of a 'fromFunction' is a static method, so
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 4575352..2c0d827 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -94,15 +94,16 @@
 }
 
 static InstancePtr CreateParameterMirrorList(const Function& func,
+                                             const FunctionType& signature,
                                              const Instance& owner_mirror) {
   HANDLESCOPE(Thread::Current());
-  const intptr_t implicit_param_count = func.NumImplicitParameters();
+  const intptr_t implicit_param_count = signature.num_implicit_parameters();
   const intptr_t non_implicit_param_count =
-      func.NumParameters() - implicit_param_count;
+      signature.NumParameters() - implicit_param_count;
   const intptr_t index_of_first_optional_param =
-      non_implicit_param_count - func.NumOptionalParameters();
+      non_implicit_param_count - signature.NumOptionalParameters();
   const intptr_t index_of_first_named_param =
-      non_implicit_param_count - func.NumOptionalNamedParameters();
+      non_implicit_param_count - signature.NumOptionalNamedParameters();
   const Array& results = Array::Handle(Array::New(non_implicit_param_count));
   const Array& args = Array::Handle(Array::New(9));
 
@@ -116,23 +117,18 @@
   // We force compilation of constructors to ensure the types of initializing
   // formals have been corrected. We do not force the compilation of all types
   // of functions because some have no body, e.g. signature functions.
-  EnsureConstructorsAreCompiled(func);
+  if (!func.IsNull()) {
+    EnsureConstructorsAreCompiled(func);
+  }
 
   bool has_extra_parameter_info = true;
   if (non_implicit_param_count == 0) {
     has_extra_parameter_info = false;
   }
-  if (func.IsImplicitConstructor()) {
+  if (func.IsNull() || func.IsImplicitConstructor()) {
     // This covers the default constructor and forwarding constructors.
     has_extra_parameter_info = false;
   }
-  if (func.IsSignatureFunction() &&
-      (func.token_pos() == TokenPosition::kNoSource)) {
-    // Signature functions (except those describing typedefs) get canonicalized,
-    // hence do not have a token position, and therefore cannot be reparsed.
-    has_extra_parameter_info = false;
-  }
-
   Array& param_descriptor = Array::Handle();
   if (has_extra_parameter_info) {
     // Reparse the function for the following information:
@@ -149,7 +145,7 @@
            (Parser::kParameterEntrySize * non_implicit_param_count));
   }
 
-  args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
+  args.SetAt(0, MirrorReference::Handle(MirrorReference::New(signature)));
   args.SetAt(2, owner_mirror);
 
   if (!has_extra_parameter_info) {
@@ -160,7 +156,11 @@
 
   for (intptr_t i = 0; i < non_implicit_param_count; i++) {
     pos = Smi::New(i);
-    name = func.ParameterNameAt(implicit_param_count + i);
+    if (!func.IsNull()) {
+      name = func.ParameterNameAt(implicit_param_count + i);
+    } else {
+      name = signature.ParameterNameAt(implicit_param_count + i);
+    }
     if (has_extra_parameter_info) {
       is_final ^= param_descriptor.At(i * Parser::kParameterEntrySize +
                                       Parser::kParameterIsFinalOffset);
@@ -217,27 +217,14 @@
   return result.raw();
 }
 
-static InstancePtr CreateTypedefMirror(const Class& cls,
-                                       const AbstractType& type,
-                                       const Bool& is_declaration,
-                                       const Instance& owner_mirror) {
-  const Array& args = Array::Handle(Array::New(6));
-  args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
-  args.SetAt(1, type);
-  args.SetAt(2, String::Handle(cls.Name()));
-  args.SetAt(3, Bool::Get(cls.IsGeneric()));
-  args.SetAt(4, cls.IsGeneric() ? is_declaration : Bool::False());
-  args.SetAt(5, owner_mirror);
-  return CreateMirror(Symbols::_TypedefMirror(), args);
-}
-
 static InstancePtr CreateFunctionTypeMirror(const AbstractType& type) {
   ASSERT(type.IsFunctionType());
-  const Class& cls = Class::Handle(Type::Cast(type).type_class());
-  const Function& func = Function::Handle(Type::Cast(type).signature());
+  const Class& closure_class =
+      Class::Handle(IsolateGroup::Current()->object_store()->closure_class());
+  const FunctionType& sig = FunctionType::Cast(type);
   const Array& args = Array::Handle(Array::New(3));
-  args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
-  args.SetAt(1, MirrorReference::Handle(MirrorReference::New(func)));
+  args.SetAt(0, MirrorReference::Handle(MirrorReference::New(closure_class)));
+  args.SetAt(1, MirrorReference::Handle(MirrorReference::New(sig)));
   args.SetAt(2, type);
   return CreateMirror(Symbols::_FunctionTypeMirror(), args);
 }
@@ -318,11 +305,7 @@
   ASSERT(!cls.IsNeverClass());
   ASSERT(!type.IsNull());
   ASSERT(type.IsFinalized());
-
-  if (cls.IsTypedefClass()) {
-    return CreateTypedefMirror(cls, type, is_declaration, owner_mirror);
-  }
-
+  ASSERT(type.IsCanonical());
   const Array& args = Array::Handle(Array::New(9));
   args.SetAt(0, MirrorReference::Handle(MirrorReference::New(cls)));
   args.SetAt(1, type);
@@ -534,16 +517,10 @@
     return CreateTypeMirror(ref_type);
   }
   ASSERT(type.IsFinalized());
-  ASSERT(type.IsCanonical() || type.IsTypeParameter());
+  ASSERT(type.IsCanonical());
 
   if (type.IsFunctionType()) {
-    const Class& scope_class = Class::Handle(Type::Cast(type).type_class());
-    if (scope_class.IsTypedefClass()) {
-      return CreateTypedefMirror(scope_class, type, Bool::False(),
-                                 Object::null_instance());
-    } else {
-      return CreateFunctionTypeMirror(type);
-    }
+    return CreateFunctionTypeMirror(type);
   }
   if (type.HasTypeClass()) {
     const Class& cls = Class::Handle(type.type_class());
@@ -564,17 +541,19 @@
     // TODO(regis): Until mirrors reflect nullability, force kLegacy, except for
     // Null type, which should remain nullable.
     if (!type.IsNullType()) {
-      const Type& legacy_type = Type::Handle(
+      Type& legacy_type = Type::Handle(
           Type::Cast(type).ToNullability(Nullability::kLegacy, Heap::kOld));
+      legacy_type ^= legacy_type.Canonicalize(Thread::Current(), nullptr);
       return CreateClassMirror(cls, legacy_type, Bool::False(),
                                Object::null_instance());
     }
     return CreateClassMirror(cls, type, Bool::False(), Object::null_instance());
   } else if (type.IsTypeParameter()) {
     // TODO(regis): Until mirrors reflect nullability, force kLegacy.
-    const TypeParameter& legacy_type =
+    TypeParameter& legacy_type =
         TypeParameter::Handle(TypeParameter::Cast(type).ToNullability(
             Nullability::kLegacy, Heap::kOld));
+    legacy_type ^= legacy_type.Canonicalize(Thread::Current(), nullptr);
     return CreateTypeVariableMirror(legacy_type, Object::null_instance());
   }
   UNREACHABLE();
@@ -631,13 +610,13 @@
   // Generic function type parameters are not reified, but mapped to dynamic,
   // i.e. all function type parameters are free with a null vector.
   ASSERT(type.IsFinalized());
-  ASSERT(type.IsCanonical() || type.IsTypeParameter());
+  ASSERT(type.IsCanonical());
 
   if (type.IsInstantiated()) {
     return type.Canonicalize(Thread::Current(), nullptr);
   }
   TypeArguments& instantiator_type_args = TypeArguments::Handle();
-  if (!instantiator.IsNull()) {
+  if (!instantiator.IsNull() && instantiator.IsType()) {
     ASSERT(instantiator.IsFinalized());
     instantiator_type_args = instantiator.arguments();
   }
@@ -763,11 +742,12 @@
 DEFINE_NATIVE_ENTRY(Mirrors_makeLocalClassMirror, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   ASSERT(type.IsFinalized());
-  ASSERT(type.HasTypeClass());
-  const Class& cls = Class::Handle(type.type_class());
+  const Class& cls = Class::Handle(
+      type.IsFunctionType()
+          ? IsolateGroup::Current()->object_store()->closure_class()
+          : type.type_class());
   ASSERT(!cls.IsNull());
-  if (cls.IsDynamicClass() || cls.IsVoidClass() || cls.IsNeverClass() ||
-      cls.IsTypedefClass()) {
+  if (cls.IsDynamicClass() || cls.IsVoidClass() || cls.IsNeverClass()) {
     Exceptions::ThrowArgumentError(type);
     UNREACHABLE();
   }
@@ -785,8 +765,10 @@
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Array, args, arguments->NativeArgAt(1));
 
-  ASSERT(type.HasTypeClass());
-  const Class& clz = Class::Handle(type.type_class());
+  const Class& clz = Class::Handle(
+      type.IsFunctionType()
+          ? IsolateGroup::Current()->object_store()->closure_class()
+          : type.type_class());
   if (!clz.IsGeneric()) {
     const Array& error_args = Array::Handle(Array::New(3));
     error_args.SetAt(0, type);
@@ -826,8 +808,7 @@
     type_args_obj.SetTypeAt(i, type_arg);
   }
 
-  Type& instantiated_type =
-      Type::Handle(Type::New(clz, type_args_obj, TokenPosition::kNoSource));
+  Type& instantiated_type = Type::Handle(Type::New(clz, type_args_obj));
   instantiated_type ^= ClassFinalizer::FinalizeType(instantiated_type);
   return instantiated_type.raw();
 }
@@ -863,7 +844,7 @@
   if (decl.IsClass()) {
     klass ^= decl.raw();
     library = klass.library();
-  } else if (decl.IsFunction() && !Function::Cast(decl).IsSignatureFunction()) {
+  } else if (decl.IsFunction()) {
     klass = Function::Cast(decl).origin();
     library = klass.library();
   } else if (decl.IsField()) {
@@ -872,12 +853,8 @@
   } else if (decl.IsLibrary()) {
     library ^= decl.raw();
   } else if (decl.IsTypeParameter()) {
-    if (TypeParameter::Cast(decl).IsFunctionTypeParameter()) {
-      // TODO(regis): Fully support generic functions.
-      return Object::empty_array().raw();
-    }
-    klass = TypeParameter::Cast(decl).parameterized_class();
-    library = klass.library();
+    // There is no reference from a canonical type parameter to its declaration.
+    return Object::empty_array().raw();
   } else {
     return Object::empty_array().raw();
   }
@@ -892,26 +869,29 @@
 DEFINE_NATIVE_ENTRY(FunctionTypeMirror_call_method, 0, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner_mirror,
                                arguments->NativeArgAt(0));
-  GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
-  // TODO(rmacnak): Return get:call() method on class _Closure instead?
-  // This now returns the result of invoking that call getter.
-  const Function& func = Function::Handle(ref.GetFunctionReferent());
-  ASSERT(!func.IsNull());
-  return CreateMethodMirror(func, owner_mirror, AbstractType::Handle());
+  // Return get:call() method on class _Closure.
+  const auto& getter_name = Symbols::GetCall();
+  const Class& closure_class =
+      Class::Handle(IsolateGroup::Current()->object_store()->closure_class());
+  const Function& get_call = Function::Handle(
+      Resolver::ResolveDynamicAnyArgs(zone, closure_class, getter_name,
+                                      /*allow_add=*/false));
+  ASSERT(!get_call.IsNull());
+  return CreateMethodMirror(get_call, owner_mirror, AbstractType::Handle());
 }
 
 DEFINE_NATIVE_ENTRY(FunctionTypeMirror_parameters, 0, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
-  const Function& func = Function::Handle(ref.GetFunctionReferent());
-  return CreateParameterMirrorList(func, owner);
+  const FunctionType& sig = FunctionType::Handle(ref.GetFunctionTypeReferent());
+  return CreateParameterMirrorList(Object::null_function(), sig, owner);
 }
 
 DEFINE_NATIVE_ENTRY(FunctionTypeMirror_return_type, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
-  const Function& func = Function::Handle(ref.GetFunctionReferent());
-  ASSERT(!func.IsNull());
-  AbstractType& type = AbstractType::Handle(func.result_type());
+  const FunctionType& sig = FunctionType::Handle(ref.GetFunctionTypeReferent());
+  ASSERT(!sig.IsNull());
+  AbstractType& type = AbstractType::Handle(sig.result_type());
   // Signatures of function types are instantiated, but not canonical.
   return type.Canonicalize(thread, nullptr);
 }
@@ -927,7 +907,10 @@
 DEFINE_NATIVE_ENTRY(ClassMirror_supertype, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   ASSERT(type.IsFinalized());
-  const Class& cls = Class::Handle(type.type_class());
+  const Class& cls = Class::Handle(
+      type.IsFunctionType()
+          ? IsolateGroup::Current()->object_store()->closure_class()
+          : type.type_class());
   const AbstractType& super_type = AbstractType::Handle(cls.super_type());
   ASSERT(super_type.IsNull() || super_type.IsFinalized());
   return super_type.raw();
@@ -936,7 +919,10 @@
 DEFINE_NATIVE_ENTRY(ClassMirror_supertype_instantiated, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   ASSERT(type.IsFinalized());
-  const Class& cls = Class::Handle(type.type_class());
+  const Class& cls = Class::Handle(
+      type.IsFunctionType()
+          ? IsolateGroup::Current()->object_store()->closure_class()
+          : type.type_class());
   const AbstractType& super_type = AbstractType::Handle(cls.super_type());
   return InstantiateType(super_type, type);
 }
@@ -944,7 +930,10 @@
 DEFINE_NATIVE_ENTRY(ClassMirror_interfaces, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   ASSERT(type.IsFinalized());
-  const Class& cls = Class::Handle(type.type_class());
+  const Class& cls = Class::Handle(
+      type.IsFunctionType()
+          ? IsolateGroup::Current()->object_store()->closure_class()
+          : type.type_class());
   const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
@@ -956,7 +945,10 @@
 DEFINE_NATIVE_ENTRY(ClassMirror_interfaces_instantiated, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   ASSERT(type.IsFinalized());
-  const Class& cls = Class::Handle(type.type_class());
+  const Class& cls = Class::Handle(
+      type.IsFunctionType()
+          ? IsolateGroup::Current()->object_store()->closure_class()
+          : type.type_class());
   const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
   if (!error.IsNull()) {
     Exceptions::PropagateError(error);
@@ -978,7 +970,10 @@
 DEFINE_NATIVE_ENTRY(ClassMirror_mixin, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
   ASSERT(type.IsFinalized());
-  const Class& cls = Class::Handle(type.type_class());
+  const Class& cls = Class::Handle(
+      type.IsFunctionType()
+          ? IsolateGroup::Current()->object_store()->closure_class()
+          : type.type_class());
   AbstractType& mixin_type = AbstractType::Handle();
   if (cls.is_transformed_mixin_application()) {
     const Array& interfaces = Array::Handle(cls.interfaces());
@@ -993,7 +988,10 @@
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, instantiator,
                                arguments->NativeArgAt(1));
   ASSERT(type.IsFinalized());
-  const Class& cls = Class::Handle(type.type_class());
+  const Class& cls = Class::Handle(
+      type.IsFunctionType()
+          ? IsolateGroup::Current()->object_store()->closure_class()
+          : type.type_class());
   AbstractType& mixin_type = AbstractType::Handle();
   if (cls.is_transformed_mixin_application()) {
     const Array& interfaces = Array::Handle(cls.interfaces());
@@ -1157,7 +1155,10 @@
 DEFINE_NATIVE_ENTRY(ClassMirror_type_arguments, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(AbstractType, type, arguments->NativeArgAt(0));
 
-  const Class& cls = Class::Handle(type.type_class());
+  const Class& cls = Class::Handle(
+      type.IsFunctionType()
+          ? IsolateGroup::Current()->object_store()->closure_class()
+          : type.type_class());
   const intptr_t num_params = cls.NumTypeParameters();
 
   if (num_params == 0) {
@@ -1192,18 +1193,9 @@
 }
 
 DEFINE_NATIVE_ENTRY(TypeVariableMirror_owner, 0, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(TypeParameter, param, arguments->NativeArgAt(0));
-  Class& owner = Class::Handle(param.parameterized_class());
-  AbstractType& type = AbstractType::Handle();
-  if (owner.IsNull()) {
-    // TODO(regis): Fully support generic functions. For now, reify function
-    // type parameters to dynamic and map their function owner to Null class.
-    ASSERT(param.IsFunctionTypeParameter());
-    type = Type::NullType();
-    owner = type.type_class();
-  } else {
-    type = owner.DeclarationType();
-  }
+  // Type parameters do not have a reference to their owner anymore.
+  const AbstractType& type = AbstractType::Handle(Type::NullType());
+  Class& owner = Class::Handle(type.type_class());
   return CreateClassMirror(owner, type,
                            Bool::True(),  // is_declaration
                            Instance::null_instance());
@@ -1214,16 +1206,6 @@
   return param.bound();
 }
 
-DEFINE_NATIVE_ENTRY(TypedefMirror_declaration, 0, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
-  ASSERT(type.IsFunctionType());
-  const Class& cls = Class::Handle(type.type_class());
-  ASSERT(cls.IsTypedefClass());
-  return CreateTypedefMirror(cls, AbstractType::Handle(cls.DeclarationType()),
-                             Bool::True(),  // is_declaration
-                             Object::null_instance());
-}
-
 DEFINE_NATIVE_ENTRY(InstanceMirror_invoke, 0, 5) {
   // Argument 0 is the mirror, which is unused by the native. It exists
   // because this native is an instance method in order to be polymorphic
@@ -1292,7 +1274,7 @@
       // function_type_arguments.
       const Class& cls = Class::Handle(
           IsolateGroup::Current()->object_store()->object_class());
-      instantiator = Type::New(cls, arguments, TokenPosition::kNoSource);
+      instantiator = Type::New(cls, arguments);
       instantiator.SetIsFinalized();
     }
     return CreateMethodMirror(function, Instance::null_instance(),
@@ -1533,7 +1515,8 @@
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, owner, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
   const Function& func = Function::Handle(ref.GetFunctionReferent());
-  return CreateParameterMirrorList(func, owner);
+  const FunctionType& sig = FunctionType::Handle(func.signature());
+  return CreateParameterMirrorList(func, sig, owner);
 }
 
 DEFINE_NATIVE_ENTRY(MethodMirror_return_type, 0, 2) {
@@ -1581,7 +1564,7 @@
 
   if (decl.IsFunction()) {
     const Function& func = Function::Cast(decl);
-    if (func.IsImplicitConstructor() || func.IsSignatureFunction()) {
+    if (func.IsImplicitConstructor()) {
       // These are synthetic methods; they have no source.
       return Instance::null();
     }
@@ -1589,8 +1572,7 @@
     token_pos = func.token_pos();
   } else if (decl.IsClass()) {
     const Class& cls = Class::Cast(decl);
-    const bool is_typedef = cls.IsTypedefClass();
-    if (cls.is_synthesized_class() && !is_typedef && !cls.is_enum_class()) {
+    if (cls.is_synthesized_class() && !cls.is_enum_class()) {
       return Instance::null();  // Synthetic.
     }
     script = cls.script();
@@ -1600,14 +1582,7 @@
     script = field.Script();
     token_pos = field.token_pos();
   } else if (decl.IsTypeParameter()) {
-    const TypeParameter& type_var = TypeParameter::Cast(decl);
-    if (type_var.IsFunctionTypeParameter()) {
-      // TODO(regis): Support generic functions.
-      return Instance::null();
-    }
-    const Class& owner = Class::Handle(zone, type_var.parameterized_class());
-    script = owner.script();
-    token_pos = type_var.token_pos();
+    return Instance::null();
   } else if (decl.IsLibrary()) {
     const Library& lib = Library::Cast(decl);
     if (lib.raw() == Library::NativeWrappersLibrary()) {
@@ -1634,25 +1609,14 @@
   return CreateSourceLocation(uri, from_line, from_col);
 }
 
-DEFINE_NATIVE_ENTRY(TypedefMirror_referent, 0, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
-  ASSERT(type.IsFunctionType());
-  const Class& cls = Class::Handle(type.type_class());
-  ASSERT(cls.IsTypedefClass());
-  const Function& sig_func = Function::Handle(cls.signature_function());
-  Type& referent_type = Type::Handle(sig_func.SignatureType());
-  ASSERT(cls.raw() == referent_type.type_class());
-  referent_type ^= InstantiateType(referent_type, type);
-  return CreateFunctionTypeMirror(referent_type);
-}
-
 DEFINE_NATIVE_ENTRY(ParameterMirror_type, 0, 3) {
   GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Smi, pos, arguments->NativeArgAt(1));
   GET_NATIVE_ARGUMENT(AbstractType, instantiator, arguments->NativeArgAt(2));
-  const Function& func = Function::Handle(ref.GetFunctionReferent());
-  AbstractType& type = AbstractType::Handle(
-      func.ParameterTypeAt(func.NumImplicitParameters() + pos.Value()));
+  const FunctionType& signature =
+      FunctionType::Handle(ref.GetFunctionTypeReferent());
+  AbstractType& type = AbstractType::Handle(signature.ParameterTypeAt(
+      signature.num_implicit_parameters() + pos.Value()));
   type = type.Canonicalize(
       thread, nullptr);  // Instantiated signatures are not canonical.
   return InstantiateType(type, instantiator);
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 2cee6cf..fae4910 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -81,6 +81,8 @@
     return Type::IntType();
   } else if (instance.IsDouble()) {
     return Type::Double();
+  } else if (instance.IsType() || instance.IsFunctionType()) {
+    return Type::DartTypeType();
   }
   return instance.GetType(Heap::kNew);
 }
@@ -97,8 +99,10 @@
   if (left_cid != right_cid) {
     if (IsIntegerClassId(left_cid)) {
       return Bool::Get(IsIntegerClassId(right_cid)).raw();
-    } else if (IsStringClassId(right_cid)) {
+    } else if (IsStringClassId(left_cid)) {
       return Bool::Get(IsStringClassId(right_cid)).raw();
+    } else if (IsTypeClassId(left_cid)) {
+      return Bool::Get(IsTypeClassId(right_cid)).raw();
     } else {
       return Bool::False().raw();
     }
@@ -198,6 +202,26 @@
   return Bool::Get(type.IsEquivalent(other, TypeEquality::kSyntactical)).raw();
 }
 
+DEFINE_NATIVE_ENTRY(FunctionType_getHashCode, 0, 1) {
+  const FunctionType& type =
+      FunctionType::CheckedHandle(zone, arguments->NativeArgAt(0));
+  intptr_t hash_val = type.Hash();
+  ASSERT(hash_val > 0);
+  ASSERT(Smi::IsValid(hash_val));
+  return Smi::New(hash_val);
+}
+
+DEFINE_NATIVE_ENTRY(FunctionType_equality, 0, 2) {
+  const FunctionType& type =
+      FunctionType::CheckedHandle(zone, arguments->NativeArgAt(0));
+  const Instance& other =
+      Instance::CheckedHandle(zone, arguments->NativeArgAt(1));
+  if (type.raw() == other.raw()) {
+    return Bool::True().raw();
+  }
+  return Bool::Get(type.IsEquivalent(other, TypeEquality::kSyntactical)).raw();
+}
+
 DEFINE_NATIVE_ENTRY(LibraryPrefix_isLoaded, 0, 1) {
   const LibraryPrefix& prefix =
       LibraryPrefix::CheckedHandle(zone, arguments->NativeArgAt(0));
diff --git a/runtime/observatory/lib/src/elements/function_view.dart b/runtime/observatory/lib/src/elements/function_view.dart
index b1b3654..f4ecbfc 100644
--- a/runtime/observatory/lib/src/elements/function_view.dart
+++ b/runtime/observatory/lib/src/elements/function_view.dart
@@ -424,8 +424,6 @@
         return 'stub';
       case M.FunctionKind.tag:
         return 'tag';
-      case M.FunctionKind.signatureFunction:
-        return 'signature function';
       case M.FunctionKind.dynamicInvocationForwarder:
         return 'dynamic invocation forwarder';
     }
diff --git a/runtime/observatory/lib/src/elements/instance_ref.dart b/runtime/observatory/lib/src/elements/instance_ref.dart
index d92d2b9..389350a 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.dart
+++ b/runtime/observatory/lib/src/elements/instance_ref.dart
@@ -125,6 +125,7 @@
                 _instance.valueAsString!, _instance.valueAsStringIsTruncated!)
         ];
       case M.InstanceKind.type:
+      case M.InstanceKind.functionType:
       case M.InstanceKind.typeRef:
       case M.InstanceKind.typeParameter:
         return [
diff --git a/runtime/observatory/lib/src/models/objects/field.dart b/runtime/observatory/lib/src/models/objects/field.dart
index c063238..91c4a05 100644
--- a/runtime/observatory/lib/src/models/objects/field.dart
+++ b/runtime/observatory/lib/src/models/objects/field.dart
@@ -15,7 +15,7 @@
   /// The declared type of this field.
   ///
   /// The value will always be of one of the kinds:
-  /// Type, TypeRef, TypeParameter.
+  /// Type, FunctionType, TypeRef, TypeParameter.
   InstanceRef? get declaredType;
 
   /// Is this field const?
diff --git a/runtime/observatory/lib/src/models/objects/function.dart b/runtime/observatory/lib/src/models/objects/function.dart
index e63ef40..4637d27 100644
--- a/runtime/observatory/lib/src/models/objects/function.dart
+++ b/runtime/observatory/lib/src/models/objects/function.dart
@@ -24,7 +24,6 @@
   ffiTrampoline,
   stub,
   tag,
-  signatureFunction,
   dynamicInvocationForwarder
 }
 
diff --git a/runtime/observatory/lib/src/models/objects/instance.dart b/runtime/observatory/lib/src/models/objects/instance.dart
index a0400c5..8102095 100644
--- a/runtime/observatory/lib/src/models/objects/instance.dart
+++ b/runtime/observatory/lib/src/models/objects/instance.dart
@@ -115,6 +115,9 @@
   /// An instance of the Dart class Type.
   type,
 
+  /// An instance of the Dart class FunctionType.
+  functionType,
+
   /// An instance of the Dart class TypeParameter.
   typeParameter,
 
@@ -170,6 +173,7 @@
   }
   switch (kind) {
     case InstanceKind.type:
+    case InstanceKind.functionType:
     case InstanceKind.typeRef:
     case InstanceKind.typeParameter:
       return true;
@@ -387,7 +391,7 @@
   /// [optional] The referent of a TypeRef instance.
   ///
   /// The value will always be of one of the kinds:
-  /// Type, TypeRef, TypeParameter.
+  /// Type, FunctionType, TypeRef, TypeParameter.
   ///
   /// Provided for instance kinds:
   ///   TypeRef
@@ -396,7 +400,7 @@
   /// [optional] The bound of a TypeParameter.
   ///
   /// The value will always be of one of the kinds:
-  /// Type, TypeRef, TypeParameter.
+  /// Type, FunctionType, TypeRef, TypeParameter.
   ///
   /// Provided for instance kinds:
   ///   TypeParameter
diff --git a/runtime/observatory/lib/src/models/objects/type_arguments.dart b/runtime/observatory/lib/src/models/objects/type_arguments.dart
index ffe2186..a8dc134 100644
--- a/runtime/observatory/lib/src/models/objects/type_arguments.dart
+++ b/runtime/observatory/lib/src/models/objects/type_arguments.dart
@@ -13,6 +13,6 @@
   /// A list of types.
   ///
   /// The value will always be one of the kinds:
-  /// Type, TypeRef, TypeParameter.
+  /// Type, FunctionType, TypeRef, TypeParameter.
   Iterable<InstanceRef>? get types;
 }
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 63ec9c4..759d854 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -2747,6 +2747,8 @@
       return M.InstanceKind.weakProperty;
     case 'Type':
       return M.InstanceKind.type;
+    case 'FunctionType':
+      return M.InstanceKind.functionType;
     case 'TypeParameter':
       return M.InstanceKind.typeParameter;
     case 'TypeRef':
@@ -3118,8 +3120,6 @@
       return M.FunctionKind.stub;
     case 'Tag':
       return M.FunctionKind.tag;
-    case 'SignatureFunction':
-      return M.FunctionKind.signatureFunction;
     case 'DynamicInvocationForwarder':
       return M.FunctionKind.dynamicInvocationForwarder;
   }
diff --git a/runtime/observatory_2/lib/src/elements/function_view.dart b/runtime/observatory_2/lib/src/elements/function_view.dart
index cad9250..963ecc4 100644
--- a/runtime/observatory_2/lib/src/elements/function_view.dart
+++ b/runtime/observatory_2/lib/src/elements/function_view.dart
@@ -422,8 +422,6 @@
         return 'stub';
       case M.FunctionKind.tag:
         return 'tag';
-      case M.FunctionKind.signatureFunction:
-        return 'signature function';
       case M.FunctionKind.dynamicInvocationForwarder:
         return 'dynamic invocation forwarder';
     }
diff --git a/runtime/observatory_2/lib/src/elements/instance_ref.dart b/runtime/observatory_2/lib/src/elements/instance_ref.dart
index 51f3616..1895783 100644
--- a/runtime/observatory_2/lib/src/elements/instance_ref.dart
+++ b/runtime/observatory_2/lib/src/elements/instance_ref.dart
@@ -124,6 +124,7 @@
                 _instance.valueAsString, _instance.valueAsStringIsTruncated)
         ];
       case M.InstanceKind.type:
+      case M.InstanceKind.functionType:
       case M.InstanceKind.typeRef:
       case M.InstanceKind.typeParameter:
         return [
diff --git a/runtime/observatory_2/lib/src/models/objects/field.dart b/runtime/observatory_2/lib/src/models/objects/field.dart
index ca59328c..53bc59d 100644
--- a/runtime/observatory_2/lib/src/models/objects/field.dart
+++ b/runtime/observatory_2/lib/src/models/objects/field.dart
@@ -15,7 +15,7 @@
   /// The declared type of this field.
   ///
   /// The value will always be of one of the kinds:
-  /// Type, TypeRef, TypeParameter.
+  /// Type, FunctionType, TypeRef, TypeParameter.
   InstanceRef get declaredType;
 
   /// Is this field const?
diff --git a/runtime/observatory_2/lib/src/models/objects/function.dart b/runtime/observatory_2/lib/src/models/objects/function.dart
index 7de7ad6..0d31983 100644
--- a/runtime/observatory_2/lib/src/models/objects/function.dart
+++ b/runtime/observatory_2/lib/src/models/objects/function.dart
@@ -24,7 +24,6 @@
   ffiTrampoline,
   stub,
   tag,
-  signatureFunction,
   dynamicInvocationForwarder
 }
 
diff --git a/runtime/observatory_2/lib/src/models/objects/instance.dart b/runtime/observatory_2/lib/src/models/objects/instance.dart
index e52cdd7..b21c572 100644
--- a/runtime/observatory_2/lib/src/models/objects/instance.dart
+++ b/runtime/observatory_2/lib/src/models/objects/instance.dart
@@ -115,6 +115,9 @@
   /// An instance of the Dart class Type.
   type,
 
+  /// An instance of the Dart class FunctionType.
+  functionType,
+
   /// An instance of the Dart class TypeParameter.
   typeParameter,
 
@@ -161,6 +164,7 @@
 bool isAbstractType(InstanceKind kind) {
   switch (kind) {
     case InstanceKind.type:
+    case InstanceKind.functionType:
     case InstanceKind.typeRef:
     case InstanceKind.typeParameter:
       return true;
@@ -378,7 +382,7 @@
   /// [optional] The referent of a TypeRef instance.
   ///
   /// The value will always be of one of the kinds:
-  /// Type, TypeRef, TypeParameter.
+  /// Type, FunctionType, TypeRef, TypeParameter.
   ///
   /// Provided for instance kinds:
   ///   TypeRef
@@ -387,7 +391,7 @@
   /// [optional] The bound of a TypeParameter.
   ///
   /// The value will always be of one of the kinds:
-  /// Type, TypeRef, TypeParameter.
+  /// Type, FunctionType, TypeRef, TypeParameter.
   ///
   /// Provided for instance kinds:
   ///   TypeParameter
diff --git a/runtime/observatory_2/lib/src/models/objects/type_arguments.dart b/runtime/observatory_2/lib/src/models/objects/type_arguments.dart
index a3614dd..a6469df 100644
--- a/runtime/observatory_2/lib/src/models/objects/type_arguments.dart
+++ b/runtime/observatory_2/lib/src/models/objects/type_arguments.dart
@@ -13,6 +13,6 @@
   /// A list of types.
   ///
   /// The value will always be one of the kinds:
-  /// Type, TypeRef, TypeParameter.
+  /// Type, FunctionType, TypeRef, TypeParameter.
   Iterable<InstanceRef> get types;
 }
diff --git a/runtime/observatory_2/lib/src/service/object.dart b/runtime/observatory_2/lib/src/service/object.dart
index 981215d..da5b60f 100644
--- a/runtime/observatory_2/lib/src/service/object.dart
+++ b/runtime/observatory_2/lib/src/service/object.dart
@@ -2756,6 +2756,8 @@
       return M.InstanceKind.weakProperty;
     case 'Type':
       return M.InstanceKind.type;
+    case 'FunctionType':
+      return M.InstanceKind.functionType;
     case 'TypeParameter':
       return M.InstanceKind.typeParameter;
     case 'TypeRef':
@@ -3131,8 +3133,6 @@
       return M.FunctionKind.stub;
     case 'Tag':
       return M.FunctionKind.tag;
-    case 'SignatureFunction':
-      return M.FunctionKind.signatureFunction;
     case 'DynamicInvocationForwarder':
       return M.FunctionKind.dynamicInvocationForwarder;
   }
diff --git a/runtime/tests/vm/dart/isolate_send_function_types_test.dart b/runtime/tests/vm/dart/isolate_send_function_types_test.dart
index 1129e87..f3b7f17 100644
--- a/runtime/tests/vm/dart/isolate_send_function_types_test.dart
+++ b/runtime/tests/vm/dart/isolate_send_function_types_test.dart
@@ -22,7 +22,7 @@
     Expect.equals(
         await caughtErrorCompleter.future,
         "Invalid argument(s): Illegal argument in isolate message : "
-        "(function types are not supported yet)");
+        "(object is a FunctionType)");
   }
 
   Future<void> genericFunc<T>() async {
@@ -36,7 +36,7 @@
     Expect.equals(
         await caughtErrorCompleter.future,
         "Invalid argument(s): Illegal argument in isolate message : "
-        "(function types are not supported yet)");
+        "(object is a FunctionType)");
   }
 
   await genericFunc<int>();
diff --git a/runtime/tests/vm/dart_2/isolate_send_function_types_test.dart b/runtime/tests/vm/dart_2/isolate_send_function_types_test.dart
index e45e045..8075c8b 100644
--- a/runtime/tests/vm/dart_2/isolate_send_function_types_test.dart
+++ b/runtime/tests/vm/dart_2/isolate_send_function_types_test.dart
@@ -22,7 +22,7 @@
     Expect.equals(
         await caughtErrorCompleter.future,
         "Invalid argument(s): Illegal argument in isolate message : "
-        "(function types are not supported yet)");
+        "(object is a FunctionType)");
   }
 
   void genericFunc<T>() async {
@@ -36,7 +36,7 @@
     Expect.equals(
         await caughtErrorCompleter.future,
         "Invalid argument(s): Illegal argument in isolate message : "
-        "(function types are not supported yet)");
+        "(object is a FunctionType)");
   }
 
   await genericFunc<int>();
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index df3b7ec..6750bf9 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -30,6 +30,8 @@
   V(AbstractType_toString, 1)                                                  \
   V(Type_getHashCode, 1)                                                       \
   V(Type_equality, 2)                                                          \
+  V(FunctionType_getHashCode, 1)                                               \
+  V(FunctionType_equality, 2)                                                  \
   V(LibraryPrefix_isLoaded, 1)                                                 \
   V(LibraryPrefix_setLoaded, 1)                                                \
   V(LibraryPrefix_loadingUnit, 1)                                              \
@@ -469,8 +471,6 @@
   V(MethodMirror_return_type, 2)                                               \
   V(MethodMirror_source, 1)                                                    \
   V(ParameterMirror_type, 3)                                                   \
-  V(TypedefMirror_referent, 1)                                                 \
-  V(TypedefMirror_declaration, 1)                                              \
   V(VariableMirror_type, 2)
 
 class BootstrapNatives : public AllStatic {
diff --git a/runtime/vm/canonical_tables.cc b/runtime/vm/canonical_tables.cc
index d5ab2ff..1fb5e8c 100644
--- a/runtime/vm/canonical_tables.cc
+++ b/runtime/vm/canonical_tables.cc
@@ -45,9 +45,12 @@
     if (!name_a.Equals(name_b)) {
       return false;
     }
-    const Object& owner_a = Object::Handle(TypeParameter::Cast(a).Owner());
-    const Object& owner_b = Object::Handle(TypeParameter::Cast(b).Owner());
-    return IsMatch(owner_a, owner_b);
+    if (TypeParameter::Cast(a).index() != TypeParameter::Cast(b).index() ||
+        TypeParameter::Cast(a).base() != TypeParameter::Cast(b).base()) {
+      return false;
+    }
+    return TypeParameter::Cast(a).parameterized_class_id() ==
+           TypeParameter::Cast(b).parameterized_class_id();
   }
   return a.raw() == b.raw();
 }
diff --git a/runtime/vm/canonical_tables.h b/runtime/vm/canonical_tables.h
index f0c3d2b..8c44802 100644
--- a/runtime/vm/canonical_tables.h
+++ b/runtime/vm/canonical_tables.h
@@ -172,6 +172,45 @@
 };
 typedef UnorderedHashSet<CanonicalTypeTraits> CanonicalTypeSet;
 
+class CanonicalFunctionTypeKey {
+ public:
+  explicit CanonicalFunctionTypeKey(const FunctionType& key) : key_(key) {}
+  bool Matches(const FunctionType& arg) const { return key_.Equals(arg); }
+  uword Hash() const { return key_.Hash(); }
+  const FunctionType& key_;
+
+ private:
+  DISALLOW_ALLOCATION();
+};
+
+// Traits for looking up Canonical FunctionType based on its hash.
+class CanonicalFunctionTypeTraits {
+ public:
+  static const char* Name() { return "CanonicalFunctionTypeTraits"; }
+  static bool ReportStats() { return false; }
+
+  // Called when growing the table.
+  static bool IsMatch(const Object& a, const Object& b) {
+    ASSERT(a.IsFunctionType() && b.IsFunctionType());
+    const FunctionType& arg1 = FunctionType::Cast(a);
+    const FunctionType& arg2 = FunctionType::Cast(b);
+    return arg1.Equals(arg2) && (arg1.Hash() == arg2.Hash());
+  }
+  static bool IsMatch(const CanonicalFunctionTypeKey& a, const Object& b) {
+    ASSERT(b.IsFunctionType());
+    return a.Matches(FunctionType::Cast(b));
+  }
+  static uword Hash(const Object& key) {
+    ASSERT(key.IsFunctionType());
+    return FunctionType::Cast(key).Hash();
+  }
+  static uword Hash(const CanonicalFunctionTypeKey& key) { return key.Hash(); }
+  static ObjectPtr NewKey(const CanonicalFunctionTypeKey& obj) {
+    return obj.key_.raw();
+  }
+};
+typedef UnorderedHashSet<CanonicalFunctionTypeTraits> CanonicalFunctionTypeSet;
+
 class CanonicalTypeParameterKey {
  public:
   explicit CanonicalTypeParameterKey(const TypeParameter& key) : key_(key) {}
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 6e3de37..f054bb9 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -288,30 +288,24 @@
 }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
-void ClassFinalizer::FinalizeTypeParameters(const Class& cls) {
+void ClassFinalizer::FinalizeTypeParameters(const Class& cls,
+                                            FinalizationKind finalization) {
   if (FLAG_trace_type_finalization) {
-    THR_Print("Finalizing type parameters of '%s'\n",
-              String::Handle(cls.Name()).ToCString());
+    THR_Print("%s type parameters of '%s'\n",
+              String::Handle(cls.Name()).ToCString(),
+              finalization == kFinalize ? "Finalizing" : "Canonicalizing");
   }
-  // The type parameter bounds are not finalized here.
-  const intptr_t offset = cls.NumTypeArguments() - cls.NumTypeParameters();
-  const TypeArguments& type_parameters =
+  const TypeArguments& type_params =
       TypeArguments::Handle(cls.type_parameters());
-  if (!type_parameters.IsNull()) {
-    TypeParameter& type_parameter = TypeParameter::Handle();
-    const intptr_t num_types = type_parameters.Length();
-    for (intptr_t i = 0; i < num_types; i++) {
-      type_parameter ^= type_parameters.TypeAt(i);
-      if (!type_parameter.IsFinalized()) {
-        ASSERT(type_parameter.index() == i);
-        type_parameter.set_index(offset + i);
-        type_parameter.SetIsFinalized();
-      } else {
-        ASSERT(type_parameter.index() == offset + i);
+  if (!type_params.IsNull()) {
+    const intptr_t num_type_params = type_params.Length();
+    TypeParameter& type_param = TypeParameter::Handle();
+    for (intptr_t i = 0; i < num_type_params; i++) {
+      type_param ^= type_params.TypeAt(i);
+      if (!type_param.IsBeingFinalized()) {
+        type_param ^= FinalizeType(type_param, finalization);
+        type_params.SetTypeAt(i, type_param);
       }
-      // The declaration of a type parameter is canonical.
-      ASSERT(type_parameter.IsDeclaration());
-      ASSERT(type_parameter.IsCanonical());
     }
   }
 }
@@ -328,6 +322,7 @@
 // pending finalization that are mutually recursive with the checked type.
 void ClassFinalizer::CheckRecursiveType(const AbstractType& type,
                                         PendingTypes* pending_types) {
+  ASSERT(!type.IsFunctionType());
   ASSERT(pending_types != NULL);
   Zone* zone = Thread::Current()->zone();
   if (FLAG_trace_type_finalization) {
@@ -338,13 +333,7 @@
   const TypeArguments& arguments =
       TypeArguments::Handle(zone, type.arguments());
   // A type can only be recursive via its type arguments.
-  if (arguments.IsNull()) {
-    // However, Kernel does not keep the relation between a function type and
-    // its declaring typedef. Therefore, a typedef-declared function type may
-    // refer to the still unfinalized typedef via a type in its signature.
-    ASSERT(type.IsFunctionType());
-    return;
-  }
+  ASSERT(!arguments.IsNull());
   const intptr_t num_type_args = arguments.Length();
   ASSERT(num_type_args > 0);
   ASSERT(num_type_args == type_cls.NumTypeArguments());
@@ -416,9 +405,6 @@
   // Also, the type parameters of the type class must be finalized.
   Class& type_class = Class::Handle(zone, type.type_class());
   type_class.EnsureDeclarationLoaded();
-  if (!type_class.is_type_finalized()) {
-    FinalizeTypeParameters(type_class);
-  }
 
   // The finalized type argument vector needs num_type_arguments types.
   const intptr_t num_type_arguments = type_class.NumTypeArguments();
@@ -430,13 +416,6 @@
   TypeArguments& arguments = TypeArguments::Handle(zone, type.arguments());
   ASSERT(arguments.IsNull() || (arguments.Length() == num_type_parameters));
 
-  // Mark the type as being finalized in order to detect self reference and
-  // postpone bound checking (if required) until after all types in the graph of
-  // mutually recursive types are finalized.
-  type.SetIsBeingFinalized();
-  ASSERT(pending_types != NULL);
-  pending_types->Add(type);
-
   // The full type argument vector consists of the type arguments of the
   // super types of type_class, which are initialized from the parsed
   // type arguments, followed by the parsed type arguments.
@@ -471,8 +450,12 @@
       if (!arguments.IsNull()) {
         for (intptr_t i = 0; i < num_type_parameters; i++) {
           type_arg = full_arguments.TypeAt(offset + i);
-          ASSERT(!type_arg.IsBeingFinalized());
-          type_arg = FinalizeType(type_arg, kFinalize, pending_types);
+          if (!type_arg.IsBeingFinalized()) {
+            type_arg = FinalizeType(type_arg, kFinalize, pending_types);
+          } else {
+            ASSERT(type_arg.IsTypeParameter());
+            // The bound of the type parameter is still being finalized.
+          }
           full_arguments.SetTypeAt(offset + i, type_arg);
         }
       }
@@ -537,7 +520,7 @@
                                            TrailPtr trail) {
   ASSERT(arguments.Length() >= cls.NumTypeArguments());
   if (!cls.is_type_finalized()) {
-    FinalizeTypeParameters(cls);
+    FinalizeTypeParameters(cls, kFinalize);
   }
   AbstractType& super_type = AbstractType::Handle(cls.super_type());
   if (!super_type.IsNull()) {
@@ -559,14 +542,25 @@
         super_type_arg = super_type_args.TypeAt(i);
         if (!super_type_arg.IsTypeRef()) {
           if (super_type_arg.IsBeingFinalized()) {
-            ASSERT(super_type_arg.IsType());
-            CheckRecursiveType(super_type_arg, pending_types);
-            if (FLAG_trace_type_finalization) {
-              THR_Print("Creating TypeRef '%s': '%s'\n",
-                        String::Handle(super_type_arg.Name()).ToCString(),
-                        super_type_arg.ToCString());
+            // A type parameter being finalized indicates an unfinalized bound,
+            // but the bound is not relevant here. Its index is finalized.
+            if (!super_type_arg.IsTypeParameter()) {
+              if (super_type_arg.IsType()) {
+                CheckRecursiveType(super_type_arg, pending_types);
+              } else {
+                // The spec prohibits a typedef-declared function type to refer
+                // to itself. However, self-reference can occur via type
+                // arguments of the base class,
+                // e.g. `class Derived extends Base<TypeDef<Derived>> {}`.
+                ASSERT(super_type_arg.IsFunctionType());
+              }
+              if (FLAG_trace_type_finalization) {
+                THR_Print("Creating TypeRef '%s': '%s'\n",
+                          String::Handle(super_type_arg.Name()).ToCString(),
+                          super_type_arg.ToCString());
+              }
+              super_type_arg = TypeRef::New(super_type_arg);
             }
-            super_type_arg = TypeRef::New(super_type_arg);
             super_type_args.SetTypeAt(i, super_type_arg);
           } else {
             if (!super_type_arg.IsFinalized()) {
@@ -603,9 +597,11 @@
           super_type_arg = super_type_arg.InstantiateFrom(
               arguments, Object::null_type_arguments(), kNoneFree, Heap::kOld,
               trail);
-          if (super_type_arg.IsBeingFinalized()) {
+          if (super_type_arg.IsBeingFinalized() &&
+              !super_type_arg.IsTypeParameter()) {
             // The super_type_arg was instantiated from a type being finalized.
-            // We need to finish finalizing its type arguments.
+            // We need to finish finalizing its type arguments, unless it is a
+            // type parameter, in which case there is nothing more to do.
             AbstractType& unfinalized_type = AbstractType::Handle();
             if (super_type_arg.IsTypeRef()) {
               unfinalized_type = TypeRef::Cast(super_type_arg).type();
@@ -618,8 +614,10 @@
                         String::Handle(unfinalized_type.Name()).ToCString(),
                         unfinalized_type.ToCString());
             }
-            CheckRecursiveType(unfinalized_type, pending_types);
-            pending_types->Add(unfinalized_type);
+            if (unfinalized_type.IsType()) {
+              CheckRecursiveType(unfinalized_type, pending_types);
+              pending_types->Add(unfinalized_type);
+            }
             const Class& super_cls =
                 Class::Handle(unfinalized_type.type_class());
             const TypeArguments& super_args =
@@ -658,12 +656,12 @@
   ASSERT((pending_types == NULL) || (finalization < kCanonicalize));
   if (type.IsFinalized()) {
     // Ensure type is canonical if canonicalization is requested.
-    if ((finalization >= kCanonicalize) && !type.IsCanonical()) {
+    if ((finalization >= kCanonicalize) && !type.IsCanonical() &&
+        !type.IsBeingFinalized()) {
       return type.Canonicalize(Thread::Current(), nullptr);
     }
     return type.raw();
   }
-  ASSERT(finalization >= kFinalize);
 
   if (type.IsTypeRef()) {
     // The referenced type will be finalized later by the code that set the
@@ -671,11 +669,21 @@
     return type.raw();
   }
 
+  if (type.IsTypeParameter() && type.IsBeingFinalized()) {
+    // The base and index have already been adjusted, but the bound referring
+    // back to the type parameter is still being finalized.
+    return type.raw();
+  }
+
   // Recursive types must be processed in FinalizeTypeArguments() and cannot be
   // encountered here.
   ASSERT(!type.IsBeingFinalized());
 
-  Zone* zone = Thread::Current()->zone();
+  // Mark the type as being finalized in order to detect self reference.
+  type.SetIsBeingFinalized();
+
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
 
   if (FLAG_trace_type_finalization) {
     THR_Print("Finalizing type '%s'\n",
@@ -686,100 +694,71 @@
     const TypeParameter& type_parameter = TypeParameter::Cast(type);
     const Class& parameterized_class =
         Class::Handle(zone, type_parameter.parameterized_class());
-    intptr_t offset;
+    // The base and index of a function type parameter are eagerly calculated
+    // upon loading and do not require adjustment here.
     if (!parameterized_class.IsNull()) {
       // The index must reflect the position of this type parameter in the type
       // arguments vector of its parameterized class. The offset to add is the
       // number of type arguments in the super type, which is equal to the
       // difference in number of type arguments and type parameters of the
       // parameterized class.
-      offset = parameterized_class.NumTypeArguments() -
-               parameterized_class.NumTypeParameters();
-    } else {
-      const Function& function =
-          Function::Handle(zone, type_parameter.parameterized_function());
-      ASSERT(!function.IsNull());
-      offset = function.NumParentTypeParameters();
+      const intptr_t offset = parameterized_class.NumTypeArguments() -
+                              parameterized_class.NumTypeParameters();
+      type_parameter.set_base(offset);  // Informative, but not needed.
+      type_parameter.set_index(type_parameter.index() + offset);
+
+      // Remove the reference to the parameterized class.
+      type_parameter.set_parameterized_class_id(kClassCid);
     }
-    type_parameter.set_index(type_parameter.index() + offset);
+
+    AbstractType& t = AbstractType::Handle(zone);
+    t = type_parameter.bound();
+    if (!t.IsBeingFinalized()) {
+      t = FinalizeType(t, kFinalize);
+      type_parameter.set_bound(t);
+    }
+    t = type_parameter.default_argument();
+    // The default argument cannot create a cycle with the type parameter.
+    t = FinalizeType(t, kFinalize);
+    type_parameter.set_default_argument(t);
+
     type_parameter.SetIsFinalized();
 
     if (FLAG_trace_type_finalization) {
-      THR_Print("Done finalizing type parameter '%s' with index %" Pd "\n",
-                String::Handle(zone, type_parameter.name()).ToCString(),
+      THR_Print("Done finalizing type parameter at index %" Pd "\n",
                 type_parameter.index());
     }
 
-    if (type_parameter.IsDeclaration()) {
-      // The declaration of a type parameter is canonical.
-      ASSERT(type_parameter.IsCanonical());
-      return type_parameter.raw();
+    if (finalization >= kCanonicalize) {
+      return type_parameter.Canonicalize(thread, nullptr);
     }
-    return type_parameter.Canonicalize(Thread::Current(), nullptr);
+    return type_parameter.raw();
   }
 
-  // At this point, we can only have a Type.
-  ASSERT(type.IsType());
+  // If the type is a function type, we also need to finalize the types in its
+  // signature, i.e. finalize the result type and parameter types of the
+  // signature function of this function type.
+  if (type.IsFunctionType()) {
+    return FinalizeSignature(zone, FunctionType::Cast(type), finalization,
+                             pending_types);
+  }
 
   // This type is the root type of the type graph if no pending types queue is
-  // allocated yet.
+  // allocated yet. A function type is a collection of types, but not a root.
   const bool is_root_type = pending_types == NULL;
   if (is_root_type) {
     pending_types = new PendingTypes(zone, 4);
   }
 
+  // At this point, we can only have a Type.
+  ASSERT(type.IsType());
+  pending_types->Add(type);
+
   const intptr_t num_expanded_type_arguments =
       ExpandAndFinalizeTypeArguments(type, pending_types);
 
   // Self referencing types may get finalized indirectly.
   if (!type.IsFinalized()) {
-    // If the type is a function type, we also need to finalize the types in its
-    // signature, i.e. finalize the result type and parameter types of the
-    // signature function of this function type.
-    // We do this after marking this type as finalized in order to allow a
-    // typedef function type to refer to itself via its parameter types and
-    // result type.
-    if (type.IsFunctionType()) {
-      const Type& fun_type = Type::Cast(type);
-      const Class& scope_class = Class::Handle(zone, fun_type.type_class());
-      if (scope_class.IsTypedefClass()) {
-        Function& signature =
-            Function::Handle(zone, scope_class.signature_function());
-        if (!scope_class.is_type_finalized()) {
-          FinalizeSignature(signature, finalization);
-        }
-        // If the function type is a generic typedef, instantiate its signature
-        // from its type arguments.
-        // Example: typedef F<T> = S Function<S>(T x) has uninstantiated
-        // signature (T x) => S.
-        // The instantiated signature of F(int) becomes (int x) => S.
-        // Note that after this step, the signature of the function type is not
-        // identical to the canonical signature of the typedef class anymore.
-        if (scope_class.IsGeneric() && !signature.HasInstantiatedSignature()) {
-          if (FLAG_trace_type_finalization) {
-            THR_Print("Instantiating signature '%s' of typedef '%s'\n",
-                      String::Handle(zone, signature.Signature()).ToCString(),
-                      String::Handle(zone, fun_type.Name()).ToCString());
-          }
-          const TypeArguments& instantiator_type_arguments =
-              TypeArguments::Handle(zone, fun_type.arguments());
-          signature = signature.InstantiateSignatureFrom(
-              instantiator_type_arguments, Object::null_type_arguments(),
-              kNoneFree, Heap::kOld);
-          // Note that if instantiator_type_arguments contains type parameters,
-          // as in F<K>, the signature is still uninstantiated (the typedef type
-          // parameters were substituted in the signature with typedef type
-          // arguments). Note also that the function type parameters were not
-          // modified.
-          FinalizeSignature(signature, finalization);
-        }
-        fun_type.set_signature(signature);
-      } else {
-        FinalizeSignature(Function::Handle(zone, fun_type.signature()),
-                          finalization);
-      }
-    }
-
     if (FLAG_trace_type_finalization) {
       THR_Print("Marking type '%s' as finalized\n",
                 String::Handle(zone, type.Name()).ToCString());
@@ -798,108 +777,73 @@
     if (FLAG_trace_type_finalization) {
       THR_Print("Canonicalizing type '%s'\n",
                 String::Handle(zone, type.Name()).ToCString());
-      AbstractType& canonical_type = AbstractType::Handle(
-          zone, type.Canonicalize(Thread::Current(), nullptr));
+      AbstractType& canonical_type =
+          AbstractType::Handle(zone, type.Canonicalize(thread, nullptr));
       THR_Print("Done canonicalizing type '%s'\n",
                 String::Handle(zone, canonical_type.Name()).ToCString());
       return canonical_type.raw();
     }
-    return type.Canonicalize(Thread::Current(), nullptr);
+    return type.Canonicalize(thread, nullptr);
   } else {
     return type.raw();
   }
 }
 
-void ClassFinalizer::FinalizeSignature(const Function& function,
-                                       FinalizationKind finalization) {
-  AbstractType& type = AbstractType::Handle();
-  AbstractType& finalized_type = AbstractType::Handle();
-  // Finalize function type parameters, including their bounds and default args.
-  const intptr_t num_parent_type_params = function.NumParentTypeParameters();
-  const intptr_t num_type_params = function.NumTypeParameters();
+AbstractTypePtr ClassFinalizer::FinalizeSignature(Zone* zone,
+                                                  const FunctionType& signature,
+                                                  FinalizationKind finalization,
+                                                  PendingTypes* pending_types) {
+  AbstractType& type = AbstractType::Handle(zone);
+  AbstractType& finalized_type = AbstractType::Handle(zone);
+  // Finalize signature type parameters, their upper bounds and default args.
+  const intptr_t num_type_params = signature.NumTypeParameters();
   if (num_type_params > 0) {
-    TypeParameter& type_param = TypeParameter::Handle();
+    TypeParameter& type_param = TypeParameter::Handle(zone);
     const TypeArguments& type_params =
-        TypeArguments::Handle(function.type_parameters());
+        TypeArguments::Handle(zone, signature.type_parameters());
     for (intptr_t i = 0; i < num_type_params; i++) {
       type_param ^= type_params.TypeAt(i);
-      if (!type_param.IsFinalized()) {
-        ASSERT(type_param.index() == i);
-        type_param.set_index(num_parent_type_params + i);
-        type_param.SetIsFinalized();
-      } else {
-        ASSERT(type_param.index() == num_parent_type_params + i);
-      }
-      // The declaration of a type parameter is canonical.
-      ASSERT(type_param.IsDeclaration());
-      ASSERT(type_param.IsCanonical());
-    }
-    for (intptr_t i = 0; i < num_type_params; i++) {
-      type_param ^= type_params.TypeAt(i);
-      type = type_param.bound();
-      finalized_type = FinalizeType(type, finalization);
-      if (finalized_type.raw() != type.raw()) {
-        type_param.set_bound(finalized_type);
-      }
-      type = type_param.default_argument();
-      finalized_type = FinalizeType(type, finalization);
-      if (finalized_type.raw() != type.raw()) {
-        type_param.set_default_argument(finalized_type);
+      finalized_type ^= FinalizeType(type_param, kFinalize, pending_types);
+      if (type_param.raw() != finalized_type.raw()) {
+        type_params.SetTypeAt(i, TypeParameter::Cast(finalized_type));
       }
     }
-    function.UpdateCachedDefaultTypeArguments(Thread::Current());
   }
+
   // Finalize result type.
-  type = function.result_type();
-  finalized_type = FinalizeType(type, finalization);
+  type = signature.result_type();
+  finalized_type = FinalizeType(type, kFinalize, pending_types);
   if (finalized_type.raw() != type.raw()) {
-    function.set_result_type(finalized_type);
+    signature.set_result_type(finalized_type);
   }
   // Finalize formal parameter types.
-  const intptr_t num_parameters = function.NumParameters();
+  const intptr_t num_parameters = signature.NumParameters();
   for (intptr_t i = 0; i < num_parameters; i++) {
-    type = function.ParameterTypeAt(i);
-    finalized_type = FinalizeType(type, finalization);
+    type = signature.ParameterTypeAt(i);
+    finalized_type = FinalizeType(type, kFinalize, pending_types);
     if (type.raw() != finalized_type.raw()) {
-      function.SetParameterTypeAt(i, finalized_type);
+      signature.SetParameterTypeAt(i, finalized_type);
     }
   }
-}
 
-// Finalize bounds and default arguments of the type parameters of class cls.
-void ClassFinalizer::FinalizeUpperBounds(const Class& cls,
-                                         FinalizationKind finalization) {
-  const intptr_t num_type_params = cls.NumTypeParameters();
-  TypeParameter& type_param = TypeParameter::Handle();
-  AbstractType& type = AbstractType::Handle();
-  const TypeArguments& type_params =
-      TypeArguments::Handle(cls.type_parameters());
-  ASSERT((type_params.IsNull() && (num_type_params == 0)) ||
-         (type_params.Length() == num_type_params));
-  for (intptr_t i = 0; i < num_type_params; i++) {
-    type_param ^= type_params.TypeAt(i);
-    // First, finalize the default argument (no cycles possible here).
-    type = type_param.default_argument();
-    type = FinalizeType(type, finalization);
-    type_param.set_default_argument(type);
-    // Next, finalize the bound.
-    type = type_param.bound();
-    // Bound may be finalized, but not canonical yet.
-    if (type.IsCanonical() || type.IsBeingFinalized()) {
-      // A bound involved in F-bounded quantification may form a cycle.
-      continue;
-    }
-    type = FinalizeType(type, finalization);
-    type_param.set_bound(type);
+  if (FLAG_trace_type_finalization) {
+    THR_Print("Marking function type '%s' as finalized\n",
+              String::Handle(zone, signature.Name()).ToCString());
   }
+  signature.SetIsFinalized();
+
+  if (finalization >= kCanonicalize) {
+    return signature.Canonicalize(Thread::Current(), nullptr);
+  }
+  return signature.raw();
 }
 
 #if defined(TARGET_ARCH_X64)
 static bool IsPotentialExactGeneric(const AbstractType& type) {
   // TODO(dartbug.com/34170) Investigate supporting this for fields with types
   // that depend on type parameters of the enclosing class.
-  if (type.IsType() && !type.IsFunctionType() && !type.IsDartFunctionType() &&
-      type.IsInstantiated() && !type.IsFutureOrType()) {
+  if (type.IsType() && !type.IsDartFunctionType() && type.IsInstantiated() &&
+      !type.IsFutureOrType()) {
     const Class& cls = Class::Handle(type.type_class());
     return cls.IsGeneric();
   }
@@ -939,6 +883,8 @@
   Array& array = Array::Handle(zone, cls.fields());
   Field& field = Field::Handle(zone);
   AbstractType& type = AbstractType::Handle(zone);
+  Function& function = Function::Handle(zone);
+  FunctionType& signature = FunctionType::Handle(zone);
   const intptr_t num_fields = array.Length();
   const bool track_exactness = isolate_group->use_field_guards();
   for (intptr_t i = 0; i < num_fields; i++) {
@@ -950,15 +896,24 @@
       field.set_static_type_exactness_state(
           StaticTypeExactnessState::Uninitialized());
     }
+    function = field.InitializerFunction();
+    if (!function.IsNull()) {
+      // TODO(regis): It looks like the initializer is never set at this point.
+      // Remove this finalization code?
+      signature = function.signature();
+      signature ^= FinalizeType(signature);
+      function.set_signature(signature);
+    }
   }
   // Finalize function signatures and check for conflicts in super classes and
   // interfaces.
   array = cls.current_functions();
-  Function& function = Function::Handle(zone);
   const intptr_t num_functions = array.Length();
   for (intptr_t i = 0; i < num_functions; i++) {
     function ^= array.At(i);
-    FinalizeSignature(function);
+    signature = function.signature();
+    signature ^= FinalizeType(signature);
+    function.set_signature(signature);
     if (function.IsSetterFunction() || function.IsImplicitSetterFunction()) {
       continue;
     }
@@ -1011,45 +966,16 @@
     FinalizeTypesInClass(super_class);
   }
   // Finalize type parameters before finalizing the super type.
-  FinalizeTypeParameters(cls);
+  FinalizeTypeParameters(cls, kFinalize);
+  ASSERT(super_class.raw() == cls.SuperClass());  // Not modified.
   ASSERT(super_class.IsNull() || super_class.is_type_finalized());
-  FinalizeUpperBounds(cls);
+  FinalizeTypeParameters(cls, kCanonicalize);
   // Finalize super type.
   AbstractType& super_type = AbstractType::Handle(cls.super_type());
   if (!super_type.IsNull()) {
     super_type = FinalizeType(super_type);
     cls.set_super_type(super_type);
   }
-  if (cls.IsTypedefClass()) {
-    Function& signature = Function::Handle(cls.signature_function());
-    Type& type = Type::Handle(signature.SignatureType());
-    ASSERT(type.signature() == signature.raw());
-    ASSERT(type.type_class() == cls.raw());
-
-    cls.set_is_type_finalized();
-
-    // Finalize the result and parameter types of the signature
-    // function of this typedef class.
-    FinalizeSignature(signature);  // Does not modify signature type.
-    ASSERT(signature.SignatureType() == type.raw());
-
-    // Finalize the signature type of this typedef.
-    type ^= FinalizeType(type);
-    ASSERT(type.type_class() == cls.raw());
-
-    // If a different canonical signature type is returned, update the signature
-    // function of the typedef.
-    signature = type.signature();
-    signature.SetSignatureType(type);
-    cls.set_signature_function(signature);
-
-    // Closure instances do not refer to this typedef as their class, so there
-    // is no need to add this typedef class to the subclasses of _Closure.
-    ASSERT(super_type.IsNull() || super_type.IsObjectType());
-
-    return;
-  }
-
   // Finalize interface types (but not necessarily interface classes).
   Array& interface_types = Array::Handle(cls.interfaces());
   AbstractType& interface_type = AbstractType::Handle();
@@ -1564,21 +1490,23 @@
 // In the Dart VM heap the following instances directly use cids for the
 // computation of canonical hash codes:
 //
-//    * RawType (due to TypeLayout::type_class_id_)
-//    * RawTypeParameter (due to TypeParameterLayout::parameterized_class_id_)
+//    * TypePtr (due to TypeLayout::type_class_id_)
+//    * TypeParameterPtr (due to TypeParameterLayout::parameterized_class_id_)
 //
 // The following instances use cids for the computation of canonical hash codes
 // indirectly:
 //
-//    * RawTypeRef (due to TypeRefLayout::type_->type_class_id)
-//    * RawType (due to TypeLayout::signature_'s result/parameter types)
-//    * RawTypeArguments (due to type references)
-//    * RawInstance (due to instance fields)
-//    * RawArray (due to type arguments & array entries)
+//    * TypeRefPtr (due to TypeRefLayout::type_->type_class_id)
+//    * TypePtr (due to type arguments)
+//    * FunctionTypePtr (due to the result and parameter types)
+//    * TypeArgumentsPtr (due to type references)
+//    * InstancePtr (due to instance fields)
+//    * ArrayPtr (due to type arguments & array entries)
 //
 // Caching of the canonical hash codes happens for:
 //
 //    * TypeLayout::hash_
+//    * FunctionTypeLayout::hash_
 //    * TypeParameterLayout::hash_
 //    * TypeArgumentsLayout::hash_
 //    * RawInstance (weak table)
@@ -1587,11 +1515,12 @@
 // No caching of canonical hash codes (i.e. it gets re-computed every time)
 // happens for:
 //
-//    * RawTypeRef (computed via TypeRefLayout::type_->type_class_id)
+//    * TypeRefPtr (computed via TypeRefLayout::type_->type_class_id)
 //
 // Usages of canonical hash codes are:
 //
 //   * ObjectStore::canonical_types()
+//   * ObjectStore::canonical_function_types()
 //   * ObjectStore::canonical_type_parameters()
 //   * ObjectStore::canonical_type_arguments()
 //   * Class::constants()
@@ -1601,6 +1530,7 @@
   explicit ClearTypeHashVisitor(Zone* zone)
       : type_param_(TypeParameter::Handle(zone)),
         type_(Type::Handle(zone)),
+        function_type_(FunctionType::Handle(zone)),
         type_args_(TypeArguments::Handle(zone)) {}
 
   void VisitObject(ObjectPtr obj) {
@@ -1610,6 +1540,9 @@
     } else if (obj->IsType()) {
       type_ ^= obj;
       type_.SetHash(0);
+    } else if (obj->IsFunctionType()) {
+      function_type_ ^= obj;
+      function_type_.SetHash(0);
     } else if (obj->IsTypeArguments()) {
       type_args_ ^= obj;
       type_args_.SetHash(0);
@@ -1619,6 +1552,7 @@
  private:
   TypeParameter& type_param_;
   Type& type_;
+  FunctionType& function_type_;
   TypeArguments& type_args_;
 };
 
@@ -1656,6 +1590,27 @@
   }
   object_store->set_canonical_types(types_table.Release());
 
+  // Rehash the canonical FunctionTypes table.
+  Array& function_types = Array::Handle(Z);
+  FunctionType& function_type = FunctionType::Handle(Z);
+  {
+    CanonicalFunctionTypeSet function_types_table(
+        Z, object_store->canonical_function_types());
+    function_types = HashTables::ToArray(function_types_table, false);
+    function_types_table.Release();
+  }
+
+  dict_size = Utils::RoundUpToPowerOfTwo(function_types.Length() * 4 / 3);
+  CanonicalFunctionTypeSet function_types_table(
+      Z, HashTables::New<CanonicalFunctionTypeSet>(dict_size, Heap::kOld));
+  for (intptr_t i = 0; i < function_types.Length(); i++) {
+    function_type ^= function_types.At(i);
+    bool present = function_types_table.Insert(function_type);
+    // Two recursive types with different topology (and hashes) may be equal.
+    ASSERT(!present || function_type.IsRecursive());
+  }
+  object_store->set_canonical_function_types(function_types_table.Release());
+
   // Rehash the canonical TypeParameters table.
   Array& typeparams = Array::Handle(Z);
   TypeParameter& typeparam = TypeParameter::Handle(Z);
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index e46d8e5..623bdb5 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -31,10 +31,6 @@
       FinalizationKind finalization = kCanonicalize,
       PendingTypes* pending_types = NULL);
 
-  // Finalize the types in the functions's signature.
-  static void FinalizeSignature(const Function& function,
-                                FinalizationKind finalization = kCanonicalize);
-
   // Return false if we still have classes pending to be finalized.
   static bool AllClassesFinalized();
 
@@ -78,8 +74,17 @@
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
  private:
+  // Finalize the types in the signature and the signature itself.
+  static AbstractTypePtr FinalizeSignature(
+      Zone* zone,
+      const FunctionType& signature,
+      FinalizationKind finalization = kCanonicalize,
+      PendingTypes* pending_types = NULL);
+
   static void AllocateEnumValues(const Class& enum_cls);
-  static void FinalizeTypeParameters(const Class& cls);
+  static void FinalizeTypeParameters(
+      const Class& cls,
+      FinalizationKind finalization = kCanonicalize);
   static intptr_t ExpandAndFinalizeTypeArguments(const AbstractType& type,
                                                  PendingTypes* pending_types);
   static void FinalizeTypeArguments(const Class& cls,
@@ -89,9 +94,6 @@
                                     TrailPtr trail);
   static void CheckRecursiveType(const AbstractType& type,
                                  PendingTypes* pending_types);
-  static void FinalizeUpperBounds(
-      const Class& cls,
-      FinalizationKind finalization = kCanonicalize);
   static void FinalizeMemberTypes(const Class& cls);
   static void PrintClassInformation(const Class& cls);
 
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index 8421944..741fc58 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -22,7 +22,6 @@
   V(PatchClass)                                                                \
   V(Function)                                                                  \
   V(ClosureData)                                                               \
-  V(SignatureData)                                                             \
   V(FfiTrampolineData)                                                         \
   V(Field)                                                                     \
   V(Script)                                                                    \
@@ -58,6 +57,7 @@
   V(TypeArguments)                                                             \
   V(AbstractType)                                                              \
   V(Type)                                                                      \
+  V(FunctionType)                                                              \
   V(TypeRef)                                                                   \
   V(TypeParameter)                                                             \
   V(Closure)                                                                   \
@@ -230,6 +230,7 @@
 bool IsTwoByteStringClassId(intptr_t index);
 bool IsExternalStringClassId(intptr_t index);
 bool IsBuiltinListClassId(intptr_t index);
+bool IsTypeClassId(intptr_t index);
 bool IsTypedDataBaseClassId(intptr_t index);
 bool IsTypedDataClassId(intptr_t index);
 bool IsTypedDataViewClassId(intptr_t index);
@@ -315,6 +316,11 @@
           (index == kByteBufferCid));
 }
 
+inline bool IsTypeClassId(intptr_t index) {
+  // Only Type and FunctionType can be encountered as instance types at runtime.
+  return index == kTypeCid || index == kFunctionTypeCid;
+}
+
 inline bool IsTypedDataBaseClassId(intptr_t index) {
   // Make sure this is updated when new TypedData types are added.
   COMPILE_ASSERT(kTypedDataInt8ArrayCid + 3 == kTypedDataUint8ArrayCid);
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 31c8d4f..ac7df11 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -776,7 +776,6 @@
       s->Push(data->ptr()->context_scope_);
     }
     s->Push(data->ptr()->parent_function_);
-    s->Push(data->ptr()->signature_type_);
     s->Push(data->ptr()->closure_);
     s->Push(data->ptr()->default_type_arguments_);
     s->Push(data->ptr()->default_type_arguments_info_);
@@ -801,7 +800,6 @@
         WriteField(data, context_scope_);
       }
       WriteField(data, parent_function_);
-      WriteField(data, signature_type_);
       WriteField(data, closure_);
       WriteField(data, default_type_arguments_);
       WriteField(data, default_type_arguments_info_);
@@ -841,7 +839,6 @@
             static_cast<ContextScopePtr>(d->ReadRef());
       }
       data->ptr()->parent_function_ = static_cast<FunctionPtr>(d->ReadRef());
-      data->ptr()->signature_type_ = static_cast<TypePtr>(d->ReadRef());
       data->ptr()->closure_ = static_cast<InstancePtr>(d->ReadRef());
       data->ptr()->default_type_arguments_ =
           static_cast<TypeArgumentsPtr>(d->ReadRef());
@@ -852,69 +849,6 @@
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-class SignatureDataSerializationCluster : public SerializationCluster {
- public:
-  SignatureDataSerializationCluster() : SerializationCluster("SignatureData") {}
-  ~SignatureDataSerializationCluster() {}
-
-  void Trace(Serializer* s, ObjectPtr object) {
-    SignatureDataPtr data = SignatureData::RawCast(object);
-    objects_.Add(data);
-    PushFromTo(data);
-  }
-
-  void WriteAlloc(Serializer* s) {
-    s->WriteCid(kSignatureDataCid);
-    const intptr_t count = objects_.length();
-    s->WriteUnsigned(count);
-    for (intptr_t i = 0; i < count; i++) {
-      SignatureDataPtr data = objects_[i];
-      s->AssignRef(data);
-    }
-  }
-
-  void WriteFill(Serializer* s) {
-    const intptr_t count = objects_.length();
-    for (intptr_t i = 0; i < count; i++) {
-      SignatureDataPtr data = objects_[i];
-      AutoTraceObject(data);
-      WriteFromTo(data);
-    }
-  }
-
- private:
-  GrowableArray<SignatureDataPtr> objects_;
-};
-#endif  // !DART_PRECOMPILED_RUNTIME
-
-class SignatureDataDeserializationCluster : public DeserializationCluster {
- public:
-  SignatureDataDeserializationCluster()
-      : DeserializationCluster("SignatureData") {}
-  ~SignatureDataDeserializationCluster() {}
-
-  void ReadAlloc(Deserializer* d, bool is_canonical) {
-    start_index_ = d->next_index();
-    PageSpace* old_space = d->heap()->old_space();
-    const intptr_t count = d->ReadUnsigned();
-    for (intptr_t i = 0; i < count; i++) {
-      d->AssignRef(
-          AllocateUninitialized(old_space, SignatureData::InstanceSize()));
-    }
-    stop_index_ = d->next_index();
-  }
-
-  void ReadFill(Deserializer* d, bool is_canonical) {
-    for (intptr_t id = start_index_; id < stop_index_; id++) {
-      SignatureDataPtr data = static_cast<SignatureDataPtr>(d->Ref(id));
-      Deserializer::InitializeHeader(data, kSignatureDataCid,
-                                     SignatureData::InstanceSize());
-      ReadFromTo(data);
-    }
-  }
-};
-
-#if !defined(DART_PRECOMPILED_RUNTIME)
 class FfiTrampolineDataSerializationCluster : public SerializationCluster {
  public:
   FfiTrampolineDataSerializationCluster()
@@ -3348,7 +3282,6 @@
   void WriteType(Serializer* s, TypePtr type) {
     AutoTraceObject(type);
     WriteFromTo(type);
-    s->WriteTokenPosition(type->ptr()->token_pos_);
     ASSERT(type->ptr()->type_state_ < (1 << TypeLayout::kTypeStateBitSize));
     ASSERT(type->ptr()->nullability_ < (1 << kNullabilityBitSize));
     static_assert(TypeLayout::kTypeStateBitSize + kNullabilityBitSize <=
@@ -3386,7 +3319,6 @@
       Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
                                      is_canonical);
       ReadFromTo(type);
-      type->ptr()->token_pos_ = d->ReadTokenPosition();
       const uint8_t combined = d->Read<uint8_t>();
       type->ptr()->type_state_ = combined >> kNullabilityBitSize;
       type->ptr()->nullability_ = combined & kNullabilityBitMask;
@@ -3429,6 +3361,124 @@
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
+class FunctionTypeSerializationCluster : public SerializationCluster {
+ public:
+  FunctionTypeSerializationCluster() : SerializationCluster("FunctionType") {}
+  ~FunctionTypeSerializationCluster() {}
+
+  void Trace(Serializer* s, ObjectPtr object) {
+    FunctionTypePtr type = FunctionType::RawCast(object);
+    objects_.Add(type);
+    PushFromTo(type);
+  }
+
+  void WriteAlloc(Serializer* s) {
+    s->WriteCid(kFunctionTypeCid);
+    intptr_t count = objects_.length();
+    s->WriteUnsigned(count);
+    for (intptr_t i = 0; i < count; i++) {
+      FunctionTypePtr type = objects_[i];
+      s->AssignRef(type);
+    }
+  }
+
+  void WriteFill(Serializer* s) {
+    intptr_t count = objects_.length();
+    for (intptr_t i = 0; i < count; i++) {
+      WriteFunctionType(s, objects_[i]);
+    }
+  }
+
+ private:
+  void WriteFunctionType(Serializer* s, FunctionTypePtr type) {
+    AutoTraceObject(type);
+    WriteFromTo(type);
+    ASSERT(type->ptr()->type_state_ <
+           (1 << FunctionTypeLayout::kTypeStateBitSize));
+    ASSERT(type->ptr()->nullability_ < (1 << kNullabilityBitSize));
+    static_assert(FunctionTypeLayout::kTypeStateBitSize + kNullabilityBitSize <=
+                      kBitsPerByte * sizeof(uint8_t),
+                  "Cannot pack type_state_ and nullability_ into a uint8_t");
+    const uint8_t combined = (type->ptr()->type_state_ << kNullabilityBitSize) |
+                             type->ptr()->nullability_;
+    ASSERT_EQUAL(type->ptr()->type_state_, combined >> kNullabilityBitSize);
+    ASSERT_EQUAL(type->ptr()->nullability_, combined & kNullabilityBitMask);
+    s->Write<uint8_t>(combined);
+    s->Write<uint32_t>(type->ptr()->packed_fields_);
+  }
+
+  GrowableArray<FunctionTypePtr> objects_;
+};
+#endif  // !DART_PRECOMPILED_RUNTIME
+
+class FunctionTypeDeserializationCluster : public DeserializationCluster {
+ public:
+  FunctionTypeDeserializationCluster()
+      : DeserializationCluster("FunctionType") {}
+  ~FunctionTypeDeserializationCluster() {}
+
+  void ReadAlloc(Deserializer* d, bool is_canonical) {
+    start_index_ = d->next_index();
+    PageSpace* old_space = d->heap()->old_space();
+    const intptr_t count = d->ReadUnsigned();
+    for (intptr_t i = 0; i < count; i++) {
+      d->AssignRef(
+          AllocateUninitialized(old_space, FunctionType::InstanceSize()));
+    }
+    stop_index_ = d->next_index();
+  }
+
+  void ReadFill(Deserializer* d, bool is_canonical) {
+    for (intptr_t id = start_index_; id < stop_index_; id++) {
+      FunctionTypePtr type = static_cast<FunctionTypePtr>(d->Ref(id));
+      Deserializer::InitializeHeader(
+          type, kFunctionTypeCid, FunctionType::InstanceSize(), is_canonical);
+      ReadFromTo(type);
+      const uint8_t combined = d->Read<uint8_t>();
+      type->ptr()->type_state_ = combined >> kNullabilityBitSize;
+      type->ptr()->nullability_ = combined & kNullabilityBitMask;
+      type->ptr()->packed_fields_ = d->Read<uint32_t>();
+    }
+  }
+
+  void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
+    if (is_canonical && (d->isolate() != Dart::vm_isolate())) {
+      CanonicalFunctionTypeSet table(
+          d->zone(),
+          d->isolate_group()->object_store()->canonical_function_types());
+      FunctionType& type = FunctionType::Handle(d->zone());
+      for (intptr_t i = start_index_; i < stop_index_; i++) {
+        type ^= refs.At(i);
+        ASSERT(type.IsCanonical());
+        bool present = table.Insert(type);
+        // Two recursive types with different topology (and hashes) may be
+        // equal.
+        ASSERT(!present || type.IsRecursive());
+      }
+      d->isolate_group()->object_store()->set_canonical_function_types(
+          table.Release());
+    }
+
+    FunctionType& type = FunctionType::Handle(d->zone());
+    Code& stub = Code::Handle(d->zone());
+
+    if (Snapshot::IncludesCode(d->kind())) {
+      for (intptr_t id = start_index_; id < stop_index_; id++) {
+        type ^= refs.At(id);
+        stub = type.type_test_stub();
+        type.SetTypeTestingStub(stub);  // Update type_test_stub_entry_point_
+      }
+    } else {
+      for (intptr_t id = start_index_; id < stop_index_; id++) {
+        type ^= refs.At(id);
+        stub = TypeTestingStubGenerator::DefaultCodeForType(type);
+        type.SetTypeTestingStub(stub);
+      }
+    }
+  }
+};
+
+#if !defined(DART_PRECOMPILED_RUNTIME)
 class TypeRefSerializationCluster : public SerializationCluster {
  public:
   TypeRefSerializationCluster() : SerializationCluster("TypeRef") {}
@@ -3544,8 +3594,8 @@
     AutoTraceObject(type);
     WriteFromTo(type);
     s->Write<int32_t>(type->ptr()->parameterized_class_id_);
-    s->WriteTokenPosition(type->ptr()->token_pos_);
-    s->Write<int16_t>(type->ptr()->index_);
+    s->Write<uint16_t>(type->ptr()->base_);
+    s->Write<uint16_t>(type->ptr()->index_);
     ASSERT(type->ptr()->flags_ < (1 << TypeParameterLayout::kFlagsBitSize));
     ASSERT(type->ptr()->nullability_ < (1 << kNullabilityBitSize));
     static_assert(TypeParameterLayout::kFlagsBitSize + kNullabilityBitSize <=
@@ -3586,8 +3636,8 @@
           type, kTypeParameterCid, TypeParameter::InstanceSize(), is_canonical);
       ReadFromTo(type);
       type->ptr()->parameterized_class_id_ = d->Read<int32_t>();
-      type->ptr()->token_pos_ = d->ReadTokenPosition();
-      type->ptr()->index_ = d->Read<int16_t>();
+      type->ptr()->base_ = d->Read<uint16_t>();
+      type->ptr()->index_ = d->Read<uint16_t>();
       const uint8_t combined = d->Read<uint8_t>();
       type->ptr()->flags_ = combined >> kNullabilityBitSize;
       type->ptr()->nullability_ = combined & kNullabilityBitMask;
@@ -3603,10 +3653,8 @@
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         type_param ^= refs.At(i);
         ASSERT(type_param.IsCanonical());
-        if (!type_param.IsDeclaration()) {
-          bool present = table.Insert(type_param);
-          ASSERT(!present);
-        }
+        bool present = table.Insert(type_param);
+        ASSERT(!present);
       }
       d->isolate_group()->object_store()->set_canonical_type_parameters(
           table.Release());
@@ -4949,6 +4997,7 @@
         object_store_(object_store),
         saved_symbol_table_(Array::Handle()),
         saved_canonical_types_(Array::Handle()),
+        saved_canonical_function_types_(Array::Handle()),
         saved_canonical_type_parameters_(Array::Handle()),
         saved_canonical_type_arguments_(Array::Handle()),
         dispatch_table_entries_(Array::Handle()) {
@@ -4960,6 +5009,10 @@
     object_store->set_canonical_types(
         Array::Handle(HashTables::New<CanonicalTypeSet>(4)));
 
+    saved_canonical_function_types_ = object_store->canonical_function_types();
+    object_store->set_canonical_function_types(
+        Array::Handle(HashTables::New<CanonicalFunctionTypeSet>(4)));
+
     saved_canonical_type_parameters_ =
         object_store->canonical_type_parameters();
     object_store->set_canonical_type_parameters(
@@ -4972,6 +5025,8 @@
   ~ProgramSerializationRoots() {
     object_store_->set_symbol_table(saved_symbol_table_);
     object_store_->set_canonical_types(saved_canonical_types_);
+    object_store_->set_canonical_function_types(
+        saved_canonical_function_types_);
     object_store_->set_canonical_type_parameters(
         saved_canonical_type_parameters_);
     object_store_->set_canonical_type_arguments(
@@ -5033,6 +5088,7 @@
   ObjectStore* object_store_;
   Array& saved_symbol_table_;
   Array& saved_canonical_types_;
+  Array& saved_canonical_function_types_;
   Array& saved_canonical_type_parameters_;
   Array& saved_canonical_type_arguments_;
   Array& dispatch_table_entries_;
@@ -5494,8 +5550,6 @@
       return new (Z) FunctionSerializationCluster();
     case kClosureDataCid:
       return new (Z) ClosureDataSerializationCluster();
-    case kSignatureDataCid:
-      return new (Z) SignatureDataSerializationCluster();
     case kFfiTrampolineDataCid:
       return new (Z) FfiTrampolineDataSerializationCluster();
     case kFieldCid:
@@ -5538,6 +5592,8 @@
       return new (Z) LibraryPrefixSerializationCluster();
     case kTypeCid:
       return new (Z) TypeSerializationCluster();
+    case kFunctionTypeCid:
+      return new (Z) FunctionTypeSerializationCluster();
     case kTypeRefCid:
       return new (Z) TypeRefSerializationCluster();
     case kTypeParameterCid:
@@ -6194,8 +6250,6 @@
       return new (Z) FunctionDeserializationCluster();
     case kClosureDataCid:
       return new (Z) ClosureDataDeserializationCluster();
-    case kSignatureDataCid:
-      return new (Z) SignatureDataDeserializationCluster();
     case kFfiTrampolineDataCid:
       return new (Z) FfiTrampolineDataDeserializationCluster();
     case kFieldCid:
@@ -6240,6 +6294,8 @@
       return new (Z) LibraryPrefixDeserializationCluster();
     case kTypeCid:
       return new (Z) TypeDeserializationCluster();
+    case kFunctionTypeCid:
+      return new (Z) FunctionTypeDeserializationCluster();
     case kTypeRefCid:
       return new (Z) TypeRefDeserializationCluster();
     case kTypeParameterCid:
diff --git a/runtime/vm/code_patcher_arm64_test.cc b/runtime/vm/code_patcher_arm64_test.cc
index d5d33e7..7d3ddc1 100644
--- a/runtime/vm/code_patcher_arm64_test.cc
+++ b/runtime/vm/code_patcher_arm64_test.cc
@@ -28,9 +28,10 @@
       Library::Handle(), class_name, script, TokenPosition::kNoSource));
   const String& function_name =
       String::Handle(Symbols::New(thread, "callerFunction"));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   const Function& function = Function::Handle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kNoSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kNoSource));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const intptr_t kTypeArgsLen = 0;
diff --git a/runtime/vm/code_patcher_arm_test.cc b/runtime/vm/code_patcher_arm_test.cc
index 3d1c56f..6e30b8e 100644
--- a/runtime/vm/code_patcher_arm_test.cc
+++ b/runtime/vm/code_patcher_arm_test.cc
@@ -28,9 +28,10 @@
       Library::Handle(), class_name, script, TokenPosition::kNoSource));
   const String& function_name =
       String::Handle(Symbols::New(thread, "callerFunction"));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   const Function& function = Function::Handle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kNoSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kNoSource));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const intptr_t kTypeArgsLen = 0;
diff --git a/runtime/vm/code_patcher_ia32_test.cc b/runtime/vm/code_patcher_ia32_test.cc
index 812f485..ed7a48b 100644
--- a/runtime/vm/code_patcher_ia32_test.cc
+++ b/runtime/vm/code_patcher_ia32_test.cc
@@ -28,9 +28,10 @@
       Library::Handle(), class_name, script, TokenPosition::kNoSource));
   const String& function_name =
       String::Handle(Symbols::New(thread, "callerFunction"));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   const Function& function = Function::Handle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kNoSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kNoSource));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const intptr_t kTypeArgsLen = 0;
diff --git a/runtime/vm/code_patcher_x64_test.cc b/runtime/vm/code_patcher_x64_test.cc
index d00b53c..2daf04c 100644
--- a/runtime/vm/code_patcher_x64_test.cc
+++ b/runtime/vm/code_patcher_x64_test.cc
@@ -28,9 +28,10 @@
       Library::Handle(), class_name, script, TokenPosition::kNoSource));
   const String& function_name =
       String::Handle(Symbols::New(thread, "callerFunction"));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   const Function& function = Function::Handle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kNoSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kNoSource));
 
   const String& target_name = String::Handle(String::New("targetFunction"));
   const intptr_t kTypeArgsLen = 0;
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index efc9d68..33bb8f0 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -168,7 +168,7 @@
   const Function& target = Function::ZoneHandle(Z, function.raw());
   StaticCallInstr* static_call =
       StaticCallInstr::FromCall(Z, call, target, call->CallCount());
-  static_call->SetResultType(Z, CompileType::FromCid(kTypeCid));
+  // Since the result is either a Type or a FunctionType, we cannot pin it.
   call->ReplaceWith(static_call, current_iterator());
   return true;
 }
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 70b1efa..7aad2ee 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -163,6 +163,8 @@
       dropped_class_count_(0),
       dropped_typearg_count_(0),
       dropped_type_count_(0),
+      dropped_functiontype_count_(0),
+      dropped_typeparam_count_(0),
       dropped_library_count_(0),
       libraries_(GrowableObjectArray::Handle(
           isolate_->group()->object_store()->libraries())),
@@ -178,6 +180,7 @@
       classes_to_retain_(),
       typeargs_to_retain_(),
       types_to_retain_(),
+      functiontypes_to_retain_(),
       typeparams_to_retain_(),
       consts_to_retain_(),
       seen_table_selectors_(),
@@ -400,6 +403,7 @@
       DropFields();
       TraceTypesFromRetainedClasses();
       DropTypes();
+      DropFunctionTypes();
       DropTypeParameters();
       DropTypeArguments();
 
@@ -460,6 +464,8 @@
     THR_Print(" %" Pd " fields,", dropped_field_count_);
     THR_Print(" %" Pd " symbols,", symbols_before - symbols_after);
     THR_Print(" %" Pd " types,", dropped_type_count_);
+    THR_Print(" %" Pd " function types,", dropped_functiontype_count_);
+    THR_Print(" %" Pd " type parameters,", dropped_typeparam_count_);
     THR_Print(" %" Pd " type arguments,", dropped_typearg_count_);
     THR_Print(" %" Pd " classes,", dropped_class_count_);
     THR_Print(" %" Pd " libraries.\n", dropped_library_count_);
@@ -481,6 +487,7 @@
       if (FLAG_trace_precompiler) {
         THR_Print("Precompiling constructor %s\n", function.ToCString());
       }
+      ASSERT(Class::Handle(zone_, function.Owner()).is_finalized());
       CompileFunction(precompiler_, Thread::Current(), zone_, function);
     }
 
@@ -558,7 +565,7 @@
   Class& subcls = Class::Handle(Z);
   Array& fields = Array::Handle(Z);
   Field& field = Field::Handle(Z);
-  Function& function = Function::Handle(Z);
+  FunctionType& signature = FunctionType::Handle(Z);
   Function& dispatcher = Function::Handle(Z);
   Array& args_desc = Array::Handle(Z);
   AbstractType& field_type = AbstractType::Handle(Z);
@@ -583,9 +590,9 @@
         if (!IsSent(field_name)) continue;
         // Create arguments descriptor with fixed parameters from
         // signature of field_type.
-        function = Type::Cast(field_type).signature();
-        if (function.IsGeneric()) continue;
-        if (function.HasOptionalParameters()) continue;
+        signature ^= field_type.raw();
+        if (signature.IsGeneric()) continue;
+        if (signature.HasOptionalParameters()) continue;
         if (FLAG_trace_precompiler) {
           THR_Print("Found callback field %s\n", field_name.ToCString());
         }
@@ -595,7 +602,7 @@
         // unboxed parameters.
         args_desc =
             ArgumentsDescriptor::NewBoxed(0,  // No type argument vector.
-                                          function.num_fixed_parameters());
+                                          signature.num_fixed_parameters());
         cids.Clear();
         if (CHA::ConcreteSubclasses(cls, &cids)) {
           for (intptr_t j = 0; j < cids.length(); ++j) {
@@ -623,6 +630,9 @@
       FLAG_use_bare_instructions ? global_object_pool_builder()->CurrentLength()
                                  : 0;
   RELEASE_ASSERT(!function.HasCode());
+  // Ffi trampoline functions have no signature.
+  ASSERT(function.kind() == FunctionLayout::kFfiTrampoline ||
+         FunctionType::Handle(Z, function.signature()).IsFinalized());
 
   TracingScope tracing_scope(this);
   function_count_++;
@@ -773,10 +783,6 @@
 
   type = cls.super_type();
   AddType(type);
-
-  if (cls.IsTypedefClass()) {
-    AddTypesOf(Function::Handle(Z, cls.signature_function()));
-  }
 }
 
 void Precompiler::AddTypesOf(const Function& function) {
@@ -784,15 +790,10 @@
   if (functions_to_retain_.ContainsKey(function)) return;
   functions_to_retain_.Insert(function);
 
-  AddTypeArguments(TypeArguments::Handle(Z, function.type_parameters()));
+  const FunctionType& signature = FunctionType::Handle(Z, function.signature());
+  AddType(signature);
 
   AbstractType& type = AbstractType::Handle(Z);
-  type = function.result_type();
-  AddType(type);
-  for (intptr_t i = 0; i < function.NumParameters(); i++) {
-    type = function.ParameterTypeAt(i);
-    AddType(type);
-  }
   // At this point, ensure any cached default type arguments are canonicalized.
   function.UpdateCachedDefaultTypeArguments(thread());
   if (function.CachesDefaultTypeArguments()) {
@@ -802,19 +803,16 @@
     AddTypeArguments(defaults);
   }
   Code& code = Code::Handle(Z, function.CurrentCode());
-  if (code.IsNull()) {
-    ASSERT(function.kind() == FunctionLayout::kSignatureFunction);
-  } else {
-    const ExceptionHandlers& handlers =
-        ExceptionHandlers::Handle(Z, code.exception_handlers());
-    if (!handlers.IsNull()) {
-      Array& types = Array::Handle(Z);
-      for (intptr_t i = 0; i < handlers.num_entries(); i++) {
-        types = handlers.GetHandledTypes(i);
-        for (intptr_t j = 0; j < types.Length(); j++) {
-          type ^= types.At(j);
-          AddType(type);
-        }
+  ASSERT(!code.IsNull());
+  const ExceptionHandlers& handlers =
+      ExceptionHandlers::Handle(Z, code.exception_handlers());
+  if (!handlers.IsNull()) {
+    Array& types = Array::Handle(Z);
+    for (intptr_t i = 0; i < handlers.num_entries(); i++) {
+      types = handlers.GetHandledTypes(i);
+      for (intptr_t j = 0; j < types.Length(); j++) {
+        type ^= types.At(j);
+        AddType(type);
       }
     }
   }
@@ -824,12 +822,6 @@
   if (!parent.IsNull()) {
     AddTypesOf(parent);
   }
-  if (function.IsSignatureFunction() || function.IsClosureFunction()) {
-    type = function.ExistingSignatureType();
-    if (!type.IsNull()) {
-      AddType(type);
-    }
-  }
   // A class may have all functions inlined except a local function.
   const Class& owner = Class::Handle(Z, function.Owner());
   AddTypesOf(owner);
@@ -847,10 +839,24 @@
     AddType(type);
     type = param.default_argument();
     AddType(type);
-    const auto& function = Function::Handle(Z, param.parameterized_function());
-    AddTypesOf(function);
-    const Class& cls = Class::Handle(Z, param.parameterized_class());
-    AddTypesOf(cls);
+    return;
+  }
+
+  if (abstype.IsFunctionType()) {
+    if (functiontypes_to_retain_.HasKey(&FunctionType::Cast(abstype))) return;
+    const FunctionType& signature =
+        FunctionType::ZoneHandle(Z, FunctionType::Cast(abstype).raw());
+    functiontypes_to_retain_.Insert(&signature);
+
+    AddTypeArguments(TypeArguments::Handle(Z, signature.type_parameters()));
+
+    AbstractType& type = AbstractType::Handle(Z);
+    type = signature.result_type();
+    AddType(type);
+    for (intptr_t i = 0; i < signature.NumParameters(); i++) {
+      type = signature.ParameterTypeAt(i);
+      AddType(type);
+    }
     return;
   }
 
@@ -863,10 +869,6 @@
     AddTypesOf(cls);
     const TypeArguments& vector = TypeArguments::Handle(Z, abstype.arguments());
     AddTypeArguments(vector);
-    if (type.IsFunctionType()) {
-      const Function& func = Function::Handle(Z, type.signature());
-      AddTypesOf(func);
-    }
   } else if (abstype.IsTypeRef()) {
     AbstractType& type = AbstractType::Handle(Z);
     type = TypeRef::Cast(abstype).type();
@@ -1859,7 +1861,9 @@
           : type_(AbstractType::Handle(zone)), types_(types) {}
 
       void VisitObject(ObjectPtr obj) {
-        if (obj->GetClassId() == kTypeCid || obj->GetClassId() == kTypeRefCid) {
+        if (obj->GetClassId() == kTypeCid ||
+            obj->GetClassId() == kFunctionTypeCid ||
+            obj->GetClassId() == kTypeRefCid) {
           type_ ^= obj;
           types_->Add(type_);
         }
@@ -1948,6 +1952,45 @@
   object_store->set_canonical_types(types_table.Release());
 }
 
+void Precompiler::DropFunctionTypes() {
+  ObjectStore* object_store = IG->object_store();
+  GrowableObjectArray& retained_types =
+      GrowableObjectArray::Handle(Z, GrowableObjectArray::New());
+  Array& types_array = Array::Handle(Z);
+  FunctionType& type = FunctionType::Handle(Z);
+  // First drop all the function types that are not referenced.
+  {
+    CanonicalFunctionTypeSet types_table(
+        Z, object_store->canonical_function_types());
+    types_array = HashTables::ToArray(types_table, false);
+    for (intptr_t i = 0; i < types_array.Length(); i++) {
+      type ^= types_array.At(i);
+      bool retain = functiontypes_to_retain_.HasKey(&type);
+      if (retain) {
+        retained_types.Add(type);
+      } else {
+        type.ClearCanonical();
+        dropped_functiontype_count_++;
+      }
+    }
+    types_table.Release();
+  }
+
+  // Now construct a new function type table and save in the object store.
+  const intptr_t dict_size =
+      Utils::RoundUpToPowerOfTwo(retained_types.Length() * 4 / 3);
+  types_array =
+      HashTables::New<CanonicalFunctionTypeSet>(dict_size, Heap::kOld);
+  CanonicalFunctionTypeSet types_table(Z, types_array.raw());
+  bool present;
+  for (intptr_t i = 0; i < retained_types.Length(); i++) {
+    type ^= retained_types.At(i);
+    present = types_table.Insert(type);
+    ASSERT(!present);
+  }
+  object_store->set_canonical_function_types(types_table.Release());
+}
+
 void Precompiler::DropTypeParameters() {
   ObjectStore* object_store = IG->object_store();
   GrowableObjectArray& retained_typeparams =
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h
index 32cfe14..4c722f9 100644
--- a/runtime/vm/compiler/aot/precompiler.h
+++ b/runtime/vm/compiler/aot/precompiler.h
@@ -146,6 +146,26 @@
 
 typedef DirectChainedHashMap<AbstractTypeKeyValueTrait> AbstractTypeSet;
 
+class FunctionTypeKeyValueTrait {
+ public:
+  // Typedefs needed for the DirectChainedHashMap template.
+  typedef const FunctionType* Key;
+  typedef const FunctionType* Value;
+  typedef const FunctionType* Pair;
+
+  static Key KeyOf(Pair kv) { return kv; }
+
+  static Value ValueOf(Pair kv) { return kv; }
+
+  static inline intptr_t Hashcode(Key key) { return key->Hash(); }
+
+  static inline bool IsKeyEqual(Pair pair, Key key) {
+    return pair->raw() == key->raw();
+  }
+};
+
+typedef DirectChainedHashMap<FunctionTypeKeyValueTrait> FunctionTypeSet;
+
 class TypeParameterKeyValueTrait {
  public:
   // Typedefs needed for the DirectChainedHashMap template.
@@ -306,6 +326,7 @@
   void DropFields();
   void TraceTypesFromRetainedClasses();
   void DropTypes();
+  void DropFunctionTypes();
   void DropTypeParameters();
   void DropTypeArguments();
   void DropMetadata();
@@ -347,6 +368,7 @@
   intptr_t dropped_class_count_;
   intptr_t dropped_typearg_count_;
   intptr_t dropped_type_count_;
+  intptr_t dropped_functiontype_count_;
   intptr_t dropped_typeparam_count_;
   intptr_t dropped_library_count_;
 
@@ -361,6 +383,7 @@
   ClassSet classes_to_retain_;
   TypeArgumentsSet typeargs_to_retain_;
   AbstractTypeSet types_to_retain_;
+  FunctionTypeSet functiontypes_to_retain_;
   TypeParameterSet typeparams_to_retain_;
   InstanceSet consts_to_retain_;
   TableSelectorSet seen_table_selectors_;
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc
index 042d3f0..601d315 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc
@@ -1443,10 +1443,18 @@
              kIfNotInRange, target);
 }
 
+static void JumpIfNotType(Assembler* assembler,
+                          Register cid,
+                          Register tmp,
+                          Label* target) {
+  RangeCheck(assembler, cid, tmp, kTypeCid, kFunctionTypeCid, kIfNotInRange,
+             target);
+}
+
 // Return type quickly for simple types (not parameterized and not signature).
 void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
                                         Label* normal_ir_body) {
-  Label use_declaration_type, not_double, not_integer;
+  Label use_declaration_type, not_double, not_integer, not_string;
   __ ldr(R0, Address(SP, 0 * target::kWordSize));
   __ LoadClassIdMayBeSmi(R1, R0);
 
@@ -1472,12 +1480,19 @@
   __ Ret();
 
   __ Bind(&not_integer);
-  JumpIfNotString(assembler, R1, R0, &use_declaration_type);
+  JumpIfNotString(assembler, R1, R0, &not_string);
   __ LoadIsolate(R0);
   __ LoadFromOffset(R0, R0, target::Isolate::cached_object_store_offset());
   __ LoadFromOffset(R0, R0, target::ObjectStore::string_type_offset());
   __ Ret();
 
+  __ Bind(&not_string);
+  JumpIfNotType(assembler, R1, R0, &use_declaration_type);
+  __ LoadIsolate(R0);
+  __ LoadFromOffset(R0, R0, target::Isolate::cached_object_store_offset());
+  __ LoadFromOffset(R0, R0, target::ObjectStore::type_type_offset());
+  __ Ret();
+
   __ Bind(&use_declaration_type);
   __ LoadClassById(R2, R1);
   __ ldrh(R3, FieldAddress(R2, target::Class::num_type_arguments_offset()));
@@ -1577,8 +1592,8 @@
   __ ldr(R0, Address(SP, 0 * target::kWordSize));
   __ ldr(R0, FieldAddress(R0, target::String::hash_offset()));
   __ cmp(R0, Operand(0));
-  READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, NE));  // Hash not yet computed.
-  __ Bind(normal_ir_body);
+  READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, NE));
+  __ Bind(normal_ir_body);  // Hash not yet computed.
 }
 
 void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
@@ -1586,8 +1601,8 @@
   __ ldr(R0, Address(SP, 0 * target::kWordSize));
   __ ldr(R0, FieldAddress(R0, target::Type::hash_offset()));
   __ cmp(R0, Operand(0));
-  READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, NE));  // Hash not yet computed.
-  __ Bind(normal_ir_body);
+  READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, NE));
+  __ Bind(normal_ir_body);  // Hash not yet computed.
 }
 
 void AsmIntrinsifier::Type_equality(Assembler* assembler,
@@ -1642,6 +1657,27 @@
   __ Bind(normal_ir_body);
 }
 
+void AsmIntrinsifier::FunctionType_getHashCode(Assembler* assembler,
+                                               Label* normal_ir_body) {
+  __ ldr(R0, Address(SP, 0 * target::kWordSize));
+  __ ldr(R0, FieldAddress(R0, target::FunctionType::hash_offset()));
+  __ cmp(R0, Operand(0));
+  READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, NE));
+  __ Bind(normal_ir_body);  // Hash not yet computed.
+}
+
+void AsmIntrinsifier::FunctionType_equality(Assembler* assembler,
+                                            Label* normal_ir_body) {
+  __ ldm(IA, SP, (1 << R1 | 1 << R2));
+  __ cmp(R1, Operand(R2));
+  __ b(normal_ir_body, NE);
+
+  __ LoadObject(R0, CastHandle<Object>(TrueObject()));
+  __ Ret();
+
+  __ Bind(normal_ir_body);
+}
+
 void GenerateSubstringMatchesSpecialization(Assembler* assembler,
                                             intptr_t receiver_cid,
                                             intptr_t other_cid,
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index ab4430c..fac06c9 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1513,10 +1513,18 @@
              kIfNotInRange, target);
 }
 
+static void JumpIfNotType(Assembler* assembler,
+                          Register cid,
+                          Register tmp,
+                          Label* target) {
+  RangeCheck(assembler, cid, tmp, kTypeCid, kFunctionTypeCid, kIfNotInRange,
+             target);
+}
+
 // Return type quickly for simple types (not parameterized and not signature).
 void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
                                         Label* normal_ir_body) {
-  Label use_declaration_type, not_double, not_integer;
+  Label use_declaration_type, not_double, not_integer, not_string;
   __ ldr(R0, Address(SP, 0 * target::kWordSize));
   __ LoadClassIdMayBeSmi(R1, R0);
 
@@ -1542,12 +1550,19 @@
   __ ret();
 
   __ Bind(&not_integer);
-  JumpIfNotString(assembler, R1, R0, &use_declaration_type);
+  JumpIfNotString(assembler, R1, R0, &not_string);
   __ LoadIsolate(R0);
   __ LoadFromOffset(R0, R0, target::Isolate::cached_object_store_offset());
   __ LoadFromOffset(R0, R0, target::ObjectStore::string_type_offset());
   __ ret();
 
+  __ Bind(&not_string);
+  JumpIfNotType(assembler, R1, R0, &use_declaration_type);
+  __ LoadIsolate(R0);
+  __ LoadFromOffset(R0, R0, target::Isolate::cached_object_store_offset());
+  __ LoadFromOffset(R0, R0, target::ObjectStore::type_type_offset());
+  __ ret();
+
   __ Bind(&use_declaration_type);
   __ LoadClassById(R2, R1);
   __ ldr(
@@ -1723,6 +1738,28 @@
   __ Bind(normal_ir_body);
 }
 
+void AsmIntrinsifier::FunctionType_getHashCode(Assembler* assembler,
+                                               Label* normal_ir_body) {
+  __ ldr(R0, Address(SP, 0 * target::kWordSize));
+  __ ldr(R0, FieldAddress(R0, target::FunctionType::hash_offset()));
+  __ cbz(normal_ir_body, R0);
+  __ ret();
+  // Hash not yet computed.
+  __ Bind(normal_ir_body);
+}
+
+void AsmIntrinsifier::FunctionType_equality(Assembler* assembler,
+                                            Label* normal_ir_body) {
+  __ ldp(R1, R2, Address(SP, 0 * target::kWordSize, Address::PairOffset));
+  __ cmp(R1, Operand(R2));
+  __ b(normal_ir_body, NE);
+
+  __ LoadObject(R0, CastHandle<Object>(TrueObject()));
+  __ ret();
+
+  __ Bind(normal_ir_body);
+}
+
 void AsmIntrinsifier::Object_getHash(Assembler* assembler,
                                      Label* normal_ir_body) {
   __ ldr(R0, Address(SP, 0 * target::kWordSize));
diff --git a/runtime/vm/compiler/asm_intrinsifier_ia32.cc b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
index ec97c64..e97ea6e 100644
--- a/runtime/vm/compiler/asm_intrinsifier_ia32.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
@@ -1538,10 +1538,14 @@
              kIfNotInRange, target);
 }
 
+static void JumpIfNotType(Assembler* assembler, Register cid, Label* target) {
+  RangeCheck(assembler, cid, kTypeCid, kFunctionTypeCid, kIfNotInRange, target);
+}
+
 // Return type quickly for simple types (not parameterized and not signature).
 void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
                                         Label* normal_ir_body) {
-  Label use_declaration_type, not_double, not_integer;
+  Label use_declaration_type, not_double, not_integer, not_string;
   __ movl(EAX, Address(ESP, +1 * target::kWordSize));
   __ LoadClassIdMayBeSmi(EDI, EAX);
 
@@ -1574,14 +1578,24 @@
   // If object is a string (one byte, two byte or external variants) return
   // string type.
   __ movl(EAX, EDI);
-  JumpIfNotString(assembler, EAX, &use_declaration_type);
+  JumpIfNotString(assembler, EAX, &not_string);
 
   __ LoadIsolate(EAX);
   __ movl(EAX, Address(EAX, target::Isolate::cached_object_store_offset()));
   __ movl(EAX, Address(EAX, target::ObjectStore::string_type_offset()));
   __ ret();
 
-  // Object is neither double, nor integer, nor string.
+  __ Bind(&not_string);
+  // If object is a type or function type, return Dart type.
+  __ movl(EAX, EDI);
+  JumpIfNotType(assembler, EAX, &use_declaration_type);
+
+  __ LoadIsolate(EAX);
+  __ movl(EAX, Address(EAX, target::Isolate::cached_object_store_offset()));
+  __ movl(EAX, Address(EAX, target::ObjectStore::type_type_offset()));
+  __ ret();
+
+  // Object is neither double, nor integer, nor string, nor type.
   __ Bind(&use_declaration_type);
   __ LoadClassById(EBX, EDI);
   __ movzxw(EDI, FieldAddress(EBX, target::Class::num_type_arguments_offset()));
@@ -1752,6 +1766,30 @@
   __ Bind(normal_ir_body);
 }
 
+void AsmIntrinsifier::FunctionType_getHashCode(Assembler* assembler,
+                                               Label* normal_ir_body) {
+  __ movl(EAX, Address(ESP, +1 * target::kWordSize));  // FunctionType object.
+  __ movl(EAX, FieldAddress(EAX, target::FunctionType::hash_offset()));
+  __ testl(EAX, EAX);
+  __ j(EQUAL, normal_ir_body, Assembler::kNearJump);
+  __ ret();
+  __ Bind(normal_ir_body);
+  // Hash not yet computed.
+}
+
+void AsmIntrinsifier::FunctionType_equality(Assembler* assembler,
+                                            Label* normal_ir_body) {
+  __ movl(EDI, Address(ESP, +1 * target::kWordSize));
+  __ movl(EBX, Address(ESP, +2 * target::kWordSize));
+  __ cmpl(EDI, EBX);
+  __ j(NOT_EQUAL, normal_ir_body);
+
+  __ LoadObject(EAX, CastHandle<Object>(TrueObject()));
+  __ ret();
+
+  __ Bind(normal_ir_body);
+}
+
 // bool _substringMatches(int start, String other)
 void AsmIntrinsifier::StringBaseSubstringMatches(Assembler* assembler,
                                                  Label* normal_ir_body) {
diff --git a/runtime/vm/compiler/asm_intrinsifier_x64.cc b/runtime/vm/compiler/asm_intrinsifier_x64.cc
index 8a424dd..e4329c4 100644
--- a/runtime/vm/compiler/asm_intrinsifier_x64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_x64.cc
@@ -1444,10 +1444,13 @@
              kIfNotInRange, target);
 }
 
+static void JumpIfNotType(Assembler* assembler, Register cid, Label* target) {
+  RangeCheck(assembler, cid, kTypeCid, kFunctionTypeCid, kIfNotInRange, target);
+}
 // Return type quickly for simple types (not parameterized and not signature).
 void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
                                         Label* normal_ir_body) {
-  Label use_declaration_type, not_integer, not_double;
+  Label use_declaration_type, not_integer, not_double, not_string;
   __ movq(RAX, Address(RSP, +1 * target::kWordSize));
   __ LoadClassIdMayBeSmi(RCX, RAX);
 
@@ -1481,14 +1484,24 @@
   // If object is a string (one byte, two byte or external variants) return
   // string type.
   __ movq(RAX, RCX);
-  JumpIfNotString(assembler, RAX, &use_declaration_type);
+  JumpIfNotString(assembler, RAX, &not_string);
 
   __ LoadIsolate(RAX);
   __ movq(RAX, Address(RAX, target::Isolate::cached_object_store_offset()));
   __ movq(RAX, Address(RAX, target::ObjectStore::string_type_offset()));
   __ ret();
 
-  // Object is neither double, nor integer, nor string.
+  __ Bind(&not_string);
+  // If object is a type or function type, return Dart type.
+  __ movq(RAX, RCX);
+  JumpIfNotType(assembler, RAX, &use_declaration_type);
+
+  __ LoadIsolate(RAX);
+  __ movq(RAX, Address(RAX, target::Isolate::cached_object_store_offset()));
+  __ movq(RAX, Address(RAX, target::ObjectStore::type_type_offset()));
+  __ ret();
+
+  // Object is neither double, nor integer, nor string, nor type.
   __ Bind(&use_declaration_type);
   __ LoadClassById(RDI, RCX);
   __ movzxw(RCX, FieldAddress(RDI, target::Class::num_type_arguments_offset()));
@@ -1663,6 +1676,32 @@
   __ Bind(normal_ir_body);
 }
 
+void AsmIntrinsifier::FunctionType_getHashCode(Assembler* assembler,
+                                               Label* normal_ir_body) {
+  __ movq(RAX, Address(RSP, +1 * target::kWordSize));  // FunctionType object.
+  __ movq(RAX, FieldAddress(RAX, target::FunctionType::hash_offset()));
+  ASSERT(kSmiTag == 0);
+  ASSERT(kSmiTagShift == 1);
+  __ testq(RAX, RAX);
+  __ j(ZERO, normal_ir_body, Assembler::kNearJump);
+  __ ret();
+  __ Bind(normal_ir_body);
+  // Hash not yet computed.
+}
+
+void AsmIntrinsifier::FunctionType_equality(Assembler* assembler,
+                                            Label* normal_ir_body) {
+  __ movq(RCX, Address(RSP, +1 * target::kWordSize));
+  __ movq(RDX, Address(RSP, +2 * target::kWordSize));
+  __ cmpq(RCX, RDX);
+  __ j(NOT_EQUAL, normal_ir_body);
+
+  __ LoadObject(RAX, CastHandle<Object>(TrueObject()));
+  __ ret();
+
+  __ Bind(normal_ir_body);
+}
+
 void AsmIntrinsifier::Object_getHash(Assembler* assembler,
                                      Label* normal_ir_body) {
   __ movq(RAX, Address(RSP, +1 * target::kWordSize));  // Object.
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 4f7810b9..6108d29 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -2480,8 +2480,7 @@
   AbstractType& bound = AbstractType::Handle(zone(), type_param.bound());
   bound = bound.UnwrapFutureOr();
   return !bound.IsTopTypeForSubtyping() && !bound.IsObjectType() &&
-                 !bound.IsFunctionType() && !bound.IsDartFunctionType() &&
-                 bound.IsType()
+                 !bound.IsDartFunctionType() && bound.IsType()
              ? kTestTypeFiveArgs
              : kTestTypeSevenArgs;
 }
@@ -3037,6 +3036,10 @@
     return output_dst_type();
   }
 
+  if (dst_type.IsFunctionType()) {
+    return output_dst_type();
+  }
+
   if (auto const hi = thread()->hierarchy_info()) {
     const Class& type_class = Class::Handle(zone(), dst_type.type_class());
 
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index cbf6c5c..318ee1f 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -354,8 +354,7 @@
 bool HierarchyInfo::CanUseSubtypeRangeCheckFor(const AbstractType& type) {
   ASSERT(type.IsFinalized());
 
-  if (!type.IsInstantiated() || !type.IsType() || type.IsFunctionType() ||
-      type.IsDartFunctionType()) {
+  if (!type.IsInstantiated() || !type.IsType() || type.IsDartFunctionType()) {
     return false;
   }
 
@@ -398,7 +397,7 @@
     const AbstractType& type) {
   ASSERT(type.IsFinalized());
 
-  if (!type.IsType() || type.IsFunctionType() || type.IsDartFunctionType()) {
+  if (!type.IsType() || type.IsDartFunctionType()) {
     return false;
   }
 
@@ -2744,8 +2743,10 @@
     case Slot::Kind::kFunction_kind_tag:
     case Slot::Kind::kFunction_packed_fields:
     case Slot::Kind::kFunction_parameter_names:
-    case Slot::Kind::kFunction_parameter_types:
-    case Slot::Kind::kFunction_type_parameters:
+    case Slot::Kind::kFunction_signature:
+    case Slot::Kind::kFunctionType_packed_fields:
+    case Slot::Kind::kFunctionType_parameter_types:
+    case Slot::Kind::kFunctionType_type_parameters:
     case Slot::Kind::kPointerBase_data_field:
     case Slot::Kind::kType_arguments:
     case Slot::Kind::kTypeArgumentsIndex:
@@ -5171,6 +5172,7 @@
   bool is_string = true;
   bool is_integer = true;
   bool is_double = true;
+  bool is_type = true;
 
   const intptr_t num_checks = targets.length();
   for (intptr_t i = 0; i < num_checks; i++) {
@@ -5182,18 +5184,24 @@
       is_string = is_string && IsStringClassId(cid);
       is_integer = is_integer && IsIntegerClassId(cid);
       is_double = is_double && (cid == kDoubleCid);
+      is_type = is_type && IsTypeClassId(cid);
     }
   }
 
   if (is_string) {
     ASSERT(!is_integer);
     ASSERT(!is_double);
+    ASSERT(!is_type);
     return Type::StringType();
   } else if (is_integer) {
     ASSERT(!is_double);
+    ASSERT(!is_type);
     return Type::IntType();
   } else if (is_double) {
+    ASSERT(!is_type);
     return Type::Double();
+  } else if (is_type) {
+    return Type::DartTypeType();
   }
 
   return Type::null();
diff --git a/runtime/vm/compiler/backend/il_deserializer.cc b/runtime/vm/compiler/backend/il_deserializer.cc
index a122337..5650a15 100644
--- a/runtime/vm/compiler/backend/il_deserializer.cc
+++ b/runtime/vm/compiler/backend/il_deserializer.cc
@@ -1506,8 +1506,12 @@
       return ParseField(list, out);
     } else if (tag->Equals("Function")) {
       return ParseFunction(list, out);
+    } else if (tag->Equals("FunctionType")) {
+      return ParseFunctionType(list, out);
     } else if (tag->Equals("TypeParameter")) {
       return ParseTypeParameter(list, out);
+    } else if (tag->Equals("Array")) {
+      return ParseArray(list, out);
     } else if (tag->Equals("ImmutableList")) {
       return ParseImmutableList(list, out);
     } else if (tag->Equals("Instance")) {
@@ -1661,7 +1665,43 @@
   return true;
 }
 
-bool FlowGraphDeserializer::ParseImmutableList(SExpList* list, Object* out) {
+bool FlowGraphDeserializer::ParseFunctionType(SExpList* list, Object* out) {
+  ASSERT(out != nullptr);
+  if (list == nullptr) return false;
+  auto& type_params = TypeArguments::ZoneHandle(zone());
+  if (auto const type_params_sexp = Retrieve(list, "type_params")) {
+    if (!ParseTypeArguments(type_params_sexp, &type_params)) return false;
+  }
+  auto& result_type = AbstractType::ZoneHandle(zone());
+  if (auto const result_type_sexp = Retrieve(list, "result_type")) {
+    if (!ParseAbstractType(result_type_sexp, &result_type)) return false;
+  }
+  auto& parameter_types = Array::ZoneHandle(zone());
+  if (auto const parameter_types_sexp = Retrieve(list, "parameter_types")) {
+    if (!ParseDartValue(parameter_types_sexp, &parameter_types)) return false;
+  }
+  auto& parameter_names = Array::ZoneHandle(zone());
+  if (auto const parameter_names_sexp = Retrieve(list, "parameter_names")) {
+    if (!ParseDartValue(parameter_names_sexp, &parameter_names)) return false;
+  }
+  intptr_t packed_fields;
+  if (auto const packed_fields_sexp =
+          CheckInteger(list->ExtraLookupValue("packed_fields"))) {
+    packed_fields = packed_fields_sexp->value();
+  } else {
+    return false;
+  }
+  auto& sig = FunctionType::ZoneHandle(zone(), FunctionType::New());
+  sig.set_type_parameters(type_params);
+  sig.set_result_type(result_type);
+  sig.set_parameter_types(parameter_types);
+  sig.set_parameter_names(parameter_names);
+  sig.set_packed_fields(packed_fields);
+  *out = sig.raw();
+  return true;
+}
+
+bool FlowGraphDeserializer::ParseArray(SExpList* list, Object* out) {
   ASSERT(out != nullptr);
   if (list == nullptr) return false;
 
@@ -1678,7 +1718,13 @@
     if (!ParseTypeArguments(type_args_sexp, &array_type_args_)) return false;
     arr.SetTypeArguments(array_type_args_);
   }
-  arr.MakeImmutable();
+  return true;
+}
+
+bool FlowGraphDeserializer::ParseImmutableList(SExpList* list, Object* out) {
+  if (!ParseArray(list, out)) return false;
+
+  Array::Cast(*out).MakeImmutable();
   return CanonicalizeInstance(list, out);
 }
 
@@ -1852,13 +1898,8 @@
   if (!ParseClass(cls_sexp, &type_class_)) return false;
   const Nullability nullability =
       type_class_.IsNullClass() ? Nullability::kNullable : Nullability::kLegacy;
-  *out = Type::New(type_class_, *type_args_ptr, token_pos, nullability);
+  *out = Type::New(type_class_, *type_args_ptr, nullability);
   auto& type = Type::Cast(*out);
-  if (auto const sig_sexp = list->ExtraLookupValue("signature")) {
-    auto& function = Function::Handle(zone());
-    if (!ParseDartValue(sig_sexp, &function)) return false;
-    type.set_signature(function);
-  }
   if (is_recursive) {
     while (!pending_typerefs->is_empty()) {
       auto const ref = pending_typerefs->RemoveLast();
@@ -1929,46 +1970,32 @@
   ASSERT(out != nullptr);
   if (list == nullptr) return false;
 
-  const Function* function = nullptr;
-  const Class* cls = nullptr;
-  if (auto const func_sexp = CheckSymbol(list->ExtraLookupValue("function"))) {
-    if (!ParseCanonicalName(func_sexp, &type_param_function_)) return false;
-    if (!type_param_function_.IsFunction() || type_param_function_.IsNull()) {
-      StoreError(func_sexp, "not a function name");
-      return false;
-    }
-    function = &type_param_function_;
-  } else if (auto const class_sexp =
-                 CheckInteger(list->ExtraLookupValue("class"))) {
-    const intptr_t cid = class_sexp->value();
-    auto const table = thread()->isolate_group()->class_table();
+  Class& cls = Class::Handle();
+  if (auto const cid_sexp = CheckInteger(list->ExtraLookupValue("cid"))) {
+    const intptr_t cid = cid_sexp->value();
+    ClassTable* table = thread()->isolate_group()->class_table();
     if (!table->HasValidClassAt(cid)) {
-      StoreError(class_sexp, "not a valid class id");
+      StoreError(cid_sexp, "no valid class found for cid");
       return false;
     }
-    type_param_class_ = table->At(cid);
-    cls = &type_param_class_;
+    cls = table->At(cid);
   } else {
-    // If we weren't given an explicit source, check in the function for this
-    // flow graph.
-    ASSERT(parsed_function_ != nullptr);
-    function = &parsed_function_->function();
+    return false;
   }
-
+  auto const base_sexp = CheckInteger(list->ExtraLookupValue("base"));
+  if (base_sexp == nullptr) return false;
+  intptr_t base = base_sexp->value();
+  auto const index_sexp = CheckInteger(list->ExtraLookupValue("index"));
+  if (index_sexp == nullptr) return false;
+  intptr_t index = index_sexp->value();
   auto const name_sexp = CheckSymbol(Retrieve(list, 1));
   if (name_sexp == nullptr) return false;
   tmp_string_ = String::New(name_sexp->value());
 
-  *out = TypeParameter::null();
-  if (function != nullptr) {
-    *out = function->LookupTypeParameter(tmp_string_, nullptr);
-  } else if (cls != nullptr) {
-    *out = cls->LookupTypeParameter(tmp_string_);
-  }
-  if (out->IsNull()) {
-    StoreError(name_sexp, "no type parameter found for name");
-    return false;
-  }
+  *out =
+      TypeParameter::New(cls, base, index, tmp_string_, Object::dynamic_type(),
+                         false, Nullability::kLegacy);
+  TypeParameter::Cast(*out).SetIsFinalized();
   return CanonicalizeInstance(list, out);
 }
 
diff --git a/runtime/vm/compiler/backend/il_deserializer.h b/runtime/vm/compiler/backend/il_deserializer.h
index f1637dd..5049850 100644
--- a/runtime/vm/compiler/backend/il_deserializer.h
+++ b/runtime/vm/compiler/backend/il_deserializer.h
@@ -67,7 +67,6 @@
         name_library_(Library::Handle(zone)),
         type_class_(Class::Handle(zone)),
         type_param_class_(Class::Handle(zone)),
-        type_param_function_(Function::Handle(zone)),
         tmp_string_(String::Handle(zone)) {
     // See canonicalization comment in ParseDartValue as to why this is
     // currently necessary.
@@ -282,9 +281,12 @@
   bool ParseClosure(SExpList* list, Object* out);
   bool ParseField(SExpList* list, Object* out);
   bool ParseFunction(SExpList* list, Object* out);
+  bool ParseSignature(SExpList* list, Object* out);
+  bool ParseArray(SExpList* list, Object* out);
   bool ParseImmutableList(SExpList* list, Object* out);
   bool ParseInstance(SExpList* list, Object* out);
   bool ParseType(SExpression* sexp, Object* out);
+  bool ParseFunctionType(SExpList* list, Object* out);
   bool ParseTypeParameter(SExpList* list, Object* out);
   bool ParseTypeArguments(SExpression* sexp, Object* out);
   bool ParseTypeRef(SExpList* list, Object* out);
@@ -401,7 +403,6 @@
   Library& name_library_;              // ParseCanonicalName
   Class& type_class_;                  // ParseType
   Class& type_param_class_;            // ParseTypeParameter
-  Function& type_param_function_;      // ParseTypeParameter
   // Uses of string handles tend to be immediate, so we only need one.
   String& tmp_string_;
 
diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc
index 863e8ab..1d8e825 100644
--- a/runtime/vm/compiler/backend/il_serializer.cc
+++ b/runtime/vm/compiler/backend/il_serializer.cc
@@ -65,7 +65,7 @@
       serialize_parent_(Function::Handle(zone_)),
       type_arguments_elem_(AbstractType::Handle(zone_)),
       type_class_(Class::Handle(zone_)),
-      type_function_(Function::Handle(zone_)),
+      type_signature_(FunctionType::Handle(zone_)),
       type_ref_type_(AbstractType::Handle(zone_)) {
   // Double-check that the zone in the flow graph is a parent of the
   // zone we'll be using for serialization.
@@ -389,20 +389,12 @@
   if (t.IsTypeParameter()) {
     const auto& param = TypeParameter::Cast(t);
     AddSymbol(sexp, "TypeParameter");
+    AddExtraInteger(sexp, "cid", param.parameterized_class_id());
+    AddExtraInteger(sexp, "base", param.base());
+    AddExtraInteger(sexp, "index", param.index());
     tmp_string_ = param.name();
     AddSymbol(sexp, tmp_string_.ToCString());
-    if (param.IsFunctionTypeParameter()) {
-      if (param.parameterized_function() != flow_graph_->function().raw()) {
-        type_function_ = param.parameterized_function();
-        sexp->AddExtra("function", CanonicalNameToSExp(type_function_));
-      } else if (FLAG_verbose_flow_graph_serialization) {
-        sexp->AddExtra("function",
-                       CanonicalNameToSExp(flow_graph_->function()));
-      }
-    } else if (param.IsClassTypeParameter()) {
-      type_class_ = param.parameterized_class();
-      AddExtraInteger(sexp, "class", type_class_.id());
-    }
+    // TODO(regis): bound, default argument, flags, nullability, hash.
     return sexp;
   }
   if (t.IsTypeRef()) {
@@ -433,21 +425,37 @@
     }
     return sexp;
   }
+  // We want to check for the type being recursive before we may serialize
+  // any sub-parts that include possible TypeRefs to this type.
+  const bool is_recursive = t.IsRecursive();
+  intptr_t hash = 0;
+  if (is_recursive) {
+    hash = t.Hash();
+    AddExtraInteger(sexp, "hash", hash);
+    open_recursive_types_.Insert(hash, &t);
+  }
+  if (t.IsFunctionType()) {
+    const auto& sig = FunctionType::Handle(zone(), FunctionType::Cast(t).raw());
+    AddSymbol(sexp, "FunctionType");
+    function_type_args_ = sig.type_parameters();
+    if (auto const ta_sexp = NonEmptyTypeArgumentsToSExp(function_type_args_)) {
+      sexp->AddExtra("type_params", ta_sexp);
+    }
+    auto& type = AbstractType::Handle(zone(), sig.result_type());
+    sexp->AddExtra("result_type", AbstractTypeToSExp(type));
+    auto& parameter_types = Array::Handle(zone(), sig.parameter_types());
+    sexp->AddExtra("parameter_types", ArrayToSExp(parameter_types));
+    auto& parameter_names = Array::Handle(zone(), sig.parameter_names());
+    sexp->AddExtra("parameter_names", ArrayToSExp(parameter_names));
+    AddExtraInteger(sexp, "packed_fields", sig.packed_fields());
+    // If we were parsing a recursive type, we're now done building it, so
+    // remove it from the open recursive types.
+    if (is_recursive) open_recursive_types_.Remove(hash);
+    return sexp;
+  }
   ASSERT(t.IsType());
   AddSymbol(sexp, "Type");
   const auto& type = Type::Cast(t);
-  if (!type.token_pos().IsNoSource()) {
-    AddExtraInteger(sexp, "token_pos", type.token_pos().Serialize());
-  }
-  // We want to check for the type being recursive before we may serialize
-  // any sub-parts that include possible TypeRefs to this type.
-  const bool is_recursive = type.IsRecursive();
-  intptr_t hash = 0;
-  if (is_recursive) {
-    hash = type.Hash();
-    AddExtraInteger(sexp, "hash", hash);
-    open_recursive_types_.Insert(hash, &type);
-  }
   if (type.HasTypeClass()) {
     type_class_ = type.type_class();
     // This avoids re-entry as long as serializing a class doesn't involve
@@ -458,10 +466,6 @@
     // just printing out this version.
     AddExtraString(sexp, "name", type.ToCString());
   }
-  if (type.IsFunctionType()) {
-    type_function_ = type.signature();
-    sexp->AddExtra("signature", DartValueToSExp(type_function_));
-  }
   // Since type arguments may themselves be instantiations of generic
   // types, we may call back into this function in the middle of printing
   // the TypeArguments and so we must allocate a fresh handle here.
@@ -591,7 +595,7 @@
   return sexp;
 }
 
-SExpression* FlowGraphSerializer::ArrayToSExp(const Array& arr) {
+SExpression* FlowGraphSerializer::ImmutableListToSExp(const Array& arr) {
   if (arr.IsNull()) return nullptr;
   // We should only be getting immutable lists when serializing Dart values
   // in flow graphs.
@@ -612,6 +616,18 @@
   return sexp;
 }
 
+SExpression* FlowGraphSerializer::ArrayToSExp(const Array& arr) {
+  if (arr.IsNull()) return nullptr;
+  auto sexp = new (zone()) SExpList(zone());
+  AddSymbol(sexp, "Array");
+  auto& array_elem = Object::Handle(zone());
+  for (intptr_t i = 0; i < arr.Length(); i++) {
+    array_elem = arr.At(i);
+    sexp->Add(DartValueToSExp(array_elem));
+  }
+  return sexp;
+}
+
 SExpression* FlowGraphSerializer::ClosureToSExp(const Closure& c) {
   if (c.IsNull()) return nullptr;
   auto sexp = new (zone()) SExpList(zone());
@@ -691,7 +707,7 @@
     return CodeToSExp(Code::Cast(dartval));
   }
   if (dartval.IsArray()) {
-    return ArrayToSExp(Array::Cast(dartval));
+    return ImmutableListToSExp(Array::Cast(dartval));
   }
   if (dartval.IsFunction()) {
     return FunctionToSExp(Function::Cast(dartval));
diff --git a/runtime/vm/compiler/backend/il_serializer.h b/runtime/vm/compiler/backend/il_serializer.h
index c5d8d6f..10ba537 100644
--- a/runtime/vm/compiler/backend/il_serializer.h
+++ b/runtime/vm/compiler/backend/il_serializer.h
@@ -72,6 +72,7 @@
   // value is the null object, the null pointer is returned.
   SExpression* AbstractTypeToSExp(const AbstractType& typ);
   SExpression* ArrayToSExp(const Array& arr);
+  SExpression* ImmutableListToSExp(const Array& arr);
   SExpression* ClassToSExp(const Class& cls);
   SExpression* ClosureToSExp(const Closure& c);
   SExpression* ContextToSExp(const Context& c);
@@ -133,7 +134,7 @@
 
   // A map of currently open (being serialized) recursive types. We use this
   // to determine whether to serialize the referred types in TypeRefs.
-  IntMap<const Type*> open_recursive_types_;
+  IntMap<const AbstractType*> open_recursive_types_;
 
   // Used for --populate-llvm-constant-pool in ConstantPoolToSExp.
   class LLVMPoolMapKeyEqualsTraits : public AllStatic {
@@ -188,7 +189,7 @@
   Function& serialize_parent_;         // SerializeCanonicalName
   AbstractType& type_arguments_elem_;  // TypeArgumentsToSExp
   Class& type_class_;                  // AbstractTypeToSExp
-  Function& type_function_;            // AbstractTypeToSExp
+  FunctionType& type_signature_;       // AbstractTypeToSExp
   AbstractType& type_ref_type_;        // AbstractTypeToSExp
 };
 
diff --git a/runtime/vm/compiler/backend/il_test_helper.h b/runtime/vm/compiler/backend/il_test_helper.h
index 8f9b5f8..aedac86 100644
--- a/runtime/vm/compiler/backend/il_test_helper.h
+++ b/runtime/vm/compiler/backend/il_test_helper.h
@@ -313,8 +313,10 @@
 
  private:
   static FlowGraph& MakeDummyGraph(Thread* thread) {
+    const FunctionType& signature =
+        FunctionType::ZoneHandle(FunctionType::New());
     const Function& func = Function::ZoneHandle(Function::New(
-        String::Handle(Symbols::New(thread, "dummy")),
+        signature, String::Handle(Symbols::New(thread, "dummy")),
         FunctionLayout::kRegularFunction,
         /*is_static=*/true,
         /*is_const=*/false,
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 1fb023c..b991d39 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -2370,6 +2370,7 @@
   ASSERT(source.token_pos.IsReal() || source.token_pos.IsSynthetic() ||
          source.token_pos.IsNoSource());
   RELEASE_ASSERT(!function.IsNull());
+  ASSERT(FunctionType::Handle(function.signature()).IsFinalized());
   inline_id_to_function_->Add(&function);
   inline_id_to_token_pos_->Add(source.token_pos);
   caller_inline_id_->Add(source.inlining_id);
@@ -4128,6 +4129,8 @@
         type = Type::Double();
       } else if (IsIntegerClassId(receiver_cid)) {
         type = Type::IntType();
+      } else if (IsTypeClassId(receiver_cid)) {
+        type = Type::DartTypeType();
       } else if (receiver_cid != kClosureCid) {
         const Class& cls = Class::Handle(
             Z, flow_graph->isolate_group()->class_table()->At(receiver_cid));
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 8a60a63..febd184 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -2725,9 +2725,10 @@
     case Slot::Kind::kClosure_instantiator_type_arguments:
     case Slot::Kind::kClosureData_default_type_arguments:
     case Slot::Kind::kFunction_data:
+    case Slot::Kind::kFunction_signature:
     case Slot::Kind::kFunction_parameter_names:
-    case Slot::Kind::kFunction_parameter_types:
-    case Slot::Kind::kFunction_type_parameters:
+    case Slot::Kind::kFunctionType_parameter_types:
+    case Slot::Kind::kFunctionType_type_parameters:
     case Slot::Kind::kPointerBase_data_field:
     case Slot::Kind::kTypedDataView_data:
     case Slot::Kind::kType_arguments:
@@ -2753,6 +2754,7 @@
       *range = Range::Full(RepresentationToRangeSize(slot().representation()));
       break;
 
+    case Slot::Kind::kFunctionType_packed_fields:
     case Slot::Kind::kClosure_hash:
     case Slot::Kind::kLinkedHashMap_hash_mask:
     case Slot::Kind::kLinkedHashMap_used_data:
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index 4e2414f..d5e5c6c 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -52,14 +52,15 @@
 //   (i.e. initialized once at construction time and does not change after
 //   that) or like a non-final field.
 #define NULLABLE_BOXED_NATIVE_SLOTS_LIST(V)                                    \
+  V(Function, FunctionLayout, signature, FunctionType, FINAL)                  \
   V(Context, ContextLayout, parent, Context, FINAL)                            \
   V(Closure, ClosureLayout, instantiator_type_arguments, TypeArguments, FINAL) \
   V(Closure, ClosureLayout, delayed_type_arguments, TypeArguments, FINAL)      \
   V(Closure, ClosureLayout, function_type_arguments, TypeArguments, FINAL)     \
   V(ClosureData, ClosureDataLayout, default_type_arguments, TypeArguments,     \
     FINAL)                                                                     \
-  V(Function, FunctionLayout, type_parameters, TypeArguments, FINAL)           \
   V(Type, TypeLayout, arguments, TypeArguments, FINAL)                         \
+  V(FunctionType, FunctionTypeLayout, type_parameters, TypeArguments, FINAL)   \
   V(WeakProperty, WeakPropertyLayout, key, Dynamic, VAR)                       \
   V(WeakProperty, WeakPropertyLayout, value, Dynamic, VAR)
 
@@ -84,7 +85,7 @@
   V(ClosureData, ClosureDataLayout, default_type_arguments_info, Smi, FINAL)   \
   V(Function, FunctionLayout, data, Dynamic, FINAL)                            \
   V(Function, FunctionLayout, parameter_names, Array, FINAL)                   \
-  V(Function, FunctionLayout, parameter_types, Array, FINAL)                   \
+  V(FunctionType, FunctionTypeLayout, parameter_types, Array, FINAL)           \
   V(GrowableObjectArray, GrowableObjectArrayLayout, length, Smi, VAR)          \
   V(GrowableObjectArray, GrowableObjectArrayLayout, data, Array, VAR)          \
   V(TypedDataBase, TypedDataBaseLayout, length, Smi, FINAL)                    \
@@ -125,6 +126,7 @@
 #define UNBOXED_NATIVE_SLOTS_LIST(V)                                           \
   V(Function, FunctionLayout, kind_tag, Uint32, FINAL)                         \
   V(Function, FunctionLayout, packed_fields, Uint32, FINAL)                    \
+  V(FunctionType, FunctionTypeLayout, packed_fields, Uint32, FINAL)            \
   V(TypeParameter, TypeParameterLayout, flags, Uint8, FINAL)
 
 // For uses that do not need the exact_type (boxed) or representation (unboxed)
diff --git a/runtime/vm/compiler/backend/slot_test.cc b/runtime/vm/compiler/backend/slot_test.cc
index 4271174..647e564 100644
--- a/runtime/vm/compiler/backend/slot_test.cc
+++ b/runtime/vm/compiler/backend/slot_test.cc
@@ -46,8 +46,9 @@
       Script::Handle(), TokenPosition::kNoSource));
   dummy_class.set_is_synthesized_class();
 
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   const Function& dummy_function = Function::ZoneHandle(
-      Function::New(String::Handle(Symbols::New(thread, "foo")),
+      Function::New(signature, String::Handle(Symbols::New(thread, "foo")),
                     FunctionLayout::kRegularFunction, false, false, false,
                     false, false, dummy_class, TokenPosition::kMinSource));
 
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index 4b25afc..a6fc022 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -564,7 +564,8 @@
 
   // Climb up the hierarchy to find a suitable supertype. Note that interface
   // types are not considered, making the union potentially non-commutative
-  if (abstract_type->IsInstantiated() && !abstract_type->IsDynamicType()) {
+  if (abstract_type->IsInstantiated() && !abstract_type->IsDynamicType() &&
+      !abstract_type->IsFunctionType()) {
     Class& cls = Class::Handle(abstract_type->type_class());
     for (; !cls.IsNull() && !cls.IsGeneric(); cls = cls.SuperClass()) {
       type_ = &AbstractType::ZoneHandle(cls.RareType());
@@ -1357,8 +1358,8 @@
             : TypeArguments::Cast(type_args_value->BoundConstant());
     const Class& cls =
         Class::Handle(IsolateGroup::Current()->class_table()->At(cid));
-    Type& type = Type::ZoneHandle(Type::New(
-        cls, type_args, TokenPosition::kNoSource, Nullability::kNonNullable));
+    Type& type =
+        Type::ZoneHandle(Type::New(cls, type_args, Nullability::kNonNullable));
     ASSERT(type.IsInstantiated());
     type.SetIsFinalized();
     return CompileType(CompileType::kNonNullable, cid, &type);
@@ -1480,8 +1481,9 @@
 CompileType AllocateObjectInstr::ComputeType() const {
   if (!closure_function().IsNull()) {
     ASSERT(cls().id() == kClosureCid);
-    return CompileType(CompileType::kNonNullable, kClosureCid,
-                       &Type::ZoneHandle(closure_function().SignatureType()));
+    const FunctionType& sig =
+        FunctionType::ZoneHandle(closure_function().signature());
+    return CompileType(CompileType::kNonNullable, kClosureCid, &sig);
   }
   // TODO(vegorov): Incorporate type arguments into the returned type.
   return CompileType::FromCid(cls().id());
diff --git a/runtime/vm/compiler/backend/type_propagator_test.cc b/runtime/vm/compiler/backend/type_propagator_test.cc
index 026fa6c..c5415fa 100644
--- a/runtime/vm/compiler/backend/type_propagator_test.cc
+++ b/runtime/vm/compiler/backend/type_propagator_test.cc
@@ -169,15 +169,16 @@
   const Class& object_class =
       Class::Handle(thread->isolate_group()->object_store()->object_class());
 
+  const FunctionType& signature = FunctionType::Handle(FunctionType::New());
   const Function& target_func = Function::ZoneHandle(Function::New(
-      String::Handle(Symbols::New(thread, "dummy2")),
+      signature, String::Handle(Symbols::New(thread, "dummy2")),
       FunctionLayout::kRegularFunction,
       /*is_static=*/true,
       /*is_const=*/false,
       /*is_abstract=*/false,
       /*is_external=*/false,
       /*is_native=*/true, object_class, TokenPosition::kNoSource));
-  target_func.set_result_type(AbstractType::Handle(Type::IntType()));
+  signature.set_result_type(AbstractType::Handle(Type::IntType()));
 
   const Field& field = Field::ZoneHandle(
       Field::New(String::Handle(Symbols::New(thread, "dummy")),
diff --git a/runtime/vm/compiler/cha.cc b/runtime/vm/compiler/cha.cc
index 6e0f9d3..a21714f 100644
--- a/runtime/vm/compiler/cha.cc
+++ b/runtime/vm/compiler/cha.cc
@@ -84,8 +84,6 @@
 }
 
 bool CHA::IsImplemented(const Class& cls) {
-  // Function type aliases have different type checking rules.
-  ASSERT(!cls.IsTypedefClass());
   // Can't track dependencies for classes on the VM heap since those are
   // read-only.
   // TODO(fschneider): Enable tracking of CHA dependent code for VM heap
diff --git a/runtime/vm/compiler/ffi/call.cc b/runtime/vm/compiler/ffi/call.cc
index 39402f5..5dc219a 100644
--- a/runtime/vm/compiler/ffi/call.cc
+++ b/runtime/vm/compiler/ffi/call.cc
@@ -14,31 +14,32 @@
 namespace ffi {
 
 // TODO(dartbug.com/36607): Cache the trampolines.
-FunctionPtr TrampolineFunction(const Function& dart_signature,
-                               const Function& c_signature) {
+FunctionPtr TrampolineFunction(const FunctionType& dart_signature,
+                               const FunctionType& c_signature) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   String& name = String::Handle(zone, Symbols::New(thread, "FfiTrampoline"));
   const Library& lib = Library::Handle(zone, Library::FfiLibrary());
   const Class& owner_class = Class::Handle(zone, lib.toplevel_class());
-  Function& function =
-      Function::Handle(zone, Function::New(name, FunctionLayout::kFfiTrampoline,
-                                           /*is_static=*/true,
-                                           /*is_const=*/false,
-                                           /*is_abstract=*/false,
-                                           /*is_external=*/false,
-                                           /*is_native=*/false, owner_class,
-                                           TokenPosition::kMinSource));
+  FunctionType& signature = FunctionType::Handle(zone, FunctionType::New());
+  Function& function = Function::Handle(
+      zone, Function::New(signature, name, FunctionLayout::kFfiTrampoline,
+                          /*is_static=*/true,
+                          /*is_const=*/false,
+                          /*is_abstract=*/false,
+                          /*is_external=*/false,
+                          /*is_native=*/false, owner_class,
+                          TokenPosition::kMinSource));
   function.set_is_debuggable(false);
   function.set_num_fixed_parameters(dart_signature.num_fixed_parameters());
-  function.set_result_type(
+  signature.set_result_type(
       AbstractType::Handle(zone, dart_signature.result_type()));
-  function.set_parameter_types(
+  signature.set_parameter_types(
       Array::Handle(zone, dart_signature.parameter_types()));
 
   // The signature function won't have any names for the parameters. We need to
   // assign unique names for scope building and error messages.
-  function.CreateNameArrayIncludingFlags(Heap::kNew);
+  signature.CreateNameArrayIncludingFlags(Heap::kOld);
   const intptr_t num_params = dart_signature.num_fixed_parameters();
   for (intptr_t i = 0; i < num_params; ++i) {
     if (i == 0) {
@@ -46,17 +47,12 @@
     } else {
       name = Symbols::NewFormatted(thread, ":ffi_param%" Pd, i);
     }
-    function.SetParameterNameAt(i, name);
+    signature.SetParameterNameAt(i, name);
   }
-  function.TruncateUnusedParameterFlags();
+  signature.FinalizeNameArrays(function);
   function.SetFfiCSignature(c_signature);
-
-  Type& type = Type::Handle(zone);
-  type ^= function.SignatureType(Nullability::kLegacy);
-  type ^= ClassFinalizer::FinalizeType(type);
-  function.SetSignatureType(type);
-  ASSERT(
-      Type::Handle(function.SignatureType(Nullability::kLegacy)).IsFinalized());
+  signature ^= ClassFinalizer::FinalizeType(signature);
+  function.set_signature(signature);
 
   return function.raw();
 }
diff --git a/runtime/vm/compiler/ffi/call.h b/runtime/vm/compiler/ffi/call.h
index 050b1d8..5a4e5f0 100644
--- a/runtime/vm/compiler/ffi/call.h
+++ b/runtime/vm/compiler/ffi/call.h
@@ -19,8 +19,8 @@
 
 namespace ffi {
 
-FunctionPtr TrampolineFunction(const Function& dart_signature,
-                               const Function& c_signature);
+FunctionPtr TrampolineFunction(const FunctionType& dart_signature,
+                               const FunctionType& c_signature);
 
 }  // namespace ffi
 
diff --git a/runtime/vm/compiler/ffi/callback.cc b/runtime/vm/compiler/ffi/callback.cc
index e5a4782..7e23851 100644
--- a/runtime/vm/compiler/ffi/callback.cc
+++ b/runtime/vm/compiler/ffi/callback.cc
@@ -4,6 +4,7 @@
 
 #include "vm/compiler/ffi/callback.h"
 
+#include "vm/class_finalizer.h"
 #include "vm/symbols.h"
 
 namespace dart {
@@ -12,7 +13,7 @@
 
 namespace ffi {
 
-FunctionPtr NativeCallbackFunction(const Function& c_signature,
+FunctionPtr NativeCallbackFunction(const FunctionType& c_signature,
                                    const Function& dart_target,
                                    const Instance& exceptional_return) {
   Thread* const thread = Thread::Current();
@@ -20,7 +21,7 @@
 
   // Create a new Function named '<target>_FfiCallback' and stick it in the
   // 'dart:ffi' library. Note that these functions will never be invoked by
-  // Dart, so they have may have duplicate names.
+  // Dart, so they may have duplicate names.
   Zone* const zone = thread->zone();
   const auto& name = String::Handle(
       zone, Symbols::FromConcat(thread, Symbols::FfiCallback(),
@@ -28,7 +29,8 @@
   const Library& lib = Library::Handle(zone, Library::FfiLibrary());
   const Class& owner_class = Class::Handle(zone, lib.toplevel_class());
   const Function& function =
-      Function::Handle(zone, Function::New(name, FunctionLayout::kFfiTrampoline,
+      Function::Handle(zone, Function::New(Object::null_function_type(), name,
+                                           FunctionLayout::kFfiTrampoline,
                                            /*is_static=*/true,
                                            /*is_const=*/false,
                                            /*is_abstract=*/false,
diff --git a/runtime/vm/compiler/ffi/callback.h b/runtime/vm/compiler/ffi/callback.h
index 265143e..37a4967 100644
--- a/runtime/vm/compiler/ffi/callback.h
+++ b/runtime/vm/compiler/ffi/callback.h
@@ -19,7 +19,7 @@
 
 namespace ffi {
 
-FunctionPtr NativeCallbackFunction(const Function& c_signature,
+FunctionPtr NativeCallbackFunction(const FunctionType& c_signature,
                                    const Function& dart_target,
                                    const Instance& exceptional_return);
 
diff --git a/runtime/vm/compiler/ffi/marshaller.cc b/runtime/vm/compiler/ffi/marshaller.cc
index ecf1994..480f045 100644
--- a/runtime/vm/compiler/ffi/marshaller.cc
+++ b/runtime/vm/compiler/ffi/marshaller.cc
@@ -27,7 +27,7 @@
 // Representations of the arguments and return value of a C signature function.
 static const NativeFunctionType& NativeFunctionSignature(
     Zone* zone,
-    const Function& c_signature) {
+    const FunctionType& c_signature) {
   ASSERT(c_signature.NumOptionalParameters() == 0);
   ASSERT(c_signature.NumOptionalPositionalParameters() == 0);
 
@@ -55,7 +55,8 @@
 BaseMarshaller::BaseMarshaller(Zone* zone, const Function& dart_signature)
     : zone_(zone),
       dart_signature_(dart_signature),
-      c_signature_(Function::ZoneHandle(zone, dart_signature.FfiCSignature())),
+      c_signature_(
+          FunctionType::ZoneHandle(zone, dart_signature.FfiCSignature())),
       native_calling_convention_(NativeCallingConvention::FromSignature(
           zone,
           NativeFunctionSignature(zone_, c_signature_))) {
diff --git a/runtime/vm/compiler/ffi/marshaller.h b/runtime/vm/compiler/ffi/marshaller.h
index e8306c0..657817e 100644
--- a/runtime/vm/compiler/ffi/marshaller.h
+++ b/runtime/vm/compiler/ffi/marshaller.h
@@ -135,7 +135,7 @@
   // Contains the function pointer as argument #0.
   // The Dart signature is used for the function and argument names.
   const Function& dart_signature_;
-  const Function& c_signature_;
+  const FunctionType& c_signature_;
   const NativeCallingConvention& native_calling_convention_;
 };
 
diff --git a/runtime/vm/compiler/ffi/native_calling_convention.h b/runtime/vm/compiler/ffi/native_calling_convention.h
index 9faf620..d1a942e 100644
--- a/runtime/vm/compiler/ffi/native_calling_convention.h
+++ b/runtime/vm/compiler/ffi/native_calling_convention.h
@@ -24,7 +24,7 @@
 // Calculates native calling convention, is not aware of Dart calling
 // convention constraints.
 //
-// This class is meant to beembedded in a class that is aware of Dart calling
+// This class is meant to be embedded in a class that is aware of Dart calling
 // convention constraints.
 class NativeCallingConvention : public ZoneAllocated {
  public:
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index 3e47d9d..96e9e57 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -1007,8 +1007,7 @@
   ASSERT(dart_type.IsFunctionType() && native_type.IsFunctionType());
   const Function& target =
       Function::ZoneHandle(compiler::ffi::TrampolineFunction(
-          Function::Handle(Z, Type::Cast(dart_type).signature()),
-          Function::Handle(Z, Type::Cast(native_type).signature())));
+          FunctionType::Cast(dart_type), FunctionType::Cast(native_type)));
 
   Fragment code;
   // Store the pointer in the context, we cannot load the untagged address
diff --git a/runtime/vm/compiler/frontend/constant_reader.cc b/runtime/vm/compiler/frontend/constant_reader.cc
index 83dffc8..eab7f31 100644
--- a/runtime/vm/compiler/frontend/constant_reader.cc
+++ b/runtime/vm/compiler/frontend/constant_reader.cc
@@ -205,8 +205,8 @@
       AbstractType& type = type_translator.BuildType();
       type_arguments.SetTypeAt(0, type);
       // Instantiate class.
-      type = Type::New(list_class, type_arguments, TokenPosition::kNoSource);
-      type = ClassFinalizer::FinalizeType(type);
+      type = Type::New(list_class, type_arguments);
+      type = ClassFinalizer::FinalizeType(type, ClassFinalizer::kCanonicalize);
       type_arguments = type.arguments();
       // Fill array with constant elements.
       const intptr_t length = reader.ReadUInt();
@@ -251,9 +251,9 @@
           type_arguments.SetTypeAt(j, type_translator.BuildType());
         }
         // Instantiate class.
-        auto& type = AbstractType::Handle(
-            Z, Type::New(klass, type_arguments, TokenPosition::kNoSource));
-        type = ClassFinalizer::FinalizeType(type);
+        auto& type = AbstractType::Handle(Z, Type::New(klass, type_arguments));
+        type =
+            ClassFinalizer::FinalizeType(type, ClassFinalizer::kCanonicalize);
         type_arguments = type.arguments();
         instance.SetTypeArguments(type_arguments);
       } else {
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index fd5cc1d..3fb0587 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -492,7 +492,7 @@
   Fragment prologue = B->BuildDefaultTypeHandling(dart_function);
 
   if (dart_function.IsClosureFunction() &&
-      dart_function.NumParentTypeParameters() > 0) {
+      dart_function.NumParentTypeArguments() > 0) {
     LocalVariable* closure = parsed_function()->ParameterVariable(0);
 
     // Function with yield points can not be generic itself but the outer
@@ -508,10 +508,9 @@
       prologue += LoadLocal(closure);
       prologue += LoadNativeField(Slot::Closure_function_type_arguments());
 
-      prologue += IntConstant(dart_function.NumParentTypeParameters());
+      prologue += IntConstant(dart_function.NumParentTypeArguments());
 
-      prologue += IntConstant(dart_function.NumTypeParameters() +
-                              dart_function.NumParentTypeParameters());
+      prologue += IntConstant(dart_function.NumTypeArguments());
 
       const auto& prepend_function =
           flow_graph_builder_->PrependTypeArgumentsFunction();
@@ -1005,7 +1004,9 @@
 
   ActiveClassScope active_class_scope(active_class(), &klass);
   ActiveMemberScope active_member(active_class(), &outermost_function);
-  ActiveTypeParametersScope active_type_params(active_class(), function, Z);
+  FunctionType& signature = FunctionType::Handle(Z, function.signature());
+  ActiveTypeParametersScope active_type_params(active_class(), function,
+                                               &signature, Z);
 
   ParseKernelASTFunction();
 
@@ -1043,7 +1044,6 @@
       return flow_graph_builder_->BuildGraphOfImplicitClosureFunction(function);
     case FunctionLayout::kFfiTrampoline:
       return flow_graph_builder_->BuildGraphOfFfiTrampoline(function);
-    case FunctionLayout::kSignatureFunction:
     case FunctionLayout::kIrregexpFunction:
       break;
   }
@@ -1101,7 +1101,6 @@
         SetupDefaultParameterValues();
       }
       break;
-    case FunctionLayout::kSignatureFunction:
     case FunctionLayout::kIrregexpFunction:
       UNREACHABLE();
       break;
@@ -4983,9 +4982,9 @@
         function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
 
         // Finalize function type.
-        Type& signature_type = Type::Handle(Z, function.SignatureType());
-        signature_type ^= ClassFinalizer::FinalizeType(signature_type);
-        function.SetSignatureType(signature_type);
+        FunctionType& signature = FunctionType::Handle(Z, function.signature());
+        signature ^= ClassFinalizer::FinalizeType(signature);
+        function.set_signature(signature);
 
         ClosureFunctionsCache::AddClosureFunctionLocked(function);
         break;
@@ -5076,8 +5075,8 @@
   const TypeArguments& type_arguments =
       T.BuildTypeArguments(list_length);  // read types.
   ASSERT(type_arguments.Length() == 1 && type_arguments.IsInstantiated());
-  const Function& native_sig = Function::Handle(
-      Z, Type::CheckedHandle(Z, type_arguments.TypeAt(0)).signature());
+  const FunctionType& native_sig =
+      FunctionType::CheckedHandle(Z, type_arguments.TypeAt(0));
 
   Fragment code;
   const intptr_t positional_count =
diff --git a/runtime/vm/compiler/frontend/kernel_fingerprints.cc b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
index 6b6a2d55..a736b8e 100644
--- a/runtime/vm/compiler/frontend/kernel_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
@@ -792,13 +792,6 @@
 uint32_t KernelSourceFingerprintHelper::CalculateClassFingerprint(
     const Class& klass) {
   Zone* zone = Thread::Current()->zone();
-
-  // Handle typedefs.
-  if (klass.IsTypedefClass()) {
-    const Function& func = Function::Handle(zone, klass.signature_function());
-    return CalculateFunctionFingerprint(func);
-  }
-
   String& name = String::Handle(zone, klass.Name());
   const Array& fields = Array::Handle(zone, klass.fields());
   const Array& functions = Array::Handle(zone, klass.current_functions());
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 7c0fab3..6588cc1 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2688,11 +2688,13 @@
   info.parameter_names = MakeTemporary("parameter_names");
 
   body += LoadLocal(info.function);
-  body += LoadNativeField(Slot::Function_parameter_types());
+  body += LoadNativeField(Slot::Function_signature());
+  body += LoadNativeField(Slot::FunctionType_parameter_types());
   info.parameter_types = MakeTemporary("parameter_types");
 
   body += LoadLocal(info.function);
-  body += LoadNativeField(Slot::Function_type_parameters());
+  body += LoadNativeField(Slot::Function_signature());
+  body += LoadNativeField(Slot::FunctionType_type_parameters());
   info.type_parameters = MakeTemporary("type_parameters");
 
   body += LoadLocal(info.closure);
@@ -3068,7 +3070,7 @@
           Function::ZoneHandle(Z, function.parent_function());
       const Class& owner = Class::ZoneHandle(Z, parent.Owner());
       AbstractType& type = AbstractType::ZoneHandle(Z);
-      type = Type::New(owner, TypeArguments::Handle(Z), owner.token_pos());
+      type = Type::New(owner, TypeArguments::Handle(Z));
       type = ClassFinalizer::FinalizeType(type);
       body += Constant(type);
     } else {
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index f18153d..6e6216e 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -713,8 +713,7 @@
     type = klass.DeclarationType();
   } else {
     // Note that the type argument vector is not yet extended.
-    type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
-                     klass.token_pos());
+    type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()));
   }
   return type;
 }
@@ -727,23 +726,27 @@
   bool is_method = !function.IsStaticFunction();
   intptr_t parameter_count = (is_method ? 1 : 0) + (is_setter ? 1 : 0);
 
+  const FunctionType& signature = FunctionType::Handle(Z, function.signature());
   function.SetNumOptionalParameters(0, false);
   function.set_num_fixed_parameters(parameter_count);
-  function.set_parameter_types(
-      Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
-  function.CreateNameArrayIncludingFlags(Heap::kNew);
+  if (parameter_count > 0) {
+    signature.set_parameter_types(
+        Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
+  }
+  signature.CreateNameArrayIncludingFlags(Heap::kOld);
 
   intptr_t pos = 0;
   if (is_method) {
-    function.SetParameterTypeAt(pos, GetDeclarationType(klass));
-    function.SetParameterNameAt(pos, Symbols::This());
+    signature.SetParameterTypeAt(pos, GetDeclarationType(klass));
+    signature.SetParameterNameAt(pos, Symbols::This());
     pos++;
   }
   if (is_setter) {
-    function.SetParameterTypeAt(pos, field_type);
-    function.SetParameterNameAt(pos, Symbols::Value());
+    signature.SetParameterTypeAt(pos, field_type);
+    signature.SetParameterNameAt(pos, Symbols::Value());
     pos++;
   }
+  signature.FinalizeNameArrays(function);
 }
 
 void TranslationHelper::ReportError(const char* format, ...) {
@@ -2855,11 +2858,13 @@
   }
 }
 
-ActiveTypeParametersScope::ActiveTypeParametersScope(ActiveClass* active_class,
-                                                     const Function& innermost,
-                                                     Zone* Z)
+ActiveTypeParametersScope::ActiveTypeParametersScope(
+    ActiveClass* active_class,
+    const Function& innermost,
+    const FunctionType* innermost_signature,
+    Zone* Z)
     : active_class_(active_class), saved_(*active_class) {
-  active_class_->enclosing = &innermost;
+  active_class_->enclosing = innermost_signature;
 
   intptr_t num_params = 0;
 
@@ -2889,11 +2894,11 @@
 
 ActiveTypeParametersScope::ActiveTypeParametersScope(
     ActiveClass* active_class,
-    const Function* function,
+    const FunctionType* innermost_signature,
     const TypeArguments& new_params,
     Zone* Z)
     : active_class_(active_class), saved_(*active_class) {
-  active_class_->enclosing = function;
+  active_class_->enclosing = innermost_signature;
 
   if (new_params.IsNull()) return;
 
@@ -3022,8 +3027,7 @@
       result_ = Type::Cast(result_).ToNullability(nullability, Heap::kOld);
     } else {
       // Note that the type argument vector is not yet extended.
-      result_ = Type::New(klass, Object::null_type_arguments(),
-                          klass.token_pos(), nullability);
+      result_ = Type::New(klass, Object::null_type_arguments(), nullability);
     }
     return;
   }
@@ -3032,8 +3036,7 @@
       helper_->ReadListLength();  // read type_arguments list length.
   const TypeArguments& type_arguments =
       BuildTypeArguments(length);  // read type arguments.
-  result_ =
-      Type::New(klass, type_arguments, TokenPosition::kNoSource, nullability);
+  result_ = Type::New(klass, type_arguments, nullability);
   result_ = result_.NormalizeFutureOrType(Heap::kOld);
   if (finalize_) {
     ASSERT(active_class_->klass != NULL);
@@ -3042,17 +3045,16 @@
 }
 
 void TypeTranslator::BuildFunctionType(bool simple) {
-  Function& signature_function = Function::ZoneHandle(
-      Z, Function::NewSignatureFunction(*active_class_->klass,
-                                        active_class_->enclosing != NULL
-                                            ? *active_class_->enclosing
-                                            : Function::Handle(Z),
-                                        TokenPosition::kNoSource));
-
+  const intptr_t num_enclosing_type_arguments =
+      active_class_->enclosing != NULL
+          ? active_class_->enclosing->NumTypeArguments()
+          : 0;
   Nullability nullability = helper_->ReadNullability();
   if (apply_legacy_erasure_) {
     nullability = Nullability::kLegacy;
   }
+  FunctionType& signature = FunctionType::ZoneHandle(
+      Z, FunctionType::New(num_enclosing_type_arguments, nullability));
 
   // Suspend finalization of types inside this one. They will be finalized after
   // the whole function type is constructed.
@@ -3063,13 +3065,14 @@
   finalize_ = false;
 
   if (!simple) {
-    LoadAndSetupTypeParameters(active_class_, signature_function,
-                               helper_->ReadListLength(), signature_function);
+    LoadAndSetupTypeParameters(
+        active_class_, Object::null_function(), Object::null_class(), signature,
+        helper_->ReadListLength(), active_class_->klass->nnbd_mode());
   }
 
   ActiveTypeParametersScope scope(
-      active_class_, &signature_function,
-      TypeArguments::Handle(Z, signature_function.type_parameters()), Z);
+      active_class_, &signature,
+      TypeArguments::Handle(Z, signature.type_parameters()), Z);
 
   intptr_t required_count;
   intptr_t all_count;
@@ -3086,23 +3089,25 @@
     all_count = positional_count;
   }
 
-  // The additional first parameter is the receiver type (set to dynamic).
-  signature_function.set_num_fixed_parameters(1 + required_count);
-  signature_function.SetNumOptionalParameters(
-      all_count - required_count, positional_count > required_count);
+  // The additional first parameter is the receiver (type set to dynamic).
+  const intptr_t kImplicitClosureParam = 1;
+  signature.set_num_implicit_parameters(kImplicitClosureParam);
+  signature.set_num_fixed_parameters(kImplicitClosureParam + required_count);
+  signature.SetNumOptionalParameters(all_count - required_count,
+                                     positional_count > required_count);
 
-  signature_function.set_parameter_types(
-      Array::Handle(Z, Array::New(1 + all_count, Heap::kOld)));
-  signature_function.CreateNameArrayIncludingFlags(Heap::kOld);
+  signature.set_parameter_types(Array::Handle(
+      Z, Array::New(kImplicitClosureParam + all_count, Heap::kOld)));
+  signature.CreateNameArrayIncludingFlags(Heap::kOld);
 
   intptr_t pos = 0;
-  signature_function.SetParameterTypeAt(pos, AbstractType::dynamic_type());
-  signature_function.SetParameterNameAt(pos, H.DartSymbolPlain("_receiver_"));
+  signature.SetParameterTypeAt(pos, AbstractType::dynamic_type());
+  signature.SetParameterNameAt(pos, H.DartSymbolPlain("_receiver_"));
   ++pos;
   for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
     BuildTypeInternal();  // read ith positional parameter.
-    signature_function.SetParameterTypeAt(pos, result_);
-    signature_function.SetParameterNameAt(pos, H.DartSymbolPlain("noname"));
+    signature.SetParameterTypeAt(pos, result_);
+    signature.SetParameterNameAt(pos, H.DartSymbolPlain("noname"));
   }
 
   if (!simple) {
@@ -3113,36 +3118,30 @@
       String& name = H.DartSymbolObfuscate(helper_->ReadStringReference());
       BuildTypeInternal();  // read named_parameters[i].type.
       const uint8_t flags = helper_->ReadFlags();  // read flags
-      signature_function.SetParameterTypeAt(pos, result_);
-      signature_function.SetParameterNameAt(pos, name);
+      signature.SetParameterTypeAt(pos, result_);
+      signature.SetParameterNameAt(pos, name);
       if (!apply_legacy_erasure_ &&
           (flags & static_cast<uint8_t>(NamedTypeFlags::kIsRequired)) != 0) {
-        signature_function.SetIsRequiredAt(pos);
+        signature.SetIsRequiredAt(pos);
       }
     }
   }
-  signature_function.TruncateUnusedParameterFlags();
+  signature.TruncateUnusedParameterFlags();
 
   if (!simple) {
     helper_->SkipOptionalDartType();  // read typedef type.
   }
 
   BuildTypeInternal();  // read return type.
-  signature_function.set_result_type(result_);
+  signature.set_result_type(result_);
 
   finalize_ = finalize;
 
-  Type& signature_type =
-      Type::ZoneHandle(Z, signature_function.SignatureType(nullability));
-
   if (finalize_) {
-    signature_type ^= ClassFinalizer::FinalizeType(signature_type);
-    // Do not refer to signature_function anymore, since it may have been
-    // replaced during canonicalization.
-    signature_function = Function::null();
+    signature ^= ClassFinalizer::FinalizeType(signature);
   }
 
-  result_ = signature_type.raw();
+  result_ = signature.raw();
 }
 
 void TypeTranslator::BuildTypeParameterType() {
@@ -3290,8 +3289,7 @@
   // We make a temporary [Type] object and use `ClassFinalizer::FinalizeType` to
   // finalize the argument types.
   // (This can for example make the [type_arguments] vector larger)
-  Type& type = Type::Handle(
-      Z, Type::New(receiver_class, type_arguments, TokenPosition::kNoSource));
+  Type& type = Type::Handle(Z, Type::New(receiver_class, type_arguments));
   if (finalize_) {
     type ^= ClassFinalizer::FinalizeType(type);
   }
@@ -3303,16 +3301,23 @@
 
 void TypeTranslator::LoadAndSetupTypeParameters(
     ActiveClass* active_class,
-    const Object& set_on,
+    const Function& function,
+    const Class& parameterized_class,
+    const FunctionType& parameterized_signature,
     intptr_t type_parameter_count,
-    const Function& parameterized_function) {
+    const NNBDMode nnbd_mode) {
+  ASSERT(parameterized_class.IsNull() != parameterized_signature.IsNull());
   ASSERT(type_parameter_count >= 0);
   if (type_parameter_count == 0) {
     return;
   }
-  ASSERT(set_on.IsClass() || set_on.IsFunction());
-  bool set_on_class = set_on.IsClass();
-  ASSERT(set_on_class == parameterized_function.IsNull());
+
+  // The finalized index of a type parameter can only be determined if the
+  // length of the flattened type argument vector is known, which in turn can
+  // only be determined after the super type and its class have been loaded.
+  // Due to the added complexity of loading classes out of order from the kernel
+  // file, class type parameter indices are not finalized during class loading.
+  // However, function type parameter indices can be immediately finalized.
 
   // First setup the type parameters, so if any of the following code uses it
   // (in a recursive way) we're fine.
@@ -3320,15 +3325,27 @@
   TypeParameter& parameter = TypeParameter::Handle(Z);
   const Type& null_bound = Type::Handle(Z);
 
-  const NNBDMode nnbd_mode = set_on.IsClass()
-                                 ? Class::Cast(set_on).nnbd_mode()
-                                 : Function::Cast(set_on).nnbd_mode();
   const Nullability nullability = (nnbd_mode == NNBDMode::kOptedInLib)
                                       ? Nullability::kNonNullable
                                       : Nullability::kLegacy;
 
-  // Step a) Create array of [TypeParameter] objects (without bound).
+  // Step a)
+  // - Create array of [TypeParameter] objects (without bound).
+  // - Create array of [String] objects.
   type_parameters = TypeArguments::New(type_parameter_count);
+  intptr_t offset = 0;
+  if (!parameterized_class.IsNull()) {
+    ASSERT(parameterized_class.type_parameters() == TypeArguments::null());
+    parameterized_class.set_type_parameters(type_parameters);
+  } else {
+    ASSERT(parameterized_signature.type_parameters() == TypeArguments::null());
+    parameterized_signature.set_type_parameters(type_parameters);
+    offset = parameterized_signature.NumParentTypeArguments();
+    if (!function.IsNull()) {
+      function.SetNumTypeParameters(type_parameter_count);
+    }
+  }
+
   const Library& lib = Library::Handle(Z, active_class->klass->library());
   {
     AlternativeReadingScope alt(&helper_->reader_);
@@ -3336,26 +3353,16 @@
       TypeParameterHelper helper(helper_);
       helper.Finish();
       parameter = TypeParameter::New(
-          set_on_class ? *active_class->klass : Class::Handle(Z),
-          parameterized_function, i,
-          H.DartIdentifier(lib, helper.name_index_),  // read ith name index.
-          null_bound, helper.IsGenericCovariantImpl(), nullability,
-          TokenPosition::kNoSource);
-      parameter.SetCanonical();
-      parameter.SetDeclaration(true);
+          parameterized_class, offset, offset + i,
+          H.DartIdentifier(lib, helper.name_index_), null_bound,
+          helper.IsGenericCovariantImpl(), nullability);
       type_parameters.SetTypeAt(i, parameter);
     }
   }
 
-  if (set_on.IsClass()) {
-    Class::Cast(set_on).set_type_parameters(type_parameters);
-  } else {
-    Function::Cast(set_on).set_type_parameters(type_parameters);
-  }
-
-  const Function* enclosing = NULL;
-  if (!parameterized_function.IsNull()) {
-    enclosing = &parameterized_function;
+  const FunctionType* enclosing = NULL;
+  if (!parameterized_signature.IsNull()) {
+    enclosing = &parameterized_signature;
   }
   ActiveTypeParametersScope scope(active_class, enclosing, type_parameters, Z);
 
@@ -3376,9 +3383,8 @@
     helper.Finish();
   }
 
-  if (set_on.IsFunction()) {
-    Function::Cast(set_on).UpdateCachedDefaultTypeArguments(Thread::Current());
-  }
+  // Note that function.UpdateCachedDefaultTypeArguments() is called in
+  // function.set_signature() and is not required here.
 
   // Fix bounds and default arguments in all derived type parameters (with
   // different nullabilities).
@@ -3389,10 +3395,13 @@
          i < n; ++i) {
       derived ^= active_class->derived_type_parameters->At(i);
       if (derived.bound() == AbstractType::null() &&
-          (derived.parameterized_class() == set_on.raw() ||
-           derived.parameterized_function() == set_on.raw())) {
-        ASSERT(!derived.IsFinalized());
-        parameter ^= type_parameters.TypeAt(derived.index());
+          ((!parameterized_class.IsNull() &&
+            derived.parameterized_class() == parameterized_class.raw()) ||
+           (!parameterized_signature.IsNull() &&
+            derived.parameterized_class() == Class::null() &&
+            derived.index() >= offset &&
+            derived.index() < offset + type_parameter_count))) {
+        parameter ^= type_parameters.TypeAt(derived.index() - offset);
         type = parameter.bound();
         derived.set_bound(type);
         type = parameter.default_argument();
@@ -3404,7 +3413,6 @@
 
 const Type& TypeTranslator::ReceiverType(const Class& klass) {
   ASSERT(!klass.IsNull());
-  ASSERT(!klass.IsTypedefClass());
   // Note that if klass is _Closure, the returned type will be _Closure,
   // and not the signature type.
   Type& type = Type::ZoneHandle(Z);
@@ -3412,7 +3420,7 @@
     type = klass.DeclarationType();
   } else {
     type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
-                     klass.token_pos(), Nullability::kNonNullable);
+                     Nullability::kNonNullable);
   }
   return type;
 }
@@ -3524,13 +3532,16 @@
   bool is_factory = function.IsFactory();
   intptr_t extra_parameters = (is_method || is_closure || is_factory) ? 1 : 0;
 
+  const FunctionType& signature = FunctionType::Handle(Z, function.signature());
+  ASSERT(!signature.IsNull());
   if (!is_factory) {
-    LoadAndSetupTypeParameters(active_class_, function,
-                               helper_->ReadListLength(), function);
+    LoadAndSetupTypeParameters(active_class_, function, Class::Handle(Z),
+                               signature, helper_->ReadListLength(),
+                               function.nnbd_mode());
     function_node_helper->SetJustRead(FunctionNodeHelper::kTypeParameters);
   }
 
-  ActiveTypeParametersScope scope(active_class_, function, Z);
+  ActiveTypeParametersScope scope(active_class_, function, &signature, Z);
 
   function_node_helper->ReadUntilExcluding(
       FunctionNodeHelper::kPositionalParameters);
@@ -3555,23 +3566,27 @@
   }
   intptr_t parameter_count = extra_parameters + total_parameter_count;
 
-  function.set_parameter_types(
-      Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
-  function.CreateNameArrayIncludingFlags(Heap::kOld);
   intptr_t pos = 0;
-  if (is_method) {
-    ASSERT(!klass.IsNull());
-    function.SetParameterTypeAt(pos, H.GetDeclarationType(klass));
-    function.SetParameterNameAt(pos, Symbols::This());
-    pos++;
-  } else if (is_closure) {
-    function.SetParameterTypeAt(pos, AbstractType::dynamic_type());
-    function.SetParameterNameAt(pos, Symbols::ClosureParameter());
-    pos++;
-  } else if (is_factory) {
-    function.SetParameterTypeAt(pos, AbstractType::dynamic_type());
-    function.SetParameterNameAt(pos, Symbols::TypeArgumentsParameter());
-    pos++;
+  if (parameter_count > 0) {
+    signature.set_parameter_types(
+        Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
+    signature.CreateNameArrayIncludingFlags(Heap::kOld);
+    if (is_method) {
+      ASSERT(!klass.IsNull());
+      signature.SetParameterTypeAt(pos, H.GetDeclarationType(klass));
+      signature.SetParameterNameAt(pos, Symbols::This());
+      pos++;
+    } else if (is_closure) {
+      signature.SetParameterTypeAt(pos, AbstractType::dynamic_type());
+      signature.SetParameterNameAt(pos, Symbols::ClosureParameter());
+      pos++;
+    } else if (is_factory) {
+      signature.SetParameterTypeAt(pos, AbstractType::dynamic_type());
+      signature.SetParameterNameAt(pos, Symbols::TypeArgumentsParameter());
+      pos++;
+    }
+  } else {
+    ASSERT(!is_method && !is_closure && !is_factory);
   }
 
   const Library& lib = Library::Handle(Z, active_class_->klass->library());
@@ -3587,8 +3602,9 @@
       helper_->SkipExpression();  // read (actual) initializer.
     }
 
-    function.SetParameterTypeAt(pos, type);
-    function.SetParameterNameAt(pos, H.DartIdentifier(lib, helper.name_index_));
+    signature.SetParameterTypeAt(pos, type);
+    signature.SetParameterNameAt(pos,
+                                 H.DartIdentifier(lib, helper.name_index_));
   }
 
   intptr_t named_parameter_count_check =
@@ -3604,13 +3620,14 @@
       helper_->SkipExpression();  // read (actual) initializer.
     }
 
-    function.SetParameterTypeAt(pos, type);
-    function.SetParameterNameAt(pos, H.DartIdentifier(lib, helper.name_index_));
+    signature.SetParameterTypeAt(pos, type);
+    signature.SetParameterNameAt(pos,
+                                 H.DartIdentifier(lib, helper.name_index_));
     if (helper.IsRequired()) {
-      function.SetIsRequiredAt(pos);
+      signature.SetIsRequiredAt(pos);
     }
   }
-  function.TruncateUnusedParameterFlags();
+  signature.FinalizeNameArrays(function);
 
   function_node_helper->SetJustRead(FunctionNodeHelper::kNamedParameters);
 
@@ -3618,7 +3635,7 @@
   if (!function.IsGenerativeConstructor()) {
     const AbstractType& return_type =
         BuildTypeWithoutFinalization();  // read return type.
-    function.set_result_type(return_type);
+    signature.set_result_type(return_type);
     function_node_helper->SetJustRead(FunctionNodeHelper::kReturnType);
   }
 }
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 23db44d..52454ac 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -1365,9 +1365,9 @@
 
   const Function* member;
 
-  // The innermost enclosing function. This is used for building types, as a
+  // The innermost enclosing signature. This is used for building types, as a
   // parent for function types.
-  const Function* enclosing;
+  const FunctionType* enclosing;
 
   const TypeArguments* local_type_parameters;
 
@@ -1410,9 +1410,9 @@
 class ActiveEnclosingFunctionScope {
  public:
   ActiveEnclosingFunctionScope(ActiveClass* active_class,
-                               const Function* enclosing)
+                               const FunctionType* enclosing_signature)
       : active_class_(active_class), saved_(*active_class) {
-    active_class_->enclosing = enclosing;
+    active_class_->enclosing = enclosing_signature;
   }
 
   ~ActiveEnclosingFunctionScope() { *active_class_ = saved_; }
@@ -1430,16 +1430,17 @@
   // parameters defined by 'innermost' and any enclosing *closures* (but not
   // enclosing methods/top-level functions/classes).
   //
-  // Also, the enclosing function is set to 'innermost'.
+  // Also, the enclosing signature is set to innermost's signature.
   ActiveTypeParametersScope(ActiveClass* active_class,
                             const Function& innermost,
+                            const FunctionType* innermost_signature,
                             Zone* Z);
 
   // Append the list of the local type parameters to the list in ActiveClass.
   //
-  // Also, the enclosing function is set to 'function'.
+  // Also, the enclosing signature is set to 'signature'.
   ActiveTypeParametersScope(ActiveClass* active_class,
-                            const Function* function,
+                            const FunctionType* innermost_signature,
                             const TypeArguments& new_params,
                             Zone* Z);
 
@@ -1470,9 +1471,11 @@
       intptr_t length);
 
   void LoadAndSetupTypeParameters(ActiveClass* active_class,
-                                  const Object& set_on,
+                                  const Function& function,
+                                  const Class& parameterized_class,
+                                  const FunctionType& parameterized_signature,
                                   intptr_t type_parameter_count,
-                                  const Function& parameterized_function);
+                                  const NNBDMode nnbd_mode);
 
   const Type& ReceiverType(const Class& klass);
 
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 4c6f1af..0d6d036 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -54,14 +54,16 @@
 
   // Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used
   // e.g. for type translation.
-  const Class& klass = Class::Handle(zone_, function.Owner());
+  const Class& klass = Class::Handle(Z, function.Owner());
 
   Function& outermost_function =
       Function::Handle(Z, function.GetOutermostFunction());
 
   ActiveClassScope active_class_scope(&active_class_, &klass);
   ActiveMemberScope active_member(&active_class_, &outermost_function);
-  ActiveTypeParametersScope active_type_params(&active_class_, function, Z);
+  FunctionType& signature = FunctionType::Handle(Z, function.signature());
+  ActiveTypeParametersScope active_type_params(&active_class_, function,
+                                               &signature, Z);
 
   LocalScope* enclosing_scope = NULL;
   if (function.IsImplicitClosureFunction() && !function.is_static()) {
@@ -88,7 +90,7 @@
   scope_->set_end_token_pos(function.end_token_pos());
 
   // Add function type arguments variable before current context variable.
-  if ((function.IsGeneric() || function.HasGenericParent())) {
+  if (function.IsGeneric() || function.HasGenericParent()) {
     LocalVariable* type_args_var = MakeVariable(
         TokenPosition::kNoSource, TokenPosition::kNoSource,
         Symbols::FunctionTypeArgumentsVar(), AbstractType::dynamic_type());
@@ -419,7 +421,6 @@
       }
       break;
     }
-    case FunctionLayout::kSignatureFunction:
     case FunctionLayout::kIrregexpFunction:
       UNREACHABLE();
   }
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 6c80aa5..e104c69 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -232,7 +232,7 @@
   V(_RegExp, _ExecuteMatch, RegExp_ExecuteMatch, 0xd8114d5f)                   \
   V(_RegExp, _ExecuteMatchSticky, RegExp_ExecuteMatchSticky, 0xd0dd0025)       \
   V(Object, ==, ObjectEquals, 0xd3f5f95a)                                      \
-  V(Object, get:runtimeType, ObjectRuntimeType, 0x8177627e)                    \
+  V(Object, get:runtimeType, ObjectRuntimeType, 0x81775ebd)                    \
   V(Object, _haveSameRuntimeType, ObjectHaveSameRuntimeType, 0xe61da79f)       \
   V(_StringBase, get:hashCode, String_getHashCode, 0x4e27ab52)                 \
   V(_StringBase, get:_identityHashCode, String_identityHash, 0x1fec4010)       \
@@ -246,6 +246,8 @@
   V(_TwoByteString, ==, TwoByteString_equality, 0x483ef8d2)                    \
   V(_Type, get:hashCode, Type_getHashCode, 0x4e27ab52)                         \
   V(_Type, ==, Type_equality, 0xd3f5f1d8)                                      \
+  V(_FunctionType, get:hashCode, FunctionType_getHashCode, 0x4e27ab52)         \
+  V(_FunctionType, ==, FunctionType_equality, 0xd3f5f1d8)                      \
   V(::, _getHash, Object_getHash, 0x1d1372ac)                                  \
   V(::, _setHash, Object_setHash, 0x77e0bb27)                                  \
 
@@ -434,7 +436,7 @@
   V(_TypedList, _setFloat64, ByteArrayBaseSetFloat64, 0x1b858d66)              \
   V(_TypedList, _setFloat32x4, ByteArrayBaseSetFloat32x4, 0x9e2320c0)          \
   V(_TypedList, _setInt32x4, ByteArrayBaseSetInt32x4, 0xfa1f5cf1)              \
-  V(Object, get:runtimeType, ObjectRuntimeType, 0x8177627e)
+  V(Object, get:runtimeType, ObjectRuntimeType, 0x81775ebd)
 
 // List of recognized list factories:
 // (factory-name-symbol, class-name-string, constructor-name-string,
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index e2965c9..31b95b2 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -823,12 +823,12 @@
 
 const word String::kHashBits = dart::String::kHashBits;
 
-const int8_t Nullability::kNullable =
-    static_cast<int8_t>(dart::Nullability::kNullable);
-const int8_t Nullability::kNonNullable =
-    static_cast<int8_t>(dart::Nullability::kNonNullable);
-const int8_t Nullability::kLegacy =
-    static_cast<int8_t>(dart::Nullability::kLegacy);
+const uint8_t Nullability::kNullable =
+    static_cast<uint8_t>(dart::Nullability::kNullable);
+const uint8_t Nullability::kNonNullable =
+    static_cast<uint8_t>(dart::Nullability::kNonNullable);
+const uint8_t Nullability::kLegacy =
+    static_cast<uint8_t>(dart::Nullability::kLegacy);
 
 bool Heap::IsAllocatableInNewSpace(intptr_t instance_size) {
   return dart::Heap::IsAllocatableInNewSpace(instance_size);
@@ -920,10 +920,18 @@
   return -kWordSize;
 }
 
+word AbstractType::NextFieldOffset() {
+  return -kWordSize;
+}
+
 word Type::NextFieldOffset() {
   return -kWordSize;
 }
 
+word FunctionType::NextFieldOffset() {
+  return -kWordSize;
+}
+
 word TypeRef::NextFieldOffset() {
   return -kWordSize;
 }
@@ -980,10 +988,6 @@
   return -kWordSize;
 }
 
-word SignatureData::NextFieldOffset() {
-  return -kWordSize;
-}
-
 word FfiTrampolineData::NextFieldOffset() {
   return -kWordSize;
 }
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 0aa1329..9af3244 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -501,8 +501,7 @@
   static word kind_tag_offset();
   static word packed_fields_offset();
   static word parameter_names_offset();
-  static word parameter_types_offset();
-  static word type_parameters_offset();
+  static word signature_offset();
   static word usage_counter_offset();
   static word InstanceSize();
   static word NextFieldOffset();
@@ -656,6 +655,8 @@
 class AbstractType : public AllStatic {
  public:
   static word type_test_stub_entry_point_offset();
+  static word InstanceSize();
+  static word NextFieldOffset();
 };
 
 class Type : public AllStatic {
@@ -663,13 +664,24 @@
   static word hash_offset();
   static word type_state_offset();
   static word arguments_offset();
-  static word signature_offset();
   static word type_class_id_offset();
   static word nullability_offset();
   static word InstanceSize();
   static word NextFieldOffset();
 };
 
+class FunctionType : public AllStatic {
+ public:
+  static word hash_offset();
+  static word type_state_offset();
+  static word packed_fields_offset();
+  static word parameter_types_offset();
+  static word type_parameters_offset();
+  static word nullability_offset();
+  static word InstanceSize();
+  static word NextFieldOffset();
+};
+
 class TypeRef : public AllStatic {
  public:
   static word type_offset();
@@ -679,9 +691,9 @@
 
 class Nullability : public AllStatic {
  public:
-  static const int8_t kNullable;
-  static const int8_t kNonNullable;
-  static const int8_t kLegacy;
+  static const uint8_t kNullable;
+  static const uint8_t kNonNullable;
+  static const uint8_t kLegacy;
 };
 
 class Double : public AllStatic {
@@ -770,12 +782,6 @@
   static word NextFieldOffset();
 };
 
-class SignatureData : public AllStatic {
- public:
-  static word InstanceSize();
-  static word NextFieldOffset();
-};
-
 class FfiTrampolineData : public AllStatic {
  public:
   static word InstanceSize();
@@ -1125,6 +1131,7 @@
   static word double_type_offset();
   static word int_type_offset();
   static word string_type_offset();
+  static word type_type_offset();
 };
 
 class Isolate : public AllStatic {
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index e48bedc..eb7276a 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -19,7 +19,7 @@
 
 #if defined(TARGET_ARCH_ARM)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    84;
+    76;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
 static constexpr dart::compiler::target::word ObjectPool_elements_start_offset =
@@ -86,12 +86,12 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    56;
+    52;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
-    92;
+    88;
 static constexpr dart::compiler::target::word Class_super_type_offset = 44;
 static constexpr dart::compiler::target::word
-    Class_host_type_arguments_field_offset_in_words_offset = 104;
+    Class_host_type_arguments_field_offset_in_words_offset = 100;
 static constexpr dart::compiler::target::word
     SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 20;
@@ -104,9 +104,9 @@
 static constexpr dart::compiler::target::word
     Closure_instantiator_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_offset = 20;
+    ClosureData_default_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_info_offset = 24;
+    ClosureData_default_type_arguments_info_offset = 20;
 static constexpr dart::compiler::target::word Code_object_pool_offset = 20;
 static constexpr dart::compiler::target::word Code_saved_instructions_offset =
     24;
@@ -131,19 +131,16 @@
     24;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 54;
-static constexpr dart::compiler::target::word Function_code_offset = 44;
-static constexpr dart::compiler::target::word Function_data_offset = 36;
+static constexpr dart::compiler::target::word Function_code_offset = 36;
+static constexpr dart::compiler::target::word Function_data_offset = 28;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
-static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
+static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    76;
+    68;
 static constexpr dart::compiler::target::word Function_parameter_names_offset =
-    28;
-static constexpr dart::compiler::target::word Function_parameter_types_offset =
-    24;
-static constexpr dart::compiler::target::word Function_type_parameters_offset =
-    32;
+    20;
+static constexpr dart::compiler::target::word Function_signature_offset = 24;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -201,6 +198,7 @@
 static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 68;
 static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
     156;
+static constexpr dart::compiler::target::word ObjectStore_type_type_offset = 48;
 static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
 static constexpr dart::compiler::target::word PointerBase_data_field_offset = 4;
 static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -388,15 +386,21 @@
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Type_hash_offset = 20;
-static constexpr dart::compiler::target::word Type_signature_offset = 24;
 static constexpr dart::compiler::target::word Type_type_class_id_offset = 12;
-static constexpr dart::compiler::target::word Type_type_state_offset = 32;
-static constexpr dart::compiler::target::word Type_nullability_offset = 33;
+static constexpr dart::compiler::target::word Type_type_state_offset = 24;
+static constexpr dart::compiler::target::word Type_nullability_offset = 25;
+static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    TypeParameter_parameterized_class_id_offset = 32;
-static constexpr dart::compiler::target::word TypeParameter_index_offset = 40;
+    FunctionType_packed_fields_offset = 32;
+static constexpr dart::compiler::target::word
+    FunctionType_parameter_types_offset = 20;
+static constexpr dart::compiler::target::word
+    FunctionType_type_parameters_offset = 12;
+static constexpr dart::compiler::target::word
+    TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 32;
 static constexpr dart::compiler::target::word TypeParameter_nullability_offset =
-    43;
+    35;
 static constexpr dart::compiler::target::word
     TypeArguments_instantiations_offset = 4;
 static constexpr dart::compiler::target::word TypeArguments_length_offset = 8;
@@ -404,7 +408,7 @@
     16;
 static constexpr dart::compiler::target::word TypeArguments_types_offset = 20;
 static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20;
-static constexpr dart::compiler::target::word TypeParameter_flags_offset = 42;
+static constexpr dart::compiler::target::word TypeParameter_flags_offset = 34;
 static constexpr dart::compiler::target::word TypeParameter_name_offset = 12;
 static constexpr dart::compiler::target::word TypeRef_type_offset = 12;
 static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8;
@@ -438,14 +442,15 @@
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
         660, 664, 668, 672, 676, -1, 680, -1, 684, 688, -1, -1, -1, -1, -1, -1};
+static constexpr dart::compiler::target::word AbstractType_InstanceSize = 12;
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word Array_header_size = 12;
 static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
 static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word Class_InstanceSize = 128;
+static constexpr dart::compiler::target::word Class_InstanceSize = 124;
 static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
-static constexpr dart::compiler::target::word ClosureData_InstanceSize = 28;
+static constexpr dart::compiler::target::word ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word Code_InstanceSize = 96;
 static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
 static constexpr dart::compiler::target::word CompressedStackMaps_HeaderSize =
@@ -468,7 +473,8 @@
 static constexpr dart::compiler::target::word Field_InstanceSize = 60;
 static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word Function_InstanceSize = 96;
+static constexpr dart::compiler::target::word Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word FunctionType_InstanceSize = 40;
 static constexpr dart::compiler::target::word FutureOr_InstanceSize = 8;
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     16;
@@ -507,7 +513,6 @@
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word Script_InstanceSize = 64;
 static constexpr dart::compiler::target::word SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word SignatureData_InstanceSize = 12;
 static constexpr dart::compiler::target::word SingleTargetCache_InstanceSize =
     16;
 static constexpr dart::compiler::target::word Smi_InstanceSize = 4;
@@ -518,9 +523,9 @@
 static constexpr dart::compiler::target::word
     TransferableTypedData_InstanceSize = 4;
 static constexpr dart::compiler::target::word TwoByteString_InstanceSize = 12;
-static constexpr dart::compiler::target::word Type_InstanceSize = 36;
+static constexpr dart::compiler::target::word Type_InstanceSize = 28;
 static constexpr dart::compiler::target::word TypeArguments_InstanceSize = 20;
-static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 44;
+static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 36;
 static constexpr dart::compiler::target::word TypeRef_InstanceSize = 16;
 static constexpr dart::compiler::target::word TypedData_InstanceSize = 12;
 static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12;
@@ -537,7 +542,7 @@
 
 #if defined(TARGET_ARCH_X64)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    132;
+    116;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word ObjectPool_elements_start_offset =
@@ -606,12 +611,12 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    112;
+    104;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
-    172;
+    164;
 static constexpr dart::compiler::target::word Class_super_type_offset = 88;
 static constexpr dart::compiler::target::word
-    Class_host_type_arguments_field_offset_in_words_offset = 184;
+    Class_host_type_arguments_field_offset_in_words_offset = 176;
 static constexpr dart::compiler::target::word
     SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 40;
@@ -624,9 +629,9 @@
 static constexpr dart::compiler::target::word
     Closure_instantiator_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_offset = 40;
+    ClosureData_default_type_arguments_offset = 32;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_info_offset = 48;
+    ClosureData_default_type_arguments_info_offset = 40;
 static constexpr dart::compiler::target::word Code_object_pool_offset = 40;
 static constexpr dart::compiler::target::word Code_saved_instructions_offset =
     48;
@@ -651,19 +656,16 @@
     48;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 90;
-static constexpr dart::compiler::target::word Function_code_offset = 88;
-static constexpr dart::compiler::target::word Function_data_offset = 72;
+static constexpr dart::compiler::target::word Function_code_offset = 72;
+static constexpr dart::compiler::target::word Function_data_offset = 56;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
-static constexpr dart::compiler::target::word Function_kind_tag_offset = 120;
+static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    124;
+    108;
 static constexpr dart::compiler::target::word Function_parameter_names_offset =
-    56;
-static constexpr dart::compiler::target::word Function_parameter_types_offset =
-    48;
-static constexpr dart::compiler::target::word Function_type_parameters_offset =
-    64;
+    40;
+static constexpr dart::compiler::target::word Function_signature_offset = 48;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -721,6 +723,7 @@
 static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 136;
 static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
     312;
+static constexpr dart::compiler::target::word ObjectStore_type_type_offset = 96;
 static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
 static constexpr dart::compiler::target::word PointerBase_data_field_offset = 8;
 static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -912,15 +915,21 @@
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
 static constexpr dart::compiler::target::word Type_arguments_offset = 32;
 static constexpr dart::compiler::target::word Type_hash_offset = 40;
-static constexpr dart::compiler::target::word Type_signature_offset = 48;
 static constexpr dart::compiler::target::word Type_type_class_id_offset = 24;
-static constexpr dart::compiler::target::word Type_type_state_offset = 60;
-static constexpr dart::compiler::target::word Type_nullability_offset = 61;
+static constexpr dart::compiler::target::word Type_type_state_offset = 48;
+static constexpr dart::compiler::target::word Type_nullability_offset = 49;
+static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    TypeParameter_parameterized_class_id_offset = 64;
-static constexpr dart::compiler::target::word TypeParameter_index_offset = 72;
+    FunctionType_packed_fields_offset = 64;
+static constexpr dart::compiler::target::word
+    FunctionType_parameter_types_offset = 40;
+static constexpr dart::compiler::target::word
+    FunctionType_type_parameters_offset = 24;
+static constexpr dart::compiler::target::word
+    TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 60;
 static constexpr dart::compiler::target::word TypeParameter_nullability_offset =
-    75;
+    63;
 static constexpr dart::compiler::target::word
     TypeArguments_instantiations_offset = 8;
 static constexpr dart::compiler::target::word TypeArguments_length_offset = 16;
@@ -928,7 +937,7 @@
     32;
 static constexpr dart::compiler::target::word TypeArguments_types_offset = 40;
 static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40;
-static constexpr dart::compiler::target::word TypeParameter_flags_offset = 74;
+static constexpr dart::compiler::target::word TypeParameter_flags_offset = 62;
 static constexpr dart::compiler::target::word TypeParameter_name_offset = 24;
 static constexpr dart::compiler::target::word TypeRef_type_offset = 24;
 static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16;
@@ -963,14 +972,15 @@
     Thread_write_barrier_wrappers_thread_offset[] = {
         1304, 1312, 1320, 1328, -1,   -1,   1336, 1344,
         1352, 1360, 1368, -1,   1376, 1384, -1,   -1};
+static constexpr dart::compiler::target::word AbstractType_InstanceSize = 24;
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word Array_header_size = 24;
 static constexpr dart::compiler::target::word Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word Class_InstanceSize = 208;
+static constexpr dart::compiler::target::word Class_InstanceSize = 200;
 static constexpr dart::compiler::target::word Closure_InstanceSize = 56;
-static constexpr dart::compiler::target::word ClosureData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ClosureData_InstanceSize = 48;
 static constexpr dart::compiler::target::word Code_InstanceSize = 176;
 static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word CompressedStackMaps_HeaderSize =
@@ -993,7 +1003,8 @@
 static constexpr dart::compiler::target::word Field_InstanceSize = 96;
 static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word Function_InstanceSize = 144;
+static constexpr dart::compiler::target::word Function_InstanceSize = 128;
+static constexpr dart::compiler::target::word FunctionType_InstanceSize = 72;
 static constexpr dart::compiler::target::word FutureOr_InstanceSize = 16;
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     32;
@@ -1032,7 +1043,6 @@
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word Script_InstanceSize = 104;
 static constexpr dart::compiler::target::word SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word SignatureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word SingleTargetCache_InstanceSize =
     32;
 static constexpr dart::compiler::target::word Smi_InstanceSize = 8;
@@ -1044,9 +1054,9 @@
 static constexpr dart::compiler::target::word
     TransferableTypedData_InstanceSize = 8;
 static constexpr dart::compiler::target::word TwoByteString_InstanceSize = 16;
-static constexpr dart::compiler::target::word Type_InstanceSize = 64;
+static constexpr dart::compiler::target::word Type_InstanceSize = 56;
 static constexpr dart::compiler::target::word TypeArguments_InstanceSize = 40;
-static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 80;
+static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 64;
 static constexpr dart::compiler::target::word TypeRef_InstanceSize = 32;
 static constexpr dart::compiler::target::word TypedData_InstanceSize = 24;
 static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24;
@@ -1063,7 +1073,7 @@
 
 #if defined(TARGET_ARCH_IA32)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    84;
+    76;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
 static constexpr dart::compiler::target::word ObjectPool_elements_start_offset =
@@ -1130,12 +1140,12 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    56;
+    52;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
-    92;
+    88;
 static constexpr dart::compiler::target::word Class_super_type_offset = 44;
 static constexpr dart::compiler::target::word
-    Class_host_type_arguments_field_offset_in_words_offset = 104;
+    Class_host_type_arguments_field_offset_in_words_offset = 100;
 static constexpr dart::compiler::target::word
     SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 20;
@@ -1148,9 +1158,9 @@
 static constexpr dart::compiler::target::word
     Closure_instantiator_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_offset = 20;
+    ClosureData_default_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_info_offset = 24;
+    ClosureData_default_type_arguments_info_offset = 20;
 static constexpr dart::compiler::target::word Code_object_pool_offset = 20;
 static constexpr dart::compiler::target::word Code_saved_instructions_offset =
     24;
@@ -1175,19 +1185,16 @@
     24;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 54;
-static constexpr dart::compiler::target::word Function_code_offset = 44;
-static constexpr dart::compiler::target::word Function_data_offset = 36;
+static constexpr dart::compiler::target::word Function_code_offset = 36;
+static constexpr dart::compiler::target::word Function_data_offset = 28;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
-static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
+static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    76;
+    68;
 static constexpr dart::compiler::target::word Function_parameter_names_offset =
-    28;
-static constexpr dart::compiler::target::word Function_parameter_types_offset =
-    24;
-static constexpr dart::compiler::target::word Function_type_parameters_offset =
-    32;
+    20;
+static constexpr dart::compiler::target::word Function_signature_offset = 24;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -1245,6 +1252,7 @@
 static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 68;
 static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
     156;
+static constexpr dart::compiler::target::word ObjectStore_type_type_offset = 48;
 static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
 static constexpr dart::compiler::target::word PointerBase_data_field_offset = 4;
 static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -1432,15 +1440,21 @@
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Type_hash_offset = 20;
-static constexpr dart::compiler::target::word Type_signature_offset = 24;
 static constexpr dart::compiler::target::word Type_type_class_id_offset = 12;
-static constexpr dart::compiler::target::word Type_type_state_offset = 32;
-static constexpr dart::compiler::target::word Type_nullability_offset = 33;
+static constexpr dart::compiler::target::word Type_type_state_offset = 24;
+static constexpr dart::compiler::target::word Type_nullability_offset = 25;
+static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    TypeParameter_parameterized_class_id_offset = 32;
-static constexpr dart::compiler::target::word TypeParameter_index_offset = 40;
+    FunctionType_packed_fields_offset = 32;
+static constexpr dart::compiler::target::word
+    FunctionType_parameter_types_offset = 20;
+static constexpr dart::compiler::target::word
+    FunctionType_type_parameters_offset = 12;
+static constexpr dart::compiler::target::word
+    TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 32;
 static constexpr dart::compiler::target::word TypeParameter_nullability_offset =
-    43;
+    35;
 static constexpr dart::compiler::target::word
     TypeArguments_instantiations_offset = 4;
 static constexpr dart::compiler::target::word TypeArguments_length_offset = 8;
@@ -1448,7 +1462,7 @@
     16;
 static constexpr dart::compiler::target::word TypeArguments_types_offset = 20;
 static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20;
-static constexpr dart::compiler::target::word TypeParameter_flags_offset = 42;
+static constexpr dart::compiler::target::word TypeParameter_flags_offset = 34;
 static constexpr dart::compiler::target::word TypeParameter_name_offset = 12;
 static constexpr dart::compiler::target::word TypeRef_type_offset = 12;
 static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8;
@@ -1479,14 +1493,15 @@
 static constexpr dart::compiler::target::word ClassTable_element_size = 1;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
+static constexpr dart::compiler::target::word AbstractType_InstanceSize = 12;
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word Array_header_size = 12;
 static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
 static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word Class_InstanceSize = 128;
+static constexpr dart::compiler::target::word Class_InstanceSize = 124;
 static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
-static constexpr dart::compiler::target::word ClosureData_InstanceSize = 28;
+static constexpr dart::compiler::target::word ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word Code_InstanceSize = 96;
 static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
 static constexpr dart::compiler::target::word CompressedStackMaps_HeaderSize =
@@ -1509,7 +1524,8 @@
 static constexpr dart::compiler::target::word Field_InstanceSize = 60;
 static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word Function_InstanceSize = 96;
+static constexpr dart::compiler::target::word Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word FunctionType_InstanceSize = 40;
 static constexpr dart::compiler::target::word FutureOr_InstanceSize = 8;
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     16;
@@ -1548,7 +1564,6 @@
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word Script_InstanceSize = 64;
 static constexpr dart::compiler::target::word SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word SignatureData_InstanceSize = 12;
 static constexpr dart::compiler::target::word SingleTargetCache_InstanceSize =
     16;
 static constexpr dart::compiler::target::word Smi_InstanceSize = 4;
@@ -1559,9 +1574,9 @@
 static constexpr dart::compiler::target::word
     TransferableTypedData_InstanceSize = 4;
 static constexpr dart::compiler::target::word TwoByteString_InstanceSize = 12;
-static constexpr dart::compiler::target::word Type_InstanceSize = 36;
+static constexpr dart::compiler::target::word Type_InstanceSize = 28;
 static constexpr dart::compiler::target::word TypeArguments_InstanceSize = 20;
-static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 44;
+static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 36;
 static constexpr dart::compiler::target::word TypeRef_InstanceSize = 16;
 static constexpr dart::compiler::target::word TypedData_InstanceSize = 12;
 static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12;
@@ -1578,7 +1593,7 @@
 
 #if defined(TARGET_ARCH_ARM64)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    132;
+    116;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word ObjectPool_elements_start_offset =
@@ -1647,12 +1662,12 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    112;
+    104;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
-    172;
+    164;
 static constexpr dart::compiler::target::word Class_super_type_offset = 88;
 static constexpr dart::compiler::target::word
-    Class_host_type_arguments_field_offset_in_words_offset = 184;
+    Class_host_type_arguments_field_offset_in_words_offset = 176;
 static constexpr dart::compiler::target::word
     SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word Closure_context_offset = 40;
@@ -1665,9 +1680,9 @@
 static constexpr dart::compiler::target::word
     Closure_instantiator_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_offset = 40;
+    ClosureData_default_type_arguments_offset = 32;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_info_offset = 48;
+    ClosureData_default_type_arguments_info_offset = 40;
 static constexpr dart::compiler::target::word Code_object_pool_offset = 40;
 static constexpr dart::compiler::target::word Code_saved_instructions_offset =
     48;
@@ -1692,19 +1707,16 @@
     48;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 90;
-static constexpr dart::compiler::target::word Function_code_offset = 88;
-static constexpr dart::compiler::target::word Function_data_offset = 72;
+static constexpr dart::compiler::target::word Function_code_offset = 72;
+static constexpr dart::compiler::target::word Function_data_offset = 56;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
-static constexpr dart::compiler::target::word Function_kind_tag_offset = 120;
+static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    124;
+    108;
 static constexpr dart::compiler::target::word Function_parameter_names_offset =
-    56;
-static constexpr dart::compiler::target::word Function_parameter_types_offset =
-    48;
-static constexpr dart::compiler::target::word Function_type_parameters_offset =
-    64;
+    40;
+static constexpr dart::compiler::target::word Function_signature_offset = 48;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -1762,6 +1774,7 @@
 static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 136;
 static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
     312;
+static constexpr dart::compiler::target::word ObjectStore_type_type_offset = 96;
 static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
 static constexpr dart::compiler::target::word PointerBase_data_field_offset = 8;
 static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -1953,15 +1966,21 @@
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
 static constexpr dart::compiler::target::word Type_arguments_offset = 32;
 static constexpr dart::compiler::target::word Type_hash_offset = 40;
-static constexpr dart::compiler::target::word Type_signature_offset = 48;
 static constexpr dart::compiler::target::word Type_type_class_id_offset = 24;
-static constexpr dart::compiler::target::word Type_type_state_offset = 60;
-static constexpr dart::compiler::target::word Type_nullability_offset = 61;
+static constexpr dart::compiler::target::word Type_type_state_offset = 48;
+static constexpr dart::compiler::target::word Type_nullability_offset = 49;
+static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    TypeParameter_parameterized_class_id_offset = 64;
-static constexpr dart::compiler::target::word TypeParameter_index_offset = 72;
+    FunctionType_packed_fields_offset = 64;
+static constexpr dart::compiler::target::word
+    FunctionType_parameter_types_offset = 40;
+static constexpr dart::compiler::target::word
+    FunctionType_type_parameters_offset = 24;
+static constexpr dart::compiler::target::word
+    TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 60;
 static constexpr dart::compiler::target::word TypeParameter_nullability_offset =
-    75;
+    63;
 static constexpr dart::compiler::target::word
     TypeArguments_instantiations_offset = 8;
 static constexpr dart::compiler::target::word TypeArguments_length_offset = 16;
@@ -1969,7 +1988,7 @@
     32;
 static constexpr dart::compiler::target::word TypeArguments_types_offset = 40;
 static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40;
-static constexpr dart::compiler::target::word TypeParameter_flags_offset = 74;
+static constexpr dart::compiler::target::word TypeParameter_flags_offset = 62;
 static constexpr dart::compiler::target::word TypeParameter_name_offset = 24;
 static constexpr dart::compiler::target::word TypeRef_type_offset = 24;
 static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16;
@@ -2005,14 +2024,15 @@
         1304, 1312, 1320, 1328, 1336, 1344, 1352, 1360, 1368, 1376, 1384,
         1392, 1400, 1408, 1416, -1,   -1,   -1,   -1,   1424, 1432, -1,
         -1,   1440, 1448, 1456, -1,   -1,   -1,   -1,   -1,   -1};
+static constexpr dart::compiler::target::word AbstractType_InstanceSize = 24;
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word Array_header_size = 24;
 static constexpr dart::compiler::target::word Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word Class_InstanceSize = 208;
+static constexpr dart::compiler::target::word Class_InstanceSize = 200;
 static constexpr dart::compiler::target::word Closure_InstanceSize = 56;
-static constexpr dart::compiler::target::word ClosureData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ClosureData_InstanceSize = 48;
 static constexpr dart::compiler::target::word Code_InstanceSize = 176;
 static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word CompressedStackMaps_HeaderSize =
@@ -2035,7 +2055,8 @@
 static constexpr dart::compiler::target::word Field_InstanceSize = 96;
 static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word Function_InstanceSize = 144;
+static constexpr dart::compiler::target::word Function_InstanceSize = 128;
+static constexpr dart::compiler::target::word FunctionType_InstanceSize = 72;
 static constexpr dart::compiler::target::word FutureOr_InstanceSize = 16;
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     32;
@@ -2074,7 +2095,6 @@
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word Script_InstanceSize = 104;
 static constexpr dart::compiler::target::word SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word SignatureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word SingleTargetCache_InstanceSize =
     32;
 static constexpr dart::compiler::target::word Smi_InstanceSize = 8;
@@ -2086,9 +2106,9 @@
 static constexpr dart::compiler::target::word
     TransferableTypedData_InstanceSize = 8;
 static constexpr dart::compiler::target::word TwoByteString_InstanceSize = 16;
-static constexpr dart::compiler::target::word Type_InstanceSize = 64;
+static constexpr dart::compiler::target::word Type_InstanceSize = 56;
 static constexpr dart::compiler::target::word TypeArguments_InstanceSize = 40;
-static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 80;
+static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 64;
 static constexpr dart::compiler::target::word TypeRef_InstanceSize = 32;
 static constexpr dart::compiler::target::word TypedData_InstanceSize = 24;
 static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24;
@@ -2107,7 +2127,7 @@
 
 #if defined(TARGET_ARCH_ARM)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    84;
+    76;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
 static constexpr dart::compiler::target::word ObjectPool_elements_start_offset =
@@ -2174,12 +2194,12 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    56;
+    52;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
-    92;
+    88;
 static constexpr dart::compiler::target::word Class_super_type_offset = 44;
 static constexpr dart::compiler::target::word
-    Class_host_type_arguments_field_offset_in_words_offset = 104;
+    Class_host_type_arguments_field_offset_in_words_offset = 100;
 static constexpr dart::compiler::target::word Closure_context_offset = 20;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 12;
@@ -2190,9 +2210,9 @@
 static constexpr dart::compiler::target::word
     Closure_instantiator_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_offset = 20;
+    ClosureData_default_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_info_offset = 24;
+    ClosureData_default_type_arguments_info_offset = 20;
 static constexpr dart::compiler::target::word Code_object_pool_offset = 20;
 static constexpr dart::compiler::target::word Code_saved_instructions_offset =
     24;
@@ -2217,19 +2237,16 @@
     24;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 54;
-static constexpr dart::compiler::target::word Function_code_offset = 44;
-static constexpr dart::compiler::target::word Function_data_offset = 36;
+static constexpr dart::compiler::target::word Function_code_offset = 36;
+static constexpr dart::compiler::target::word Function_data_offset = 28;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
-static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
+static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    76;
+    68;
 static constexpr dart::compiler::target::word Function_parameter_names_offset =
-    28;
-static constexpr dart::compiler::target::word Function_parameter_types_offset =
-    24;
-static constexpr dart::compiler::target::word Function_type_parameters_offset =
-    32;
+    20;
+static constexpr dart::compiler::target::word Function_signature_offset = 24;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -2286,6 +2303,7 @@
 static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 68;
 static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
     156;
+static constexpr dart::compiler::target::word ObjectStore_type_type_offset = 48;
 static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
 static constexpr dart::compiler::target::word PointerBase_data_field_offset = 4;
 static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -2473,15 +2491,21 @@
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Type_hash_offset = 20;
-static constexpr dart::compiler::target::word Type_signature_offset = 24;
 static constexpr dart::compiler::target::word Type_type_class_id_offset = 12;
-static constexpr dart::compiler::target::word Type_type_state_offset = 32;
-static constexpr dart::compiler::target::word Type_nullability_offset = 33;
+static constexpr dart::compiler::target::word Type_type_state_offset = 24;
+static constexpr dart::compiler::target::word Type_nullability_offset = 25;
+static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    TypeParameter_parameterized_class_id_offset = 32;
-static constexpr dart::compiler::target::word TypeParameter_index_offset = 40;
+    FunctionType_packed_fields_offset = 32;
+static constexpr dart::compiler::target::word
+    FunctionType_parameter_types_offset = 20;
+static constexpr dart::compiler::target::word
+    FunctionType_type_parameters_offset = 12;
+static constexpr dart::compiler::target::word
+    TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 32;
 static constexpr dart::compiler::target::word TypeParameter_nullability_offset =
-    43;
+    35;
 static constexpr dart::compiler::target::word
     TypeArguments_instantiations_offset = 4;
 static constexpr dart::compiler::target::word TypeArguments_length_offset = 8;
@@ -2489,7 +2513,7 @@
     16;
 static constexpr dart::compiler::target::word TypeArguments_types_offset = 20;
 static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20;
-static constexpr dart::compiler::target::word TypeParameter_flags_offset = 42;
+static constexpr dart::compiler::target::word TypeParameter_flags_offset = 34;
 static constexpr dart::compiler::target::word TypeParameter_name_offset = 12;
 static constexpr dart::compiler::target::word TypeRef_type_offset = 12;
 static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8;
@@ -2520,14 +2544,15 @@
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
         660, 664, 668, 672, 676, -1, 680, -1, 684, 688, -1, -1, -1, -1, -1, -1};
+static constexpr dart::compiler::target::word AbstractType_InstanceSize = 12;
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word Array_header_size = 12;
 static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
 static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word Class_InstanceSize = 128;
+static constexpr dart::compiler::target::word Class_InstanceSize = 124;
 static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
-static constexpr dart::compiler::target::word ClosureData_InstanceSize = 28;
+static constexpr dart::compiler::target::word ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word Code_InstanceSize = 76;
 static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
 static constexpr dart::compiler::target::word CompressedStackMaps_HeaderSize =
@@ -2550,7 +2575,8 @@
 static constexpr dart::compiler::target::word Field_InstanceSize = 60;
 static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word Function_InstanceSize = 96;
+static constexpr dart::compiler::target::word Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word FunctionType_InstanceSize = 40;
 static constexpr dart::compiler::target::word FutureOr_InstanceSize = 8;
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     16;
@@ -2589,7 +2615,6 @@
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word Script_InstanceSize = 56;
 static constexpr dart::compiler::target::word SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word SignatureData_InstanceSize = 12;
 static constexpr dart::compiler::target::word SingleTargetCache_InstanceSize =
     16;
 static constexpr dart::compiler::target::word Smi_InstanceSize = 4;
@@ -2600,9 +2625,9 @@
 static constexpr dart::compiler::target::word
     TransferableTypedData_InstanceSize = 4;
 static constexpr dart::compiler::target::word TwoByteString_InstanceSize = 12;
-static constexpr dart::compiler::target::word Type_InstanceSize = 36;
+static constexpr dart::compiler::target::word Type_InstanceSize = 28;
 static constexpr dart::compiler::target::word TypeArguments_InstanceSize = 20;
-static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 44;
+static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 36;
 static constexpr dart::compiler::target::word TypeRef_InstanceSize = 16;
 static constexpr dart::compiler::target::word TypedData_InstanceSize = 12;
 static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12;
@@ -2619,7 +2644,7 @@
 
 #if defined(TARGET_ARCH_X64)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    132;
+    116;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word ObjectPool_elements_start_offset =
@@ -2688,12 +2713,12 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    112;
+    104;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
-    172;
+    164;
 static constexpr dart::compiler::target::word Class_super_type_offset = 88;
 static constexpr dart::compiler::target::word
-    Class_host_type_arguments_field_offset_in_words_offset = 184;
+    Class_host_type_arguments_field_offset_in_words_offset = 176;
 static constexpr dart::compiler::target::word Closure_context_offset = 40;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 24;
@@ -2704,9 +2729,9 @@
 static constexpr dart::compiler::target::word
     Closure_instantiator_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_offset = 40;
+    ClosureData_default_type_arguments_offset = 32;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_info_offset = 48;
+    ClosureData_default_type_arguments_info_offset = 40;
 static constexpr dart::compiler::target::word Code_object_pool_offset = 40;
 static constexpr dart::compiler::target::word Code_saved_instructions_offset =
     48;
@@ -2731,19 +2756,16 @@
     48;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 90;
-static constexpr dart::compiler::target::word Function_code_offset = 88;
-static constexpr dart::compiler::target::word Function_data_offset = 72;
+static constexpr dart::compiler::target::word Function_code_offset = 72;
+static constexpr dart::compiler::target::word Function_data_offset = 56;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
-static constexpr dart::compiler::target::word Function_kind_tag_offset = 120;
+static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    124;
+    108;
 static constexpr dart::compiler::target::word Function_parameter_names_offset =
-    56;
-static constexpr dart::compiler::target::word Function_parameter_types_offset =
-    48;
-static constexpr dart::compiler::target::word Function_type_parameters_offset =
-    64;
+    40;
+static constexpr dart::compiler::target::word Function_signature_offset = 48;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -2800,6 +2822,7 @@
 static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 136;
 static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
     312;
+static constexpr dart::compiler::target::word ObjectStore_type_type_offset = 96;
 static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
 static constexpr dart::compiler::target::word PointerBase_data_field_offset = 8;
 static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -2991,15 +3014,21 @@
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
 static constexpr dart::compiler::target::word Type_arguments_offset = 32;
 static constexpr dart::compiler::target::word Type_hash_offset = 40;
-static constexpr dart::compiler::target::word Type_signature_offset = 48;
 static constexpr dart::compiler::target::word Type_type_class_id_offset = 24;
-static constexpr dart::compiler::target::word Type_type_state_offset = 60;
-static constexpr dart::compiler::target::word Type_nullability_offset = 61;
+static constexpr dart::compiler::target::word Type_type_state_offset = 48;
+static constexpr dart::compiler::target::word Type_nullability_offset = 49;
+static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    TypeParameter_parameterized_class_id_offset = 64;
-static constexpr dart::compiler::target::word TypeParameter_index_offset = 72;
+    FunctionType_packed_fields_offset = 64;
+static constexpr dart::compiler::target::word
+    FunctionType_parameter_types_offset = 40;
+static constexpr dart::compiler::target::word
+    FunctionType_type_parameters_offset = 24;
+static constexpr dart::compiler::target::word
+    TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 60;
 static constexpr dart::compiler::target::word TypeParameter_nullability_offset =
-    75;
+    63;
 static constexpr dart::compiler::target::word
     TypeArguments_instantiations_offset = 8;
 static constexpr dart::compiler::target::word TypeArguments_length_offset = 16;
@@ -3007,7 +3036,7 @@
     32;
 static constexpr dart::compiler::target::word TypeArguments_types_offset = 40;
 static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40;
-static constexpr dart::compiler::target::word TypeParameter_flags_offset = 74;
+static constexpr dart::compiler::target::word TypeParameter_flags_offset = 62;
 static constexpr dart::compiler::target::word TypeParameter_name_offset = 24;
 static constexpr dart::compiler::target::word TypeRef_type_offset = 24;
 static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16;
@@ -3039,14 +3068,15 @@
     Thread_write_barrier_wrappers_thread_offset[] = {
         1304, 1312, 1320, 1328, -1,   -1,   1336, 1344,
         1352, 1360, 1368, -1,   1376, 1384, -1,   -1};
+static constexpr dart::compiler::target::word AbstractType_InstanceSize = 24;
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word Array_header_size = 24;
 static constexpr dart::compiler::target::word Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word Class_InstanceSize = 208;
+static constexpr dart::compiler::target::word Class_InstanceSize = 200;
 static constexpr dart::compiler::target::word Closure_InstanceSize = 56;
-static constexpr dart::compiler::target::word ClosureData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ClosureData_InstanceSize = 48;
 static constexpr dart::compiler::target::word Code_InstanceSize = 144;
 static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word CompressedStackMaps_HeaderSize =
@@ -3069,7 +3099,8 @@
 static constexpr dart::compiler::target::word Field_InstanceSize = 96;
 static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word Function_InstanceSize = 144;
+static constexpr dart::compiler::target::word Function_InstanceSize = 128;
+static constexpr dart::compiler::target::word FunctionType_InstanceSize = 72;
 static constexpr dart::compiler::target::word FutureOr_InstanceSize = 16;
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     32;
@@ -3108,7 +3139,6 @@
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word Script_InstanceSize = 88;
 static constexpr dart::compiler::target::word SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word SignatureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word SingleTargetCache_InstanceSize =
     32;
 static constexpr dart::compiler::target::word Smi_InstanceSize = 8;
@@ -3120,9 +3150,9 @@
 static constexpr dart::compiler::target::word
     TransferableTypedData_InstanceSize = 8;
 static constexpr dart::compiler::target::word TwoByteString_InstanceSize = 16;
-static constexpr dart::compiler::target::word Type_InstanceSize = 64;
+static constexpr dart::compiler::target::word Type_InstanceSize = 56;
 static constexpr dart::compiler::target::word TypeArguments_InstanceSize = 40;
-static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 80;
+static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 64;
 static constexpr dart::compiler::target::word TypeRef_InstanceSize = 32;
 static constexpr dart::compiler::target::word TypedData_InstanceSize = 24;
 static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24;
@@ -3139,7 +3169,7 @@
 
 #if defined(TARGET_ARCH_IA32)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    84;
+    76;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
 static constexpr dart::compiler::target::word ObjectPool_elements_start_offset =
@@ -3206,12 +3236,12 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    56;
+    52;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
-    92;
+    88;
 static constexpr dart::compiler::target::word Class_super_type_offset = 44;
 static constexpr dart::compiler::target::word
-    Class_host_type_arguments_field_offset_in_words_offset = 104;
+    Class_host_type_arguments_field_offset_in_words_offset = 100;
 static constexpr dart::compiler::target::word Closure_context_offset = 20;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 12;
@@ -3222,9 +3252,9 @@
 static constexpr dart::compiler::target::word
     Closure_instantiator_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_offset = 20;
+    ClosureData_default_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_info_offset = 24;
+    ClosureData_default_type_arguments_info_offset = 20;
 static constexpr dart::compiler::target::word Code_object_pool_offset = 20;
 static constexpr dart::compiler::target::word Code_saved_instructions_offset =
     24;
@@ -3249,19 +3279,16 @@
     24;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 54;
-static constexpr dart::compiler::target::word Function_code_offset = 44;
-static constexpr dart::compiler::target::word Function_data_offset = 36;
+static constexpr dart::compiler::target::word Function_code_offset = 36;
+static constexpr dart::compiler::target::word Function_data_offset = 28;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
-static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
+static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    76;
+    68;
 static constexpr dart::compiler::target::word Function_parameter_names_offset =
-    28;
-static constexpr dart::compiler::target::word Function_parameter_types_offset =
-    24;
-static constexpr dart::compiler::target::word Function_type_parameters_offset =
-    32;
+    20;
+static constexpr dart::compiler::target::word Function_signature_offset = 24;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -3318,6 +3345,7 @@
 static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 68;
 static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
     156;
+static constexpr dart::compiler::target::word ObjectStore_type_type_offset = 48;
 static constexpr dart::compiler::target::word OneByteString_data_offset = 12;
 static constexpr dart::compiler::target::word PointerBase_data_field_offset = 4;
 static constexpr dart::compiler::target::word Pointer_type_arguments_offset = 8;
@@ -3505,15 +3533,21 @@
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
 static constexpr dart::compiler::target::word Type_hash_offset = 20;
-static constexpr dart::compiler::target::word Type_signature_offset = 24;
 static constexpr dart::compiler::target::word Type_type_class_id_offset = 12;
-static constexpr dart::compiler::target::word Type_type_state_offset = 32;
-static constexpr dart::compiler::target::word Type_nullability_offset = 33;
+static constexpr dart::compiler::target::word Type_type_state_offset = 24;
+static constexpr dart::compiler::target::word Type_nullability_offset = 25;
+static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    TypeParameter_parameterized_class_id_offset = 32;
-static constexpr dart::compiler::target::word TypeParameter_index_offset = 40;
+    FunctionType_packed_fields_offset = 32;
+static constexpr dart::compiler::target::word
+    FunctionType_parameter_types_offset = 20;
+static constexpr dart::compiler::target::word
+    FunctionType_type_parameters_offset = 12;
+static constexpr dart::compiler::target::word
+    TypeParameter_parameterized_class_id_offset = 28;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 32;
 static constexpr dart::compiler::target::word TypeParameter_nullability_offset =
-    43;
+    35;
 static constexpr dart::compiler::target::word
     TypeArguments_instantiations_offset = 4;
 static constexpr dart::compiler::target::word TypeArguments_length_offset = 8;
@@ -3521,7 +3555,7 @@
     16;
 static constexpr dart::compiler::target::word TypeArguments_types_offset = 20;
 static constexpr dart::compiler::target::word TypeParameter_bound_offset = 20;
-static constexpr dart::compiler::target::word TypeParameter_flags_offset = 42;
+static constexpr dart::compiler::target::word TypeParameter_flags_offset = 34;
 static constexpr dart::compiler::target::word TypeParameter_name_offset = 12;
 static constexpr dart::compiler::target::word TypeRef_type_offset = 12;
 static constexpr dart::compiler::target::word TypedDataBase_length_offset = 8;
@@ -3549,14 +3583,15 @@
 static constexpr dart::compiler::target::word TypeArguments_element_size = 4;
 static constexpr dart::compiler::target::word Code_entry_point_offset[] = {
     4, 12, 8, 16};
+static constexpr dart::compiler::target::word AbstractType_InstanceSize = 12;
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word Array_header_size = 12;
 static constexpr dart::compiler::target::word Bool_InstanceSize = 8;
 static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word Class_InstanceSize = 128;
+static constexpr dart::compiler::target::word Class_InstanceSize = 124;
 static constexpr dart::compiler::target::word Closure_InstanceSize = 28;
-static constexpr dart::compiler::target::word ClosureData_InstanceSize = 28;
+static constexpr dart::compiler::target::word ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word Code_InstanceSize = 76;
 static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 8;
 static constexpr dart::compiler::target::word CompressedStackMaps_HeaderSize =
@@ -3579,7 +3614,8 @@
 static constexpr dart::compiler::target::word Field_InstanceSize = 60;
 static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word Function_InstanceSize = 96;
+static constexpr dart::compiler::target::word Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word FunctionType_InstanceSize = 40;
 static constexpr dart::compiler::target::word FutureOr_InstanceSize = 8;
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     16;
@@ -3618,7 +3654,6 @@
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word Script_InstanceSize = 56;
 static constexpr dart::compiler::target::word SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word SignatureData_InstanceSize = 12;
 static constexpr dart::compiler::target::word SingleTargetCache_InstanceSize =
     16;
 static constexpr dart::compiler::target::word Smi_InstanceSize = 4;
@@ -3629,9 +3664,9 @@
 static constexpr dart::compiler::target::word
     TransferableTypedData_InstanceSize = 4;
 static constexpr dart::compiler::target::word TwoByteString_InstanceSize = 12;
-static constexpr dart::compiler::target::word Type_InstanceSize = 36;
+static constexpr dart::compiler::target::word Type_InstanceSize = 28;
 static constexpr dart::compiler::target::word TypeArguments_InstanceSize = 20;
-static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 44;
+static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 36;
 static constexpr dart::compiler::target::word TypeRef_InstanceSize = 16;
 static constexpr dart::compiler::target::word TypedData_InstanceSize = 12;
 static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 12;
@@ -3648,7 +3683,7 @@
 
 #if defined(TARGET_ARCH_ARM64)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    132;
+    116;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word ObjectPool_elements_start_offset =
@@ -3717,12 +3752,12 @@
 static constexpr dart::compiler::target::word Array_tags_offset = 0;
 static constexpr dart::compiler::target::word Array_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word Class_declaration_type_offset =
-    112;
+    104;
 static constexpr dart::compiler::target::word Class_num_type_arguments_offset =
-    172;
+    164;
 static constexpr dart::compiler::target::word Class_super_type_offset = 88;
 static constexpr dart::compiler::target::word
-    Class_host_type_arguments_field_offset_in_words_offset = 184;
+    Class_host_type_arguments_field_offset_in_words_offset = 176;
 static constexpr dart::compiler::target::word Closure_context_offset = 40;
 static constexpr dart::compiler::target::word
     Closure_delayed_type_arguments_offset = 24;
@@ -3733,9 +3768,9 @@
 static constexpr dart::compiler::target::word
     Closure_instantiator_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_offset = 40;
+    ClosureData_default_type_arguments_offset = 32;
 static constexpr dart::compiler::target::word
-    ClosureData_default_type_arguments_info_offset = 48;
+    ClosureData_default_type_arguments_info_offset = 40;
 static constexpr dart::compiler::target::word Code_object_pool_offset = 40;
 static constexpr dart::compiler::target::word Code_saved_instructions_offset =
     48;
@@ -3760,19 +3795,16 @@
     48;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 90;
-static constexpr dart::compiler::target::word Function_code_offset = 88;
-static constexpr dart::compiler::target::word Function_data_offset = 72;
+static constexpr dart::compiler::target::word Function_code_offset = 72;
+static constexpr dart::compiler::target::word Function_data_offset = 56;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
-static constexpr dart::compiler::target::word Function_kind_tag_offset = 120;
+static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    124;
+    108;
 static constexpr dart::compiler::target::word Function_parameter_names_offset =
-    56;
-static constexpr dart::compiler::target::word Function_parameter_types_offset =
-    48;
-static constexpr dart::compiler::target::word Function_type_parameters_offset =
-    64;
+    40;
+static constexpr dart::compiler::target::word Function_signature_offset = 48;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -3829,6 +3861,7 @@
 static constexpr dart::compiler::target::word ObjectStore_int_type_offset = 136;
 static constexpr dart::compiler::target::word ObjectStore_string_type_offset =
     312;
+static constexpr dart::compiler::target::word ObjectStore_type_type_offset = 96;
 static constexpr dart::compiler::target::word OneByteString_data_offset = 16;
 static constexpr dart::compiler::target::word PointerBase_data_field_offset = 8;
 static constexpr dart::compiler::target::word Pointer_type_arguments_offset =
@@ -4020,15 +4053,21 @@
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
 static constexpr dart::compiler::target::word Type_arguments_offset = 32;
 static constexpr dart::compiler::target::word Type_hash_offset = 40;
-static constexpr dart::compiler::target::word Type_signature_offset = 48;
 static constexpr dart::compiler::target::word Type_type_class_id_offset = 24;
-static constexpr dart::compiler::target::word Type_type_state_offset = 60;
-static constexpr dart::compiler::target::word Type_nullability_offset = 61;
+static constexpr dart::compiler::target::word Type_type_state_offset = 48;
+static constexpr dart::compiler::target::word Type_nullability_offset = 49;
+static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    TypeParameter_parameterized_class_id_offset = 64;
-static constexpr dart::compiler::target::word TypeParameter_index_offset = 72;
+    FunctionType_packed_fields_offset = 64;
+static constexpr dart::compiler::target::word
+    FunctionType_parameter_types_offset = 40;
+static constexpr dart::compiler::target::word
+    FunctionType_type_parameters_offset = 24;
+static constexpr dart::compiler::target::word
+    TypeParameter_parameterized_class_id_offset = 56;
+static constexpr dart::compiler::target::word TypeParameter_index_offset = 60;
 static constexpr dart::compiler::target::word TypeParameter_nullability_offset =
-    75;
+    63;
 static constexpr dart::compiler::target::word
     TypeArguments_instantiations_offset = 8;
 static constexpr dart::compiler::target::word TypeArguments_length_offset = 16;
@@ -4036,7 +4075,7 @@
     32;
 static constexpr dart::compiler::target::word TypeArguments_types_offset = 40;
 static constexpr dart::compiler::target::word TypeParameter_bound_offset = 40;
-static constexpr dart::compiler::target::word TypeParameter_flags_offset = 74;
+static constexpr dart::compiler::target::word TypeParameter_flags_offset = 62;
 static constexpr dart::compiler::target::word TypeParameter_name_offset = 24;
 static constexpr dart::compiler::target::word TypeRef_type_offset = 24;
 static constexpr dart::compiler::target::word TypedDataBase_length_offset = 16;
@@ -4069,14 +4108,15 @@
         1304, 1312, 1320, 1328, 1336, 1344, 1352, 1360, 1368, 1376, 1384,
         1392, 1400, 1408, 1416, -1,   -1,   -1,   -1,   1424, 1432, -1,
         -1,   1440, 1448, 1456, -1,   -1,   -1,   -1,   -1,   -1};
+static constexpr dart::compiler::target::word AbstractType_InstanceSize = 24;
 static constexpr dart::compiler::target::word ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word Array_header_size = 24;
 static constexpr dart::compiler::target::word Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word Class_InstanceSize = 208;
+static constexpr dart::compiler::target::word Class_InstanceSize = 200;
 static constexpr dart::compiler::target::word Closure_InstanceSize = 56;
-static constexpr dart::compiler::target::word ClosureData_InstanceSize = 56;
+static constexpr dart::compiler::target::word ClosureData_InstanceSize = 48;
 static constexpr dart::compiler::target::word Code_InstanceSize = 144;
 static constexpr dart::compiler::target::word CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word CompressedStackMaps_HeaderSize =
@@ -4099,7 +4139,8 @@
 static constexpr dart::compiler::target::word Field_InstanceSize = 96;
 static constexpr dart::compiler::target::word Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word Function_InstanceSize = 144;
+static constexpr dart::compiler::target::word Function_InstanceSize = 128;
+static constexpr dart::compiler::target::word FunctionType_InstanceSize = 72;
 static constexpr dart::compiler::target::word FutureOr_InstanceSize = 16;
 static constexpr dart::compiler::target::word GrowableObjectArray_InstanceSize =
     32;
@@ -4138,7 +4179,6 @@
 static constexpr dart::compiler::target::word RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word Script_InstanceSize = 88;
 static constexpr dart::compiler::target::word SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word SignatureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word SingleTargetCache_InstanceSize =
     32;
 static constexpr dart::compiler::target::word Smi_InstanceSize = 8;
@@ -4150,9 +4190,9 @@
 static constexpr dart::compiler::target::word
     TransferableTypedData_InstanceSize = 8;
 static constexpr dart::compiler::target::word TwoByteString_InstanceSize = 16;
-static constexpr dart::compiler::target::word Type_InstanceSize = 64;
+static constexpr dart::compiler::target::word Type_InstanceSize = 56;
 static constexpr dart::compiler::target::word TypeArguments_InstanceSize = 40;
-static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 80;
+static constexpr dart::compiler::target::word TypeParameter_InstanceSize = 64;
 static constexpr dart::compiler::target::word TypeRef_InstanceSize = 32;
 static constexpr dart::compiler::target::word TypedData_InstanceSize = 24;
 static constexpr dart::compiler::target::word TypedDataBase_InstanceSize = 24;
@@ -4240,12 +4280,12 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 56;
+    AOT_Class_declaration_type_offset = 52;
 static constexpr dart::compiler::target::word
-    AOT_Class_num_type_arguments_offset = 92;
+    AOT_Class_num_type_arguments_offset = 88;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 44;
 static constexpr dart::compiler::target::word
-    AOT_Class_host_type_arguments_field_offset_in_words_offset = 104;
+    AOT_Class_host_type_arguments_field_offset_in_words_offset = 100;
 static constexpr dart::compiler::target::word
     AOT_SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word AOT_Closure_context_offset = 20;
@@ -4258,9 +4298,9 @@
 static constexpr dart::compiler::target::word
     AOT_Closure_instantiator_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_offset = 20;
+    AOT_ClosureData_default_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_info_offset = 24;
+    AOT_ClosureData_default_type_arguments_info_offset = 20;
 static constexpr dart::compiler::target::word AOT_Code_object_pool_offset = 20;
 static constexpr dart::compiler::target::word
     AOT_Code_saved_instructions_offset = 24;
@@ -4286,19 +4326,17 @@
     AOT_Field_guarded_list_length_offset = 24;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 42;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 46;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 44;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 36;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 36;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 28;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 40;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 52;
+    AOT_Function_packed_fields_offset = 44;
 static constexpr dart::compiler::target::word
-    AOT_Function_parameter_names_offset = 28;
-static constexpr dart::compiler::target::word
-    AOT_Function_parameter_types_offset = 24;
-static constexpr dart::compiler::target::word
-    AOT_Function_type_parameters_offset = 32;
+    AOT_Function_parameter_names_offset = 20;
+static constexpr dart::compiler::target::word AOT_Function_signature_offset =
+    24;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
@@ -4368,6 +4406,8 @@
     68;
 static constexpr dart::compiler::target::word
     AOT_ObjectStore_string_type_offset = 156;
+static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
+    48;
 static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
     12;
 static constexpr dart::compiler::target::word
@@ -4571,17 +4611,23 @@
     12;
 static constexpr dart::compiler::target::word AOT_Type_arguments_offset = 16;
 static constexpr dart::compiler::target::word AOT_Type_hash_offset = 20;
-static constexpr dart::compiler::target::word AOT_Type_signature_offset = 24;
 static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset =
     12;
-static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 32;
-static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 33;
+static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 24;
+static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 25;
+static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_parameterized_class_id_offset = 32;
+    AOT_FunctionType_packed_fields_offset = 32;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_parameter_types_offset = 20;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_type_parameters_offset = 12;
+static constexpr dart::compiler::target::word
+    AOT_TypeParameter_parameterized_class_id_offset = 28;
 static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
-    40;
+    32;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_nullability_offset = 43;
+    AOT_TypeParameter_nullability_offset = 35;
 static constexpr dart::compiler::target::word
     AOT_TypeArguments_instantiations_offset = 4;
 static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
@@ -4593,7 +4639,7 @@
 static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset =
     20;
 static constexpr dart::compiler::target::word AOT_TypeParameter_flags_offset =
-    42;
+    34;
 static constexpr dart::compiler::target::word AOT_TypeParameter_name_offset =
     12;
 static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 12;
@@ -4632,14 +4678,16 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
         660, 664, 668, 672, 676, -1, 680, -1, 684, 688, -1, -1, -1, -1, -1, -1};
+static constexpr dart::compiler::target::word AOT_AbstractType_InstanceSize =
+    12;
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 12;
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 112;
+static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 108;
 static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 28;
-static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 28;
+static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Code_InstanceSize = 88;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 8;
 static constexpr dart::compiler::target::word
@@ -4664,7 +4712,9 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
+    40;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 16;
@@ -4709,8 +4759,6 @@
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word AOT_Script_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_SignatureData_InstanceSize =
-    12;
 static constexpr dart::compiler::target::word
     AOT_SingleTargetCache_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Smi_InstanceSize = 4;
@@ -4723,11 +4771,11 @@
     AOT_TransferableTypedData_InstanceSize = 4;
 static constexpr dart::compiler::target::word AOT_TwoByteString_InstanceSize =
     12;
-static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 36;
+static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 28;
 static constexpr dart::compiler::target::word AOT_TypeArguments_InstanceSize =
     20;
 static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize =
-    44;
+    36;
 static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_TypedData_InstanceSize = 12;
 static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize =
@@ -4816,12 +4864,12 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 112;
+    AOT_Class_declaration_type_offset = 104;
 static constexpr dart::compiler::target::word
-    AOT_Class_num_type_arguments_offset = 172;
+    AOT_Class_num_type_arguments_offset = 164;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
 static constexpr dart::compiler::target::word
-    AOT_Class_host_type_arguments_field_offset_in_words_offset = 184;
+    AOT_Class_host_type_arguments_field_offset_in_words_offset = 176;
 static constexpr dart::compiler::target::word
     AOT_SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word AOT_Closure_context_offset = 40;
@@ -4834,9 +4882,9 @@
 static constexpr dart::compiler::target::word
     AOT_Closure_instantiator_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_offset = 40;
+    AOT_ClosureData_default_type_arguments_offset = 32;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_info_offset = 48;
+    AOT_ClosureData_default_type_arguments_info_offset = 40;
 static constexpr dart::compiler::target::word AOT_Code_object_pool_offset = 40;
 static constexpr dart::compiler::target::word
     AOT_Code_saved_instructions_offset = 48;
@@ -4862,19 +4910,17 @@
     AOT_Field_guarded_list_length_offset = 48;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 74;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 78;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 88;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 72;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 72;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 56;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 96;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 80;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 100;
+    AOT_Function_packed_fields_offset = 84;
 static constexpr dart::compiler::target::word
-    AOT_Function_parameter_names_offset = 56;
-static constexpr dart::compiler::target::word
-    AOT_Function_parameter_types_offset = 48;
-static constexpr dart::compiler::target::word
-    AOT_Function_type_parameters_offset = 64;
+    AOT_Function_parameter_names_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_signature_offset =
+    48;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -4944,6 +4990,8 @@
     136;
 static constexpr dart::compiler::target::word
     AOT_ObjectStore_string_type_offset = 312;
+static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
+    96;
 static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
     16;
 static constexpr dart::compiler::target::word
@@ -5148,17 +5196,23 @@
     16;
 static constexpr dart::compiler::target::word AOT_Type_arguments_offset = 32;
 static constexpr dart::compiler::target::word AOT_Type_hash_offset = 40;
-static constexpr dart::compiler::target::word AOT_Type_signature_offset = 48;
 static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset =
     24;
-static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 60;
-static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 61;
+static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 48;
+static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 49;
+static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_parameterized_class_id_offset = 64;
+    AOT_FunctionType_packed_fields_offset = 64;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_parameter_types_offset = 40;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_type_parameters_offset = 24;
+static constexpr dart::compiler::target::word
+    AOT_TypeParameter_parameterized_class_id_offset = 56;
 static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
-    72;
+    60;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_nullability_offset = 75;
+    AOT_TypeParameter_nullability_offset = 63;
 static constexpr dart::compiler::target::word
     AOT_TypeArguments_instantiations_offset = 8;
 static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
@@ -5170,7 +5224,7 @@
 static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset =
     40;
 static constexpr dart::compiler::target::word AOT_TypeParameter_flags_offset =
-    74;
+    62;
 static constexpr dart::compiler::target::word AOT_TypeParameter_name_offset =
     24;
 static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 24;
@@ -5211,14 +5265,16 @@
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
         1304, 1312, 1320, 1328, -1,   -1,   1336, 1344,
         1352, 1360, 1368, -1,   1376, 1384, -1,   -1};
+static constexpr dart::compiler::target::word AOT_AbstractType_InstanceSize =
+    24;
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 24;
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 192;
+static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 184;
 static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
-static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 48;
 static constexpr dart::compiler::target::word AOT_Code_InstanceSize = 152;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -5243,7 +5299,9 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 104;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
+    72;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 32;
@@ -5288,8 +5346,6 @@
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word AOT_Script_InstanceSize = 88;
 static constexpr dart::compiler::target::word AOT_SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_SignatureData_InstanceSize =
-    24;
 static constexpr dart::compiler::target::word
     AOT_SingleTargetCache_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_Smi_InstanceSize = 8;
@@ -5302,11 +5358,11 @@
     AOT_TransferableTypedData_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_InstanceSize =
     16;
-static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 64;
+static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_TypeArguments_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize =
-    80;
+    64;
 static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_TypedData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize =
@@ -5398,12 +5454,12 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 112;
+    AOT_Class_declaration_type_offset = 104;
 static constexpr dart::compiler::target::word
-    AOT_Class_num_type_arguments_offset = 172;
+    AOT_Class_num_type_arguments_offset = 164;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
 static constexpr dart::compiler::target::word
-    AOT_Class_host_type_arguments_field_offset_in_words_offset = 184;
+    AOT_Class_host_type_arguments_field_offset_in_words_offset = 176;
 static constexpr dart::compiler::target::word
     AOT_SharedClassTable_class_heap_stats_table_offset = 0;
 static constexpr dart::compiler::target::word AOT_Closure_context_offset = 40;
@@ -5416,9 +5472,9 @@
 static constexpr dart::compiler::target::word
     AOT_Closure_instantiator_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_offset = 40;
+    AOT_ClosureData_default_type_arguments_offset = 32;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_info_offset = 48;
+    AOT_ClosureData_default_type_arguments_info_offset = 40;
 static constexpr dart::compiler::target::word AOT_Code_object_pool_offset = 40;
 static constexpr dart::compiler::target::word
     AOT_Code_saved_instructions_offset = 48;
@@ -5444,19 +5500,17 @@
     AOT_Field_guarded_list_length_offset = 48;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 74;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 78;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 88;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 72;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 72;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 56;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 96;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 80;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 100;
+    AOT_Function_packed_fields_offset = 84;
 static constexpr dart::compiler::target::word
-    AOT_Function_parameter_names_offset = 56;
-static constexpr dart::compiler::target::word
-    AOT_Function_parameter_types_offset = 48;
-static constexpr dart::compiler::target::word
-    AOT_Function_type_parameters_offset = 64;
+    AOT_Function_parameter_names_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_signature_offset =
+    48;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -5526,6 +5580,8 @@
     136;
 static constexpr dart::compiler::target::word
     AOT_ObjectStore_string_type_offset = 312;
+static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
+    96;
 static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
     16;
 static constexpr dart::compiler::target::word
@@ -5730,17 +5786,23 @@
     16;
 static constexpr dart::compiler::target::word AOT_Type_arguments_offset = 32;
 static constexpr dart::compiler::target::word AOT_Type_hash_offset = 40;
-static constexpr dart::compiler::target::word AOT_Type_signature_offset = 48;
 static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset =
     24;
-static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 60;
-static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 61;
+static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 48;
+static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 49;
+static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_parameterized_class_id_offset = 64;
+    AOT_FunctionType_packed_fields_offset = 64;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_parameter_types_offset = 40;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_type_parameters_offset = 24;
+static constexpr dart::compiler::target::word
+    AOT_TypeParameter_parameterized_class_id_offset = 56;
 static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
-    72;
+    60;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_nullability_offset = 75;
+    AOT_TypeParameter_nullability_offset = 63;
 static constexpr dart::compiler::target::word
     AOT_TypeArguments_instantiations_offset = 8;
 static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
@@ -5752,7 +5814,7 @@
 static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset =
     40;
 static constexpr dart::compiler::target::word AOT_TypeParameter_flags_offset =
-    74;
+    62;
 static constexpr dart::compiler::target::word AOT_TypeParameter_name_offset =
     24;
 static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 24;
@@ -5794,14 +5856,16 @@
         1304, 1312, 1320, 1328, 1336, 1344, 1352, 1360, 1368, 1376, 1384,
         1392, 1400, 1408, 1416, -1,   -1,   -1,   -1,   1424, 1432, -1,
         -1,   1440, 1448, 1456, -1,   -1,   -1,   -1,   -1,   -1};
+static constexpr dart::compiler::target::word AOT_AbstractType_InstanceSize =
+    24;
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 24;
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 192;
+static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 184;
 static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
-static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 48;
 static constexpr dart::compiler::target::word AOT_Code_InstanceSize = 152;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -5826,7 +5890,9 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 104;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
+    72;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 32;
@@ -5871,8 +5937,6 @@
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word AOT_Script_InstanceSize = 88;
 static constexpr dart::compiler::target::word AOT_SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_SignatureData_InstanceSize =
-    24;
 static constexpr dart::compiler::target::word
     AOT_SingleTargetCache_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_Smi_InstanceSize = 8;
@@ -5885,11 +5949,11 @@
     AOT_TransferableTypedData_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_InstanceSize =
     16;
-static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 64;
+static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_TypeArguments_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize =
-    80;
+    64;
 static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_TypedData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize =
@@ -5979,12 +6043,12 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 56;
+    AOT_Class_declaration_type_offset = 52;
 static constexpr dart::compiler::target::word
-    AOT_Class_num_type_arguments_offset = 92;
+    AOT_Class_num_type_arguments_offset = 88;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 44;
 static constexpr dart::compiler::target::word
-    AOT_Class_host_type_arguments_field_offset_in_words_offset = 104;
+    AOT_Class_host_type_arguments_field_offset_in_words_offset = 100;
 static constexpr dart::compiler::target::word AOT_Closure_context_offset = 20;
 static constexpr dart::compiler::target::word
     AOT_Closure_delayed_type_arguments_offset = 12;
@@ -5995,9 +6059,9 @@
 static constexpr dart::compiler::target::word
     AOT_Closure_instantiator_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_offset = 20;
+    AOT_ClosureData_default_type_arguments_offset = 16;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_info_offset = 24;
+    AOT_ClosureData_default_type_arguments_info_offset = 20;
 static constexpr dart::compiler::target::word AOT_Code_object_pool_offset = 20;
 static constexpr dart::compiler::target::word
     AOT_Code_saved_instructions_offset = 24;
@@ -6023,19 +6087,17 @@
     AOT_Field_guarded_list_length_offset = 24;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 42;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 46;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 44;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 36;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 36;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 28;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 40;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 52;
+    AOT_Function_packed_fields_offset = 44;
 static constexpr dart::compiler::target::word
-    AOT_Function_parameter_names_offset = 28;
-static constexpr dart::compiler::target::word
-    AOT_Function_parameter_types_offset = 24;
-static constexpr dart::compiler::target::word
-    AOT_Function_type_parameters_offset = 32;
+    AOT_Function_parameter_names_offset = 20;
+static constexpr dart::compiler::target::word AOT_Function_signature_offset =
+    24;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
@@ -6103,6 +6165,8 @@
     68;
 static constexpr dart::compiler::target::word
     AOT_ObjectStore_string_type_offset = 156;
+static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
+    48;
 static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
     12;
 static constexpr dart::compiler::target::word
@@ -6306,17 +6370,23 @@
     12;
 static constexpr dart::compiler::target::word AOT_Type_arguments_offset = 16;
 static constexpr dart::compiler::target::word AOT_Type_hash_offset = 20;
-static constexpr dart::compiler::target::word AOT_Type_signature_offset = 24;
 static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset =
     12;
-static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 32;
-static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 33;
+static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 24;
+static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 25;
+static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_parameterized_class_id_offset = 32;
+    AOT_FunctionType_packed_fields_offset = 32;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_parameter_types_offset = 20;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_type_parameters_offset = 12;
+static constexpr dart::compiler::target::word
+    AOT_TypeParameter_parameterized_class_id_offset = 28;
 static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
-    40;
+    32;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_nullability_offset = 43;
+    AOT_TypeParameter_nullability_offset = 35;
 static constexpr dart::compiler::target::word
     AOT_TypeArguments_instantiations_offset = 4;
 static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
@@ -6328,7 +6398,7 @@
 static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset =
     20;
 static constexpr dart::compiler::target::word AOT_TypeParameter_flags_offset =
-    42;
+    34;
 static constexpr dart::compiler::target::word AOT_TypeParameter_name_offset =
     12;
 static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 12;
@@ -6364,14 +6434,16 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
         660, 664, 668, 672, 676, -1, 680, -1, 684, 688, -1, -1, -1, -1, -1, -1};
+static constexpr dart::compiler::target::word AOT_AbstractType_InstanceSize =
+    12;
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 12;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 12;
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 112;
+static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 108;
 static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 28;
-static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 28;
+static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Code_InstanceSize = 64;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 8;
 static constexpr dart::compiler::target::word
@@ -6396,7 +6468,9 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
+    40;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 16;
@@ -6441,8 +6515,6 @@
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 60;
 static constexpr dart::compiler::target::word AOT_Script_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_SignatureData_InstanceSize =
-    12;
 static constexpr dart::compiler::target::word
     AOT_SingleTargetCache_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Smi_InstanceSize = 4;
@@ -6455,11 +6527,11 @@
     AOT_TransferableTypedData_InstanceSize = 4;
 static constexpr dart::compiler::target::word AOT_TwoByteString_InstanceSize =
     12;
-static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 36;
+static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 28;
 static constexpr dart::compiler::target::word AOT_TypeArguments_InstanceSize =
     20;
 static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize =
-    44;
+    36;
 static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_TypedData_InstanceSize = 12;
 static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize =
@@ -6548,12 +6620,12 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 112;
+    AOT_Class_declaration_type_offset = 104;
 static constexpr dart::compiler::target::word
-    AOT_Class_num_type_arguments_offset = 172;
+    AOT_Class_num_type_arguments_offset = 164;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
 static constexpr dart::compiler::target::word
-    AOT_Class_host_type_arguments_field_offset_in_words_offset = 184;
+    AOT_Class_host_type_arguments_field_offset_in_words_offset = 176;
 static constexpr dart::compiler::target::word AOT_Closure_context_offset = 40;
 static constexpr dart::compiler::target::word
     AOT_Closure_delayed_type_arguments_offset = 24;
@@ -6564,9 +6636,9 @@
 static constexpr dart::compiler::target::word
     AOT_Closure_instantiator_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_offset = 40;
+    AOT_ClosureData_default_type_arguments_offset = 32;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_info_offset = 48;
+    AOT_ClosureData_default_type_arguments_info_offset = 40;
 static constexpr dart::compiler::target::word AOT_Code_object_pool_offset = 40;
 static constexpr dart::compiler::target::word
     AOT_Code_saved_instructions_offset = 48;
@@ -6592,19 +6664,17 @@
     AOT_Field_guarded_list_length_offset = 48;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 74;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 78;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 88;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 72;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 72;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 56;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 96;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 80;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 100;
+    AOT_Function_packed_fields_offset = 84;
 static constexpr dart::compiler::target::word
-    AOT_Function_parameter_names_offset = 56;
-static constexpr dart::compiler::target::word
-    AOT_Function_parameter_types_offset = 48;
-static constexpr dart::compiler::target::word
-    AOT_Function_type_parameters_offset = 64;
+    AOT_Function_parameter_names_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_signature_offset =
+    48;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -6672,6 +6742,8 @@
     136;
 static constexpr dart::compiler::target::word
     AOT_ObjectStore_string_type_offset = 312;
+static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
+    96;
 static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
     16;
 static constexpr dart::compiler::target::word
@@ -6876,17 +6948,23 @@
     16;
 static constexpr dart::compiler::target::word AOT_Type_arguments_offset = 32;
 static constexpr dart::compiler::target::word AOT_Type_hash_offset = 40;
-static constexpr dart::compiler::target::word AOT_Type_signature_offset = 48;
 static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset =
     24;
-static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 60;
-static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 61;
+static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 48;
+static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 49;
+static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_parameterized_class_id_offset = 64;
+    AOT_FunctionType_packed_fields_offset = 64;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_parameter_types_offset = 40;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_type_parameters_offset = 24;
+static constexpr dart::compiler::target::word
+    AOT_TypeParameter_parameterized_class_id_offset = 56;
 static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
-    72;
+    60;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_nullability_offset = 75;
+    AOT_TypeParameter_nullability_offset = 63;
 static constexpr dart::compiler::target::word
     AOT_TypeArguments_instantiations_offset = 8;
 static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
@@ -6898,7 +6976,7 @@
 static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset =
     40;
 static constexpr dart::compiler::target::word AOT_TypeParameter_flags_offset =
-    74;
+    62;
 static constexpr dart::compiler::target::word AOT_TypeParameter_name_offset =
     24;
 static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 24;
@@ -6936,14 +7014,16 @@
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
         1304, 1312, 1320, 1328, -1,   -1,   1336, 1344,
         1352, 1360, 1368, -1,   1376, 1384, -1,   -1};
+static constexpr dart::compiler::target::word AOT_AbstractType_InstanceSize =
+    24;
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 24;
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 192;
+static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 184;
 static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
-static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 48;
 static constexpr dart::compiler::target::word AOT_Code_InstanceSize = 120;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -6968,7 +7048,9 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 104;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
+    72;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 32;
@@ -7013,8 +7095,6 @@
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word AOT_Script_InstanceSize = 88;
 static constexpr dart::compiler::target::word AOT_SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_SignatureData_InstanceSize =
-    24;
 static constexpr dart::compiler::target::word
     AOT_SingleTargetCache_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_Smi_InstanceSize = 8;
@@ -7027,11 +7107,11 @@
     AOT_TransferableTypedData_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_InstanceSize =
     16;
-static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 64;
+static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_TypeArguments_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize =
-    80;
+    64;
 static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_TypedData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize =
@@ -7123,12 +7203,12 @@
 static constexpr dart::compiler::target::word AOT_Array_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word
-    AOT_Class_declaration_type_offset = 112;
+    AOT_Class_declaration_type_offset = 104;
 static constexpr dart::compiler::target::word
-    AOT_Class_num_type_arguments_offset = 172;
+    AOT_Class_num_type_arguments_offset = 164;
 static constexpr dart::compiler::target::word AOT_Class_super_type_offset = 88;
 static constexpr dart::compiler::target::word
-    AOT_Class_host_type_arguments_field_offset_in_words_offset = 184;
+    AOT_Class_host_type_arguments_field_offset_in_words_offset = 176;
 static constexpr dart::compiler::target::word AOT_Closure_context_offset = 40;
 static constexpr dart::compiler::target::word
     AOT_Closure_delayed_type_arguments_offset = 24;
@@ -7139,9 +7219,9 @@
 static constexpr dart::compiler::target::word
     AOT_Closure_instantiator_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_offset = 40;
+    AOT_ClosureData_default_type_arguments_offset = 32;
 static constexpr dart::compiler::target::word
-    AOT_ClosureData_default_type_arguments_info_offset = 48;
+    AOT_ClosureData_default_type_arguments_info_offset = 40;
 static constexpr dart::compiler::target::word AOT_Code_object_pool_offset = 40;
 static constexpr dart::compiler::target::word
     AOT_Code_saved_instructions_offset = 48;
@@ -7167,19 +7247,17 @@
     AOT_Field_guarded_list_length_offset = 48;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 74;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 78;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 88;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 72;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 72;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 56;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 96;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 80;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 100;
+    AOT_Function_packed_fields_offset = 84;
 static constexpr dart::compiler::target::word
-    AOT_Function_parameter_names_offset = 56;
-static constexpr dart::compiler::target::word
-    AOT_Function_parameter_types_offset = 48;
-static constexpr dart::compiler::target::word
-    AOT_Function_type_parameters_offset = 64;
+    AOT_Function_parameter_names_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_signature_offset =
+    48;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -7247,6 +7325,8 @@
     136;
 static constexpr dart::compiler::target::word
     AOT_ObjectStore_string_type_offset = 312;
+static constexpr dart::compiler::target::word AOT_ObjectStore_type_type_offset =
+    96;
 static constexpr dart::compiler::target::word AOT_OneByteString_data_offset =
     16;
 static constexpr dart::compiler::target::word
@@ -7451,17 +7531,23 @@
     16;
 static constexpr dart::compiler::target::word AOT_Type_arguments_offset = 32;
 static constexpr dart::compiler::target::word AOT_Type_hash_offset = 40;
-static constexpr dart::compiler::target::word AOT_Type_signature_offset = 48;
 static constexpr dart::compiler::target::word AOT_Type_type_class_id_offset =
     24;
-static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 60;
-static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 61;
+static constexpr dart::compiler::target::word AOT_Type_type_state_offset = 48;
+static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 49;
+static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_parameterized_class_id_offset = 64;
+    AOT_FunctionType_packed_fields_offset = 64;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_parameter_types_offset = 40;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_type_parameters_offset = 24;
+static constexpr dart::compiler::target::word
+    AOT_TypeParameter_parameterized_class_id_offset = 56;
 static constexpr dart::compiler::target::word AOT_TypeParameter_index_offset =
-    72;
+    60;
 static constexpr dart::compiler::target::word
-    AOT_TypeParameter_nullability_offset = 75;
+    AOT_TypeParameter_nullability_offset = 63;
 static constexpr dart::compiler::target::word
     AOT_TypeArguments_instantiations_offset = 8;
 static constexpr dart::compiler::target::word AOT_TypeArguments_length_offset =
@@ -7473,7 +7559,7 @@
 static constexpr dart::compiler::target::word AOT_TypeParameter_bound_offset =
     40;
 static constexpr dart::compiler::target::word AOT_TypeParameter_flags_offset =
-    74;
+    62;
 static constexpr dart::compiler::target::word AOT_TypeParameter_name_offset =
     24;
 static constexpr dart::compiler::target::word AOT_TypeRef_type_offset = 24;
@@ -7512,14 +7598,16 @@
         1304, 1312, 1320, 1328, 1336, 1344, 1352, 1360, 1368, 1376, 1384,
         1392, 1400, 1408, 1416, -1,   -1,   -1,   -1,   1424, 1432, -1,
         -1,   1440, 1448, 1456, -1,   -1,   -1,   -1,   -1,   -1};
+static constexpr dart::compiler::target::word AOT_AbstractType_InstanceSize =
+    24;
 static constexpr dart::compiler::target::word AOT_ApiError_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Array_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Array_header_size = 24;
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
-static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 192;
+static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 184;
 static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
-static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 48;
 static constexpr dart::compiler::target::word AOT_Code_InstanceSize = 120;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -7544,7 +7632,9 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 104;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
+    72;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_InstanceSize = 32;
@@ -7589,8 +7679,6 @@
 static constexpr dart::compiler::target::word AOT_RegExp_InstanceSize = 120;
 static constexpr dart::compiler::target::word AOT_Script_InstanceSize = 88;
 static constexpr dart::compiler::target::word AOT_SendPort_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_SignatureData_InstanceSize =
-    24;
 static constexpr dart::compiler::target::word
     AOT_SingleTargetCache_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_Smi_InstanceSize = 8;
@@ -7603,11 +7691,11 @@
     AOT_TransferableTypedData_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_InstanceSize =
     16;
-static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 64;
+static constexpr dart::compiler::target::word AOT_Type_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_TypeArguments_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_TypeParameter_InstanceSize =
-    80;
+    64;
 static constexpr dart::compiler::target::word AOT_TypeRef_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_TypedData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_TypedDataBase_InstanceSize =
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 347cf96..86412d2 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -112,8 +112,7 @@
   FIELD(Function, kind_tag_offset)                                             \
   FIELD(Function, packed_fields_offset)                                        \
   FIELD(Function, parameter_names_offset)                                      \
-  FIELD(Function, parameter_types_offset)                                      \
-  FIELD(Function, type_parameters_offset)                                      \
+  FIELD(Function, signature_offset)                                            \
   FIELD(FutureOr, type_arguments_offset)                                       \
   FIELD(GrowableObjectArray, data_offset)                                      \
   FIELD(GrowableObjectArray, length_offset)                                    \
@@ -153,6 +152,7 @@
   FIELD(ObjectStore, double_type_offset)                                       \
   FIELD(ObjectStore, int_type_offset)                                          \
   FIELD(ObjectStore, string_type_offset)                                       \
+  FIELD(ObjectStore, type_type_offset)                                         \
   FIELD(OneByteString, data_offset)                                            \
   FIELD(PointerBase, data_field_offset)                                        \
   FIELD(Pointer, type_arguments_offset)                                        \
@@ -261,10 +261,13 @@
   FIELD(TwoByteString, data_offset)                                            \
   FIELD(Type, arguments_offset)                                                \
   FIELD(Type, hash_offset)                                                     \
-  FIELD(Type, signature_offset)                                                \
   FIELD(Type, type_class_id_offset)                                            \
   FIELD(Type, type_state_offset)                                               \
   FIELD(Type, nullability_offset)                                              \
+  FIELD(FunctionType, hash_offset)                                             \
+  FIELD(FunctionType, packed_fields_offset)                                    \
+  FIELD(FunctionType, parameter_types_offset)                                  \
+  FIELD(FunctionType, type_parameters_offset)                                  \
   FIELD(TypeParameter, parameterized_class_id_offset)                          \
   FIELD(TypeParameter, index_offset)                                           \
   FIELD(TypeParameter, nullability_offset)                                     \
@@ -299,6 +302,7 @@
       kNumberOfCpuRegisters - 1,                                               \
       [](Register reg) { return (kDartAvailableCpuRegs & (1 << reg)) != 0; })) \
                                                                                \
+  SIZEOF(AbstractType, InstanceSize, AbstractTypeLayout)                       \
   SIZEOF(ApiError, InstanceSize, ApiErrorLayout)                               \
   SIZEOF(Array, InstanceSize, ArrayLayout)                                     \
   SIZEOF(Array, header_size, ArrayLayout)                                      \
@@ -324,6 +328,7 @@
   SIZEOF(Float32x4, InstanceSize, Float32x4Layout)                             \
   SIZEOF(Float64x2, InstanceSize, Float64x2Layout)                             \
   SIZEOF(Function, InstanceSize, FunctionLayout)                               \
+  SIZEOF(FunctionType, InstanceSize, FunctionTypeLayout)                       \
   SIZEOF(FutureOr, InstanceSize, FutureOrLayout)                               \
   SIZEOF(GrowableObjectArray, InstanceSize, GrowableObjectArrayLayout)         \
   SIZEOF(ICData, InstanceSize, ICDataLayout)                                   \
@@ -355,7 +360,6 @@
   SIZEOF(RegExp, InstanceSize, RegExpLayout)                                   \
   SIZEOF(Script, InstanceSize, ScriptLayout)                                   \
   SIZEOF(SendPort, InstanceSize, SendPortLayout)                               \
-  SIZEOF(SignatureData, InstanceSize, SignatureDataLayout)                     \
   SIZEOF(SingleTargetCache, InstanceSize, SingleTargetCacheLayout)             \
   SIZEOF(Smi, InstanceSize, SmiLayout)                                         \
   SIZEOF(StackTrace, InstanceSize, StackTraceLayout)                           \
diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc
index 0f635af..8a434fe 100644
--- a/runtime/vm/compiler/stub_code_compiler.cc
+++ b/runtime/vm/compiler/stub_code_compiler.cc
@@ -196,16 +196,21 @@
 
 // For use in GenerateTypeIsTopTypeForSubtyping and
 // GenerateNullIsAssignableToType.
-static void EnsureIsTypeOrTypeParameter(Assembler* assembler,
-                                        Register type_reg,
-                                        Register scratch_reg) {
+static void EnsureIsTypeOrFunctionTypeOrTypeParameter(Assembler* assembler,
+                                                      Register type_reg,
+                                                      Register scratch_reg) {
 #if defined(DEBUG)
-  compiler::Label is_type_param_or_type;
+  compiler::Label is_type_param_or_type_or_function_type;
   __ LoadClassIdMayBeSmi(scratch_reg, type_reg);
   __ CompareImmediate(scratch_reg, kTypeParameterCid);
-  __ BranchIf(EQUAL, &is_type_param_or_type, compiler::Assembler::kNearJump);
+  __ BranchIf(EQUAL, &is_type_param_or_type_or_function_type,
+              compiler::Assembler::kNearJump);
   __ CompareImmediate(scratch_reg, kTypeCid);
-  __ BranchIf(EQUAL, &is_type_param_or_type, compiler::Assembler::kNearJump);
+  __ BranchIf(EQUAL, &is_type_param_or_type_or_function_type,
+              compiler::Assembler::kNearJump);
+  __ CompareImmediate(scratch_reg, kFunctionTypeCid);
+  __ BranchIf(EQUAL, &is_type_param_or_type_or_function_type,
+              compiler::Assembler::kNearJump);
   // Type references show up in F-bounded polymorphism, which is limited
   // to classes. Thus, TypeRefs only appear in places like class type
   // arguments or the bounds of uninstantiated class type parameters.
@@ -215,8 +220,8 @@
   // a function type parameter or the type of a function parameter
   // (respectively), we should never see a TypeRef here. This check is here
   // in case this changes and we need to update this stub.
-  __ Stop("not a type or type parameter");
-  __ Bind(&is_type_param_or_type);
+  __ Stop("not a type or function type or type parameter");
+  __ Bind(&is_type_param_or_type_or_function_type);
 #endif
 }
 
@@ -265,12 +270,14 @@
   __ MoveRegister(scratch1_reg, TypeTestABI::kDstTypeReg);
   __ Bind(&check_top_type);
   // scratch1_reg: Current type to check.
-  EnsureIsTypeOrTypeParameter(assembler, scratch1_reg, scratch2_reg);
+  EnsureIsTypeOrFunctionTypeOrTypeParameter(assembler, scratch1_reg,
+                                            scratch2_reg);
   compiler::Label is_type_ref;
-  __ CompareClassId(scratch1_reg, kTypeParameterCid, scratch2_reg);
+  __ CompareClassId(scratch1_reg, kTypeCid, scratch2_reg);
   // Type parameters can't be top types themselves, though a particular
   // instantiation may result in a top type.
-  __ BranchIf(EQUAL, &done);
+  // Function types cannot be top types.
+  __ BranchIf(NOT_EQUAL, &done);
   __ LoadField(
       scratch2_reg,
       compiler::FieldAddress(scratch1_reg,
@@ -377,7 +384,8 @@
     __ BranchIf(NOT_EQUAL, &done, compiler::Assembler::kNearJump);
     __ Bind(&check_null_assignable);
     // scratch1_reg: Current type to check.
-    EnsureIsTypeOrTypeParameter(assembler, scratch1_reg, scratch2_reg);
+    EnsureIsTypeOrFunctionTypeOrTypeParameter(assembler, scratch1_reg,
+                                              scratch2_reg);
     compiler::Label is_not_type;
     __ CompareClassId(scratch1_reg, kTypeCid, scratch2_reg);
     __ BranchIf(NOT_EQUAL, &is_not_type, compiler::Assembler::kNearJump);
@@ -614,12 +622,6 @@
       target::AbstractTypeLayout::kTypeStateFinalizedInstantiated);
   __ BranchIf(NOT_EQUAL, &is_complex_case, Assembler::kNearJump);
 
-  // Check whether this [Type] is a function type.
-  __ LoadFieldFromOffset(TypeTestABI::kScratchReg, TypeTestABI::kDstTypeReg,
-                         target::Type::signature_offset());
-  __ CompareObject(TypeTestABI::kScratchReg, NullObject());
-  __ BranchIf(NOT_EQUAL, &is_complex_case, Assembler::kNearJump);
-
   // This [Type] could be a FutureOr. Subtype2TestCache does not support Smi.
   __ BranchIfSmi(TypeTestABI::kInstanceReg, &is_complex_case);
 
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 5353b50..7566ee6 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -119,11 +119,6 @@
     if (obj->IsFunction()) {
       funcHandle_ ^= obj;
       classHandle_ ^= funcHandle_.Owner();
-      // Signature functions get created, but not canonicalized, when function
-      // types get instantiated during run time type tests.
-      if (funcHandle_.IsSignatureFunction()) {
-        return;
-      }
       // Verify that the result type of a function is canonical or a
       // TypeParameter.
       typeHandle_ ^= funcHandle_.result_type();
@@ -2384,7 +2379,7 @@
   Thread* thread = Thread::Current();
   CHECK_ISOLATE(thread->isolate());
   TransitionNativeToVM transition(thread);
-  return Api::ClassId(handle) == kTypeCid;
+  return IsTypeClassId(Api::ClassId(handle));
 }
 
 DART_EXPORT bool Dart_IsFunction(Dart_Handle handle) {
@@ -5632,8 +5627,7 @@
     }
 
     // Construct the type object, canonicalize it and return.
-    type ^=
-        Type::New(cls, type_args_obj, TokenPosition::kNoSource, nullability);
+    type ^= Type::New(cls, type_args_obj, nullability);
   }
   type ^= ClassFinalizer::FinalizeType(type);
   return Api::NewHandle(T, type.raw());
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 323fd11..ce152a5 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -1259,8 +1259,7 @@
 
   if ((function().IsGeneric() || function().HasGenericParent()) &&
       type_arguments_available) {
-    intptr_t num_vars =
-        function().NumTypeParameters() + function().NumParentTypeParameters();
+    intptr_t num_vars = function().NumTypeArguments();
     type_params_names.Grow(num_vars);
     type_params_names.SetLength(num_vars);
     TypeArguments& type_params = TypeArguments::Handle();
@@ -1271,6 +1270,7 @@
                   current = current.parent_function()) {
       type_params = current.type_parameters();
       intptr_t size = current.NumTypeParameters();
+      ASSERT(size == 0 || type_params.Length() == size);
       ASSERT(mapping_offset >= size);
       mapping_offset -= size;
       for (intptr_t j = 0; j < size; ++j) {
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 82db8b2..94ce65c 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -2086,9 +2086,6 @@
   Code& code = Code::Handle(zone);
   for (intptr_t i = 0; i < functions.length(); i++) {
     const Function& func = *functions[i];
-    if (func.IsSignatureFunction()) {
-      continue;
-    }
 
     // Switch to unoptimized code or the lazy compilation stub.
     func.SwitchToLazyCompiledUnoptimizedCode();
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 0d043d2..437cbd7 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -1418,8 +1418,9 @@
   // kImplementedClasses, [...].
 
   // Set type parameters.
-  T.LoadAndSetupTypeParameters(&active_class_, *klass, type_parameter_count,
-                               Function::Handle(Z));
+  T.LoadAndSetupTypeParameters(&active_class_, Object::null_function(), *klass,
+                               Object::null_function_type(),
+                               type_parameter_count, klass->nnbd_mode());
 
   // Set super type.  Some classes (e.g., Object) do not have one.
   Tag type_tag = helper_.ReadTag();  // read super class type (part 1).
@@ -1702,8 +1703,9 @@
       owner = &ClassForScriptAt(klass, source_uri_index);
     }
 
-    Function& function = Function::ZoneHandle(
-        Z, Function::New(name, FunctionLayout::kConstructor,
+    FunctionType& signature = FunctionType::Handle(Z, FunctionType::New());
+    const Function& function = Function::ZoneHandle(
+        Z, Function::New(signature, name, FunctionLayout::kConstructor,
                          false,  // is_static
                          constructor_helper.IsConst(),
                          false,  // is_abstract
@@ -1711,9 +1713,8 @@
                          false,  // is_native
                          *owner, constructor_helper.start_position_));
     function.set_end_token_pos(constructor_helper.end_position_);
-    functions_.Add(&function);
     function.set_kernel_offset(constructor_offset);
-    function.set_result_type(T.ReceiverType(klass));
+    signature.set_result_type(T.ReceiverType(klass));
     function.set_has_pragma(has_pragma_annotation);
 
     FunctionNodeHelper function_node_helper(&helper_);
@@ -1738,6 +1739,16 @@
     constructor_helper.SetJustRead(ConstructorHelper::kFunction);
     constructor_helper.ReadUntilExcluding(ConstructorHelper::kEnd);
 
+    if (klass.is_finalized()) {
+      // The owner class has already been marked as finalized (e.g. class
+      // 'NativeFieldWrapperClass1'), so the signature of this added constructor
+      // must be finalized here, since finalization of member types will not be
+      // called anymore.
+      signature ^= ClassFinalizer::FinalizeType(signature);
+      function.set_signature(signature);
+    }
+    functions_.Add(&function);
+
     if ((FLAG_enable_mirrors || has_pragma_annotation) &&
         annotation_count > 0) {
       library.AddMetadata(function, constructor_offset);
@@ -1981,8 +1992,9 @@
   // they are not reachable anymore and we never look them up by name.
   const bool register_function = !name.Equals(Symbols::DebugProcedureName());
 
-  Function& function = Function::ZoneHandle(
-      Z, Function::New(name, kind,
+  const FunctionType& signature = FunctionType::Handle(Z, FunctionType::New());
+  const Function& function = Function::ZoneHandle(
+      Z, Function::New(signature, name, kind,
                        !is_method,  // is_static
                        false,       // is_const
                        is_abstract, is_external,
@@ -2208,10 +2220,11 @@
       H.DartGetterName(field_helper->canonical_name_getter_);
   const Object& script_class =
       ClassForScriptAt(klass, field_helper->source_uri_index_);
+  const FunctionType& signature = FunctionType::Handle(Z, FunctionType::New());
   Function& getter = Function::ZoneHandle(
       Z,
       Function::New(
-          getter_name,
+          signature, getter_name,
           field_helper->IsStatic() ? FunctionLayout::kImplicitStaticGetter
                                    : FunctionLayout::kImplicitGetter,
           field_helper->IsStatic(),
@@ -2228,7 +2241,7 @@
   getter.set_end_token_pos(field_helper->end_position_);
   getter.set_kernel_offset(field.kernel_offset());
   const AbstractType& field_type = AbstractType::Handle(Z, field.type());
-  getter.set_result_type(field_type);
+  signature.set_result_type(field_type);
   getter.set_is_debuggable(false);
   getter.set_accessor_field(field);
   getter.set_is_extension_member(field.is_extension_member());
@@ -2240,18 +2253,21 @@
     ASSERT(!field_helper->IsConst());
     const String& setter_name =
         H.DartSetterName(field_helper->canonical_name_setter_);
+    const FunctionType& signature =
+        FunctionType::Handle(Z, FunctionType::New());
     Function& setter = Function::ZoneHandle(
-        Z, Function::New(setter_name, FunctionLayout::kImplicitSetter,
-                         field_helper->IsStatic(),
-                         false,  // is_const
-                         false,  // is_abstract
-                         false,  // is_external
-                         false,  // is_native
-                         script_class, field_helper->position_));
+        Z,
+        Function::New(signature, setter_name, FunctionLayout::kImplicitSetter,
+                      field_helper->IsStatic(),
+                      false,  // is_const
+                      false,  // is_abstract
+                      false,  // is_external
+                      false,  // is_native
+                      script_class, field_helper->position_));
     functions_.Add(&setter);
     setter.set_end_token_pos(field_helper->end_position_);
     setter.set_kernel_offset(field.kernel_offset());
-    setter.set_result_type(Object::void_type());
+    signature.set_result_type(Object::void_type());
     setter.set_is_debuggable(false);
     setter.set_accessor_field(field);
     setter.set_is_extension_member(field.is_extension_member());
@@ -2400,25 +2416,27 @@
   initializer_owner.set_library_kernel_offset(lib.kernel_offset());
 
   // Create a static initializer.
+  FunctionType& signature = FunctionType::Handle(zone, FunctionType::New());
   const Function& initializer_fun = Function::Handle(
-      zone, Function::New(init_name, FunctionLayout::kFieldInitializer,
-                          field.is_static(),  // is_static
-                          false,              // is_const
-                          false,              // is_abstract
-                          false,              // is_external
-                          false,              // is_native
-                          initializer_owner, TokenPosition::kNoSource));
+      zone,
+      Function::New(signature, init_name, FunctionLayout::kFieldInitializer,
+                    field.is_static(),  // is_static
+                    false,              // is_const
+                    false,              // is_abstract
+                    false,              // is_external
+                    false,              // is_native
+                    initializer_owner, TokenPosition::kNoSource));
   if (!field.is_static()) {
     initializer_fun.set_num_fixed_parameters(1);
-    initializer_fun.set_parameter_types(
+    signature.set_parameter_types(
         Array::Handle(zone, Array::New(1, Heap::kOld)));
-    initializer_fun.CreateNameArrayIncludingFlags(Heap::kOld);
-    initializer_fun.SetParameterTypeAt(
+    signature.CreateNameArrayIncludingFlags(Heap::kOld);
+    signature.SetParameterTypeAt(
         0, AbstractType::Handle(zone, field_owner.DeclarationType()));
-    initializer_fun.SetParameterNameAt(0, Symbols::This());
-    initializer_fun.TruncateUnusedParameterFlags();
+    signature.SetParameterNameAt(0, Symbols::This());
+    signature.FinalizeNameArrays(initializer_fun);
   }
-  initializer_fun.set_result_type(AbstractType::Handle(zone, field.type()));
+  signature.set_result_type(AbstractType::Handle(zone, field.type()));
   initializer_fun.set_is_reflectable(false);
   initializer_fun.set_is_inlinable(false);
   initializer_fun.set_token_pos(field.token_pos());
@@ -2426,6 +2444,10 @@
   initializer_fun.set_accessor_field(field);
   initializer_fun.InheritKernelOffsetFrom(field);
   initializer_fun.set_is_extension_member(field.is_extension_member());
+
+  signature ^= ClassFinalizer::FinalizeType(signature);
+  initializer_fun.set_signature(signature);
+
   field.SetInitializerFunction(initializer_fun);
   return initializer_fun.raw();
 }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index fedaad2..36a2155 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -146,7 +146,6 @@
 ClassPtr Object::patch_class_class_ = static_cast<ClassPtr>(RAW_NULL);
 ClassPtr Object::function_class_ = static_cast<ClassPtr>(RAW_NULL);
 ClassPtr Object::closure_data_class_ = static_cast<ClassPtr>(RAW_NULL);
-ClassPtr Object::signature_data_class_ = static_cast<ClassPtr>(RAW_NULL);
 ClassPtr Object::ffi_trampoline_data_class_ = static_cast<ClassPtr>(RAW_NULL);
 ClassPtr Object::field_class_ = static_cast<ClassPtr>(RAW_NULL);
 ClassPtr Object::script_class_ = static_cast<ClassPtr>(RAW_NULL);
@@ -671,10 +670,12 @@
 #undef INITIALIZE_SHARED_READONLY_HANDLE
 
   *null_object_ = Object::null();
+  *null_class_ = Class::null();
   *null_array_ = Array::null();
   *null_string_ = String::null();
   *null_instance_ = Instance::null();
   *null_function_ = Function::null();
+  *null_function_type_ = FunctionType::null();
   *null_type_arguments_ = TypeArguments::null();
   *empty_type_arguments_ = TypeArguments::null();
   *null_abstract_type_ = AbstractType::null();
@@ -783,9 +784,6 @@
   cls = Class::New<ClosureData, RTN::ClosureData>(isolate_group);
   closure_data_class_ = cls.raw();
 
-  cls = Class::New<SignatureData, RTN::SignatureData>(isolate_group);
-  signature_data_class_ = cls.raw();
-
   cls = Class::New<FfiTrampolineData, RTN::FfiTrampolineData>(isolate_group);
   ffi_trampoline_data_class_ = cls.raw();
 
@@ -1061,15 +1059,15 @@
   cls.set_is_type_finalized();
 
   cls = dynamic_class_;
-  *dynamic_type_ = Type::New(cls, Object::null_type_arguments(),
-                             TokenPosition::kNoSource, Nullability::kNullable);
+  *dynamic_type_ =
+      Type::New(cls, Object::null_type_arguments(), Nullability::kNullable);
   dynamic_type_->SetIsFinalized();
   dynamic_type_->ComputeHash();
   dynamic_type_->SetCanonical();
 
   cls = void_class_;
-  *void_type_ = Type::New(cls, Object::null_type_arguments(),
-                          TokenPosition::kNoSource, Nullability::kNullable);
+  *void_type_ =
+      Type::New(cls, Object::null_type_arguments(), Nullability::kNullable);
   void_type_->SetIsFinalized();
   void_type_->ComputeHash();
   void_type_->SetCanonical();
@@ -1132,6 +1130,8 @@
   thr->clear_pending_functions();
 
   ASSERT(!null_object_->IsSmi());
+  ASSERT(!null_class_->IsSmi());
+  ASSERT(null_class_->IsClass());
   ASSERT(!null_array_->IsSmi());
   ASSERT(null_array_->IsArray());
   ASSERT(!null_string_->IsSmi());
@@ -1140,6 +1140,8 @@
   ASSERT(null_instance_->IsInstance());
   ASSERT(!null_function_->IsSmi());
   ASSERT(null_function_->IsFunction());
+  ASSERT(!null_function_type_->IsSmi());
+  ASSERT(null_function_type_->IsFunctionType());
   ASSERT(!null_type_arguments_->IsSmi());
   ASSERT(null_type_arguments_->IsTypeArguments());
   ASSERT(!null_compressed_stackmaps_->IsSmi());
@@ -1218,7 +1220,6 @@
   patch_class_class_ = static_cast<ClassPtr>(RAW_NULL);
   function_class_ = static_cast<ClassPtr>(RAW_NULL);
   closure_data_class_ = static_cast<ClassPtr>(RAW_NULL);
-  signature_data_class_ = static_cast<ClassPtr>(RAW_NULL);
   ffi_trampoline_data_class_ = static_cast<ClassPtr>(RAW_NULL);
   field_class_ = static_cast<ClassPtr>(RAW_NULL);
   script_class_ = static_cast<ClassPtr>(RAW_NULL);
@@ -1318,7 +1319,6 @@
   SET_CLASS_NAME(patch_class, PatchClass);
   SET_CLASS_NAME(function, Function);
   SET_CLASS_NAME(closure_data, ClosureData);
-  SET_CLASS_NAME(signature_data, SignatureData);
   SET_CLASS_NAME(ffi_trampoline_data, FfiTrampolineData);
   SET_CLASS_NAME(field, Field);
   SET_CLASS_NAME(script, Script);
@@ -1604,6 +1604,12 @@
                                               Heap::kOld);
     object_store->set_canonical_types(array);
 
+    // Initialize hash set for canonical function types.
+    const intptr_t kInitialCanonicalFunctionTypeSize = 16;
+    array = HashTables::New<CanonicalFunctionTypeSet>(
+        kInitialCanonicalFunctionTypeSize, Heap::kOld);
+    object_store->set_canonical_function_types(array);
+
     // Initialize hash set for canonical type parameters.
     const intptr_t kInitialCanonicalTypeParameterSize = 4;
     array = HashTables::New<CanonicalTypeParameterSet>(
@@ -1619,6 +1625,8 @@
     // Setup type class early in the process.
     const Class& type_cls =
         Class::Handle(zone, Class::New<Type, RTN::Type>(isolate_group));
+    const Class& function_type_cls = Class::Handle(
+        zone, Class::New<FunctionType, RTN::FunctionType>(isolate_group));
     const Class& type_ref_cls =
         Class::Handle(zone, Class::New<TypeRef, RTN::TypeRef>(isolate_group));
     const Class& type_parameter_cls = Class::Handle(
@@ -1665,9 +1673,8 @@
     // declared number of type parameters is still 0. It will become 1 after
     // patching. The array type allocated below represents the raw type _List
     // and not _List<E> as we could expect. Use with caution.
-    type =
-        Type::New(Class::Handle(zone, cls.raw()), TypeArguments::Handle(zone),
-                  TokenPosition::kNoSource, Nullability::kNonNullable);
+    type = Type::New(Class::Handle(zone, cls.raw()),
+                     TypeArguments::Handle(zone), Nullability::kNonNullable);
     type.SetIsFinalized();
     type ^= type.Canonicalize(thread, nullptr);
     object_store->set_array_type(type);
@@ -1753,9 +1760,8 @@
     // Initialize the base interfaces used by the core VM classes.
 
     // Allocate and initialize the pre-allocated classes in the core library.
-    // The script and token index of these pre-allocated classes is set up in
-    // the parser when the corelib script is compiled (see
-    // Parser::ParseClassDefinition).
+    // The script and token index of these pre-allocated classes is set up when
+    // the corelib script is compiled.
     cls = Class::New<Instance, RTN::Instance>(kInstanceCid, isolate_group);
     object_store->set_object_class(cls);
     cls.set_name(Symbols::Object());
@@ -1765,12 +1771,16 @@
     core_lib.AddClass(cls);
     pending_classes.Add(cls);
     type = Type::NewNonParameterizedType(cls);
+    ASSERT(type.IsCanonical());
     object_store->set_object_type(type);
     type = type.ToNullability(Nullability::kLegacy, Heap::kOld);
+    ASSERT(type.IsCanonical());
     object_store->set_legacy_object_type(type);
     type = type.ToNullability(Nullability::kNonNullable, Heap::kOld);
+    ASSERT(type.IsCanonical());
     object_store->set_non_nullable_object_type(type);
     type = type.ToNullability(Nullability::kNullable, Heap::kOld);
+    ASSERT(type.IsCanonical());
     object_store->set_nullable_object_type(type);
 
     cls = Class::New<Bool, RTN::Bool>(isolate_group);
@@ -1801,6 +1811,9 @@
     RegisterPrivateClass(type_cls, Symbols::_Type(), core_lib);
     pending_classes.Add(type_cls);
 
+    RegisterPrivateClass(function_type_cls, Symbols::_FunctionType(), core_lib);
+    pending_classes.Add(function_type_cls);
+
     RegisterPrivateClass(type_ref_cls, Symbols::_TypeRef(), core_lib);
     pending_classes.Add(type_ref_cls);
 
@@ -1838,9 +1851,8 @@
     object_store->set_weak_property_class(cls);
     RegisterPrivateClass(cls, Symbols::_WeakProperty(), core_lib);
 
-// Pre-register the mirrors library so we can place the vm class
-// MirrorReference there rather than the core library.
-#if !defined(DART_PRECOMPILED_RUNTIME)
+    // Pre-register the mirrors library so we can place the vm class
+    // MirrorReference there rather than the core library.
     lib = Library::LookupLibrary(thread, Symbols::DartMirrors());
     if (lib.IsNull()) {
       lib = Library::NewLibraryHelper(Symbols::DartMirrors(), true);
@@ -1853,7 +1865,6 @@
 
     cls = Class::New<MirrorReference, RTN::MirrorReference>(isolate_group);
     RegisterPrivateClass(cls, Symbols::_MirrorReference(), lib);
-#endif
 
     // Pre-register the collection library so we can place the vm class
     // LinkedHashMap there rather than the core library.
@@ -2122,8 +2133,8 @@
     // name is a built-in identifier (this is wrong).  The corresponding types
     // are stored in the object store.
     cls = object_store->null_class();
-    type = Type::New(cls, Object::null_type_arguments(),
-                     TokenPosition::kNoSource, Nullability::kNullable);
+    type =
+        Type::New(cls, Object::null_type_arguments(), Nullability::kNullable);
     type.SetIsFinalized();
     type ^= type.Canonicalize(thread, nullptr);
     object_store->set_null_type(type);
@@ -2135,7 +2146,7 @@
 
     cls = object_store->never_class();
     type = Type::New(cls, Object::null_type_arguments(),
-                     TokenPosition::kNoSource, Nullability::kNonNullable);
+                     Nullability::kNonNullable);
     type.SetIsFinalized();
     type ^= type.Canonicalize(thread, nullptr);
     object_store->set_never_type(type);
@@ -2323,6 +2334,7 @@
 
     cls = Class::New<LibraryPrefix, RTN::LibraryPrefix>(isolate_group);
     cls = Class::New<Type, RTN::Type>(isolate_group);
+    cls = Class::New<FunctionType, RTN::FunctionType>(isolate_group);
     cls = Class::New<TypeRef, RTN::TypeRef>(isolate_group);
     cls = Class::New<TypeParameter, RTN::TypeParameter>(isolate_group);
 
@@ -2725,13 +2737,12 @@
 }
 
 AbstractTypePtr Class::RareType() const {
-  if (!IsGeneric() && !IsClosureClass() && !IsTypedefClass()) {
+  if (!IsGeneric() && !IsClosureClass()) {
     return DeclarationType();
   }
   ASSERT(is_declaration_loaded());
-  const Type& type = Type::Handle(
-      Type::New(*this, Object::null_type_arguments(), TokenPosition::kNoSource,
-                Nullability::kNonNullable));
+  const Type& type = Type::Handle(Type::New(
+      *this, Object::null_type_arguments(), Nullability::kNonNullable));
   return ClassFinalizer::FinalizeType(type);
 }
 
@@ -2892,14 +2903,23 @@
 typedef UnorderedHashSet<ClassFunctionsTraits> ClassFunctionsSet;
 
 void Class::SetFunctions(const Array& value) const {
+  ASSERT(!value.IsNull());
+  const intptr_t len = value.Length();
 #if defined(DEBUG)
   Thread* thread = Thread::Current();
   ASSERT(thread->IsMutatorThread());
   ASSERT(thread->isolate_group()->program_lock()->IsCurrentThreadWriter());
+  if (is_finalized()) {
+    Function& function = Function::Handle();
+    FunctionType& signature = FunctionType::Handle();
+    for (intptr_t i = 0; i < len; ++i) {
+      function ^= value.At(i);
+      signature = function.signature();
+      ASSERT(signature.IsFinalized());
+    }
+  }
 #endif
-  ASSERT(!value.IsNull());
   set_functions(value);
-  const intptr_t len = value.Length();
   if (len >= kFunctionLookupHashTreshold) {
     ClassFunctionsSet set(HashTables::New<ClassFunctionsSet>(len, Heap::kOld));
     Function& func = Function::Handle();
@@ -2920,6 +2940,8 @@
   Thread* thread = Thread::Current();
   ASSERT(thread->IsMutatorThread());
   ASSERT(thread->isolate_group()->program_lock()->IsCurrentThreadWriter());
+  ASSERT(!is_finalized() ||
+         FunctionType::Handle(function.signature()).IsFinalized());
 #endif
   const Array& arr = Array::Handle(functions());
   const Array& new_array =
@@ -3035,11 +3057,6 @@
   return Function::Cast(object).raw();
 }
 
-void Class::set_signature_function(const Function& value) const {
-  ASSERT(value.IsClosureFunction() || value.IsSignatureFunction());
-  raw_ptr()->set_signature_function(value.raw());
-}
-
 void Class::set_state_bits(intptr_t bits) const {
   StoreNonPointer<uint32_t, uint32_t, std::memory_order_release>(
       &raw_ptr()->state_bits_, static_cast<uint32_t>(bits));
@@ -3109,8 +3126,6 @@
   ASSERT(sup_type.IsType());
 
   const auto& sup_class = Class::Handle(zone, sup_type.type_class());
-  ASSERT(!sup_class.IsTypedefClass());
-
   const intptr_t sup_class_num_type_args = sup_class.NumTypeArguments();
   if (num_type_params == 0) {
     return sup_class_num_type_args;
@@ -3149,8 +3164,10 @@
     intptr_t i = 0;
     for (; i < num_overlapping_type_args; i++) {
       type_param ^= type_params.TypeAt(i);
+      ASSERT(!type_param.IsNull());
       sup_type_arg = sup_type_args.TypeAt(sup_type_args_length -
                                           num_overlapping_type_args + i);
+      ASSERT(!sup_type_arg.IsNull());
       if (!type_param.Equals(sup_type_arg)) break;
     }
     if (i == num_overlapping_type_args) {
@@ -3470,8 +3487,10 @@
                                               FunctionLayout::Kind kind) const {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
+  FunctionType& signature = FunctionType::Handle(zone, FunctionType::New());
   Function& invocation = Function::Handle(
       zone, Function::New(
+                signature,
                 String::Handle(zone, Symbols::New(thread, target_name)), kind,
                 false,  // Not static.
                 false,  // Not const.
@@ -3482,29 +3501,24 @@
   ArgumentsDescriptor desc(args_desc);
   if (desc.TypeArgsLen() > 0) {
     // Make dispatcher function generic, since type arguments are passed.
-    const TypeArguments& type_params =
-        TypeArguments::Handle(zone, TypeArguments::New(desc.TypeArgsLen()));
-    // The presence of a type parameter array is enough to mark this dispatcher
-    // as generic. To save memory, we do not copy the type parameters to the
-    // array (they are not accessed), but leave it as an array of null objects.
-    invocation.set_type_parameters(type_params);
+    invocation.SetNumTypeParameters(desc.TypeArgsLen());
   }
 
   invocation.set_num_fixed_parameters(desc.PositionalCount());
   invocation.SetNumOptionalParameters(desc.NamedCount(),
                                       false);  // Not positional.
-  invocation.set_parameter_types(
+  signature.set_parameter_types(
       Array::Handle(zone, Array::New(desc.Count(), Heap::kOld)));
-  invocation.CreateNameArrayIncludingFlags(Heap::kOld);
+  signature.CreateNameArrayIncludingFlags(Heap::kOld);
   // Receiver.
-  invocation.SetParameterTypeAt(0, Object::dynamic_type());
-  invocation.SetParameterNameAt(0, Symbols::This());
+  signature.SetParameterTypeAt(0, Object::dynamic_type());
+  signature.SetParameterNameAt(0, Symbols::This());
   // Remaining positional parameters.
   for (intptr_t i = 1; i < desc.PositionalCount(); i++) {
-    invocation.SetParameterTypeAt(i, Object::dynamic_type());
+    signature.SetParameterTypeAt(i, Object::dynamic_type());
     char name[64];
     Utils::SNPrint(name, 64, ":p%" Pd, i);
-    invocation.SetParameterNameAt(
+    signature.SetParameterNameAt(
         i, String::Handle(zone, Symbols::New(thread, name)));
   }
 
@@ -3512,16 +3526,19 @@
   for (intptr_t i = 0; i < desc.NamedCount(); i++) {
     const intptr_t param_index = desc.PositionAt(i);
     const auto& param_name = String::Handle(zone, desc.NameAt(i));
-    invocation.SetParameterTypeAt(param_index, Object::dynamic_type());
-    invocation.SetParameterNameAt(param_index, param_name);
+    signature.SetParameterTypeAt(param_index, Object::dynamic_type());
+    signature.SetParameterNameAt(param_index, param_name);
   }
-  invocation.TruncateUnusedParameterFlags();
-  invocation.set_result_type(Object::dynamic_type());
+  signature.FinalizeNameArrays(invocation);
+  signature.set_result_type(Object::dynamic_type());
   invocation.set_is_debuggable(false);
   invocation.set_is_visible(false);
   invocation.set_is_reflectable(false);
   invocation.set_saved_args_desc(args_desc);
 
+  signature ^= ClassFinalizer::FinalizeType(signature);
+  invocation.set_signature(signature);
+
   return invocation.raw();
 }
 
@@ -3538,9 +3555,11 @@
       Function::Handle(zone, ImplicitClosureFunction());
 
   const Class& owner = Class::Handle(zone, closure_function.Owner());
-  Function& extractor = Function::Handle(
+  FunctionType& signature = FunctionType::Handle(zone, FunctionType::New());
+  const Function& extractor = Function::Handle(
       zone,
-      Function::New(String::Handle(zone, Symbols::New(thread, getter_name)),
+      Function::New(signature,
+                    String::Handle(zone, Symbols::New(thread, getter_name)),
                     FunctionLayout::kMethodExtractor,
                     false,  // Not static.
                     false,  // Not const.
@@ -3553,9 +3572,10 @@
   const intptr_t kNumParameters = 1;
   extractor.set_num_fixed_parameters(kNumParameters);
   extractor.SetNumOptionalParameters(0, false);
-  extractor.set_parameter_types(Object::extractor_parameter_types());
-  extractor.set_parameter_names(Object::extractor_parameter_names());
-  extractor.set_result_type(Object::dynamic_type());
+  signature.set_parameter_types(Object::extractor_parameter_types());
+  signature.set_parameter_names(Object::extractor_parameter_names());
+  extractor.SetParameterNamesFrom(signature);
+  signature.set_result_type(Object::dynamic_type());
 
   extractor.InheritKernelOffsetFrom(*this);
 
@@ -3563,6 +3583,9 @@
   extractor.set_is_debuggable(false);
   extractor.set_is_visible(false);
 
+  signature ^= ClassFinalizer::FinalizeType(signature);
+  extractor.set_signature(signature);
+
   owner.AddFunction(extractor);
 
   return extractor.raw();
@@ -4524,6 +4547,9 @@
     cls.set_next_field_offset(host_instance_size, target_instance_size);
     cls.set_num_native_fields(field_count);
     cls.set_is_allocate_finalized();
+    // The signature of the constructor yet to be added to this class will have
+    // to be finalized explicitly, since the class is prematurely marked as
+    // 'is_allocate_finalized' and finalization of member types will not occur.
     cls.set_is_declaration_loaded();
     cls.set_is_type_finalized();
     cls.set_is_synthesized_class();
@@ -4746,8 +4772,6 @@
       return Symbols::Function().ToCString();
     case kClosureDataCid:
       return Symbols::ClosureData().ToCString();
-    case kSignatureDataCid:
-      return Symbols::SignatureData().ToCString();
     case kFfiTrampolineDataCid:
       return Symbols::FfiTrampolineData().ToCString();
     case kFieldCid:
@@ -5021,7 +5045,7 @@
   // The exception is type Null which is stored as kNullable.
   Type& type =
       Type::Handle(Type::New(*this, TypeArguments::Handle(type_parameters()),
-                             token_pos(), Nullability::kNonNullable));
+                             Nullability::kNonNullable));
   type ^= ClassFinalizer::FinalizeType(type);
   set_declaration_type(type);
   return type.raw();
@@ -5073,7 +5097,7 @@
   classid_t this_cid = cls.id();
   ASSERT(this_cid != kNullCid && this_cid != kNeverCid &&
          this_cid != kDynamicCid && this_cid != kVoidCid);
-  // Type T1 must have a type class (e.g. not a type parameter).
+  // Type T1 must have a type class (e.g. not a type param or a function type).
   ASSERT(other.HasTypeClass());
   const classid_t other_cid = other.type_class_id();
   if (other_cid == kDynamicCid || other_cid == kVoidCid) {
@@ -5961,13 +5985,10 @@
   return Symbols::New(thread, printer.buffer());
 }
 
-void TypeArguments::PrintSubvectorName(
-    intptr_t from_index,
-    intptr_t len,
-    NameVisibility name_visibility,
-    BaseTextBuffer* printer,
-    NameDisambiguation name_disambiguation /* = NameDisambiguation::kNo */)
-    const {
+void TypeArguments::PrintSubvectorName(intptr_t from_index,
+                                       intptr_t len,
+                                       NameVisibility name_visibility,
+                                       BaseTextBuffer* printer) const {
   printer->AddString("<");
   AbstractType& type = AbstractType::Handle();
   for (intptr_t i = 0; i < len; i++) {
@@ -5976,7 +5997,7 @@
       if (type.IsNull()) {
         printer->AddString("null");  // Unfinalized vector.
       } else {
-        type.PrintName(name_visibility, printer, name_disambiguation);
+        type.PrintName(name_visibility, printer);
       }
     } else {
       printer->AddString("dynamic");
@@ -6029,7 +6050,7 @@
   return true;
 }
 
-bool TypeArguments::IsRecursive() const {
+bool TypeArguments::IsRecursive(TrailPtr trail) const {
   if (IsNull()) return false;
   const intptr_t num_types = Length();
   AbstractType& type = AbstractType::Handle();
@@ -6039,7 +6060,7 @@
     // argument is still being finalized and is definitely recursive. The null
     // type argument will be replaced by a non-null type before the type is
     // marked as finalized.
-    if (type.IsNull() || type.IsRecursive()) {
+    if (type.IsNull() || type.IsRecursive(trail)) {
       return true;
     }
   }
@@ -6298,10 +6319,10 @@
     *with_runtime_check = false;
   }
   const intptr_t num_type_args = Length();
-  const intptr_t num_parent_type_params = function.NumParentTypeParameters();
+  const intptr_t num_parent_type_args = function.NumParentTypeArguments();
   const intptr_t num_function_type_params = function.NumTypeParameters();
   const intptr_t num_function_type_args =
-      num_parent_type_params + num_function_type_params;
+      num_parent_type_args + num_function_type_params;
   if (num_type_args > num_function_type_args) {
     // This vector cannot be a prefix of a shorter vector.
     return false;
@@ -6892,14 +6913,10 @@
 }
 
 FunctionPtr Function::parent_function() const {
-  if (IsClosureFunction() || IsSignatureFunction()) {
+  if (IsClosureFunction()) {
     const Object& obj = Object::Handle(raw_ptr()->data());
     ASSERT(!obj.IsNull());
-    if (IsClosureFunction()) {
-      return ClosureData::Cast(obj).parent_function();
-    } else {
-      return SignatureData::Cast(obj).parent_function();
-    }
+    return ClosureData::Cast(obj).parent_function();
   }
   return Function::null();
 }
@@ -6907,12 +6924,8 @@
 void Function::set_parent_function(const Function& value) const {
   const Object& obj = Object::Handle(raw_ptr()->data());
   ASSERT(!obj.IsNull());
-  if (IsClosureFunction()) {
-    ClosureData::Cast(obj).set_parent_function(value);
-  } else {
-    ASSERT(IsSignatureFunction());
-    SignatureData::Cast(obj).set_parent_function(value);
-  }
+  ASSERT(IsClosureFunction());
+  ClosureData::Cast(obj).set_parent_function(value);
 }
 
 TypeArgumentsPtr Function::InstantiateToBounds(
@@ -6952,8 +6965,9 @@
   }
   if (CachesDefaultTypeArguments()) {
     auto defaults = &Object::empty_type_arguments();
-    if (NumTypeParameters(thread) > 0) {
-      const auto& params = TypeArguments::Handle(zone, type_parameters());
+    const FunctionType& sig = FunctionType::Handle(zone, signature());
+    if (sig.NumTypeParameters(thread) > 0) {
+      const auto& params = TypeArguments::Handle(zone, sig.type_parameters());
       const intptr_t num_params = params.Length();
       auto& new_defaults = TypeArguments::Handle(
           zone, TypeArguments::New(num_params, Heap::kNew));
@@ -7009,7 +7023,7 @@
   auto kind = DefaultTypeArgumentsKindFor(value);
   ASSERT(kind != DefaultTypeArgumentsKind::kInvalid);
   updated_info = DefaultTypeArgumentsKindField::update(kind, updated_info);
-  updated_info = NumParentTypeParametersField::update(NumParentTypeParameters(),
+  updated_info = NumParentTypeParametersField::update(NumParentTypeArguments(),
                                                       updated_info);
   closure_data.set_default_type_arguments_info(updated_info);
   // We could just store null for the ksharesFunction/kSharesInstantiator cases,
@@ -7063,8 +7077,8 @@
 }
 
 FunctionPtr Function::implicit_closure_function() const {
-  if (IsClosureFunction() || IsSignatureFunction() || IsFactory() ||
-      IsDispatcherOrImplicitAccessor() || IsFieldInitializer()) {
+  if (IsClosureFunction() || IsFactory() || IsDispatcherOrImplicitAccessor() ||
+      IsFieldInitializer() || IsFfiTrampoline()) {
     return Function::null();
   }
   const Object& obj = Object::Handle(raw_ptr()->data());
@@ -7082,7 +7096,7 @@
 }
 
 void Function::set_implicit_closure_function(const Function& value) const {
-  ASSERT(!IsClosureFunction() && !IsSignatureFunction());
+  ASSERT(!IsClosureFunction());
   const Object& old_data = Object::Handle(raw_ptr()->data());
   if (is_native()) {
     ASSERT(old_data.IsArray());
@@ -7100,27 +7114,14 @@
   }
 }
 
-TypePtr Function::ExistingSignatureType() const {
-  const Object& obj = Object::Handle(raw_ptr()->data());
-  ASSERT(!obj.IsNull());
-  if (IsSignatureFunction()) {
-    return SignatureData::Cast(obj).signature_type();
-  } else if (IsClosureFunction()) {
-    return ClosureData::Cast(obj).signature_type();
-  } else {
-    ASSERT(IsFfiTrampoline());
-    return FfiTrampolineData::Cast(obj).signature_type();
-  }
-}
-
-void Function::SetFfiCSignature(const Function& sig) const {
+void Function::SetFfiCSignature(const FunctionType& sig) const {
   ASSERT(IsFfiTrampoline());
   const Object& obj = Object::Handle(raw_ptr()->data());
   ASSERT(!obj.IsNull());
   FfiTrampolineData::Cast(obj).set_c_signature(sig);
 }
 
-FunctionPtr Function::FfiCSignature() const {
+FunctionTypePtr Function::FfiCSignature() const {
   ASSERT(IsFfiTrampoline());
   const Object& obj = Object::Handle(raw_ptr()->data());
   ASSERT(!obj.IsNull());
@@ -7129,7 +7130,7 @@
 
 bool Function::FfiCSignatureContainsHandles() const {
   ASSERT(IsFfiTrampoline());
-  const Function& c_signature = Function::Handle(FfiCSignature());
+  const FunctionType& c_signature = FunctionType::Handle(FfiCSignature());
   const intptr_t num_params = c_signature.num_fixed_parameters();
   for (intptr_t i = 0; i < num_params; i++) {
     const bool is_handle =
@@ -7145,7 +7146,7 @@
 
 bool Function::FfiCSignatureReturnsStruct() const {
   ASSERT(IsFfiTrampoline());
-  const Function& c_signature = Function::Handle(FfiCSignature());
+  const FunctionType& c_signature = FunctionType::Handle(FfiCSignature());
   const auto& return_type = AbstractType::Handle(c_signature.result_type());
   const bool predefined = IsFfiTypeClassId(return_type.type_class_id());
   return !predefined;
@@ -7193,62 +7194,6 @@
   FfiTrampolineData::Cast(obj).set_callback_exceptional_return(value);
 }
 
-TypePtr Function::SignatureType(Nullability nullability) const {
-  Type& type = Type::Handle(ExistingSignatureType());
-  if (type.IsNull()) {
-    // The function type of this function is not yet cached and needs to be
-    // constructed and cached here.
-    // A function type is type parameterized in the same way as the owner class
-    // of its non-static signature function.
-    // It is not type parameterized if its signature function is static, or if
-    // none of its result type or formal parameter types are type parameterized.
-    // Unless the function type is a generic typedef, the type arguments of the
-    // function type are not explicitly stored in the function type as a vector
-    // of type arguments.
-    // The type class of a non-typedef function type is always the non-generic
-    // _Closure class, whether the type is generic or not.
-    // The type class of a typedef function type is always the typedef class,
-    // which may be generic, in which case the type stores type arguments.
-    // With the introduction of generic functions, we may reach here before the
-    // function type parameters have been resolved. Therefore, we cannot yet
-    // check whether the function type has an instantiated signature.
-    // We can do it only when the signature has been resolved.
-    // We only set the type class of the function type to the typedef class
-    // if the signature of the function type is the signature of the typedef.
-    // Note that a function type can have a typedef class as owner without
-    // representing the typedef, as in the following example:
-    // typedef F(f(int x)); where the type of f is a function type with F as
-    // owner, without representing the function type of F.
-    Class& scope_class = Class::Handle(Owner());
-    if (!scope_class.IsTypedefClass() ||
-        (scope_class.signature_function() != raw())) {
-      scope_class = IsolateGroup::Current()->object_store()->closure_class();
-    }
-    const TypeArguments& signature_type_arguments =
-        TypeArguments::Handle(scope_class.type_parameters());
-    // Return the still unfinalized signature type.
-    type = Type::New(scope_class, signature_type_arguments, token_pos(),
-                     nullability);
-    type.set_signature(*this);
-    SetSignatureType(type);
-  }
-  return type.ToNullability(nullability, Heap::kOld);
-}
-
-void Function::SetSignatureType(const Type& value) const {
-  const Object& obj = Object::Handle(raw_ptr()->data());
-  ASSERT(!obj.IsNull());
-  if (IsSignatureFunction()) {
-    SignatureData::Cast(obj).set_signature_type(value);
-    ASSERT(!value.IsCanonical() || (value.signature() == this->raw()));
-  } else if (IsClosureFunction()) {
-    ClosureData::Cast(obj).set_signature_type(value);
-  } else {
-    ASSERT(IsFfiTrampoline());
-    FfiTrampolineData::Cast(obj).set_signature_type(value);
-  }
-}
-
 const char* Function::KindToCString(FunctionLayout::Kind kind) {
   return FunctionLayout::KindToCString(kind);
 }
@@ -7268,11 +7213,9 @@
 }
 
 // This field is heavily overloaded:
-//   eval function:           Script expression source
 //   kernel eval function:    Array[0] = Script
 //                            Array[1] = Kernel data
 //                            Array[2] = Kernel offset of enclosing library
-//   signature function:      SignatureData
 //   method extractor:        Function extracted closure function
 //   implicit getter:         Field
 //   implicit setter:         Field
@@ -7310,7 +7253,7 @@
 }
 
 void Function::set_owner(const Object& value) const {
-  ASSERT(!value.IsNull() || IsSignatureFunction());
+  ASSERT(!value.IsNull());
   raw_ptr()->set_owner(value.raw());
 }
 
@@ -7381,26 +7324,45 @@
   set_data(pair);
 }
 
-void Function::set_result_type(const AbstractType& value) const {
+void Function::set_signature(const FunctionType& value) const {
+  // Signature may be reset to null in aot to save space.
+  raw_ptr()->set_signature(value.raw());
+  if (!value.IsNull()) {
+    ASSERT(NumImplicitParameters() == value.num_implicit_parameters());
+    UpdateCachedDefaultTypeArguments(Thread::Current());
+  }
+}
+
+void FunctionType::set_result_type(const AbstractType& value) const {
   ASSERT(!value.IsNull());
   raw_ptr()->set_result_type(value.raw());
 }
 
 AbstractTypePtr Function::ParameterTypeAt(intptr_t index) const {
+  const Array& parameter_types =
+      Array::Handle(raw_ptr()->signature()->ptr()->parameter_types());
+  return AbstractType::RawCast(parameter_types.At(index));
+}
+
+AbstractTypePtr FunctionType::ParameterTypeAt(intptr_t index) const {
   const Array& parameter_types = Array::Handle(raw_ptr()->parameter_types());
   return AbstractType::RawCast(parameter_types.At(index));
 }
 
-void Function::SetParameterTypeAt(intptr_t index,
-                                  const AbstractType& value) const {
+void FunctionType::SetParameterTypeAt(intptr_t index,
+                                      const AbstractType& value) const {
   ASSERT(!value.IsNull());
-  // Method extractor parameters are shared and are in the VM heap.
-  ASSERT(kind() != FunctionLayout::kMethodExtractor);
   const Array& parameter_types = Array::Handle(raw_ptr()->parameter_types());
   parameter_types.SetAt(index, value);
 }
 
 void Function::set_parameter_types(const Array& value) const {
+  ASSERT(value.IsNull() || value.Length() > 0);
+  raw_ptr()->signature()->ptr()->set_parameter_types(value.raw());
+}
+
+void FunctionType::set_parameter_types(const Array& value) const {
+  ASSERT(value.IsNull() || value.Length() > 0);
   raw_ptr()->set_parameter_types(value.raw());
 }
 
@@ -7409,19 +7371,36 @@
   return String::RawCast(parameter_names.At(index));
 }
 
-void Function::SetParameterNameAt(intptr_t index, const String& value) const {
+void Function::SetParameterNamesFrom(const FunctionType& signature) const {
+  raw_ptr()->set_parameter_names(signature.parameter_names());
+}
+
+StringPtr FunctionType::ParameterNameAt(intptr_t index) const {
+  const Array& parameter_names = Array::Handle(raw_ptr()->parameter_names());
+  return String::RawCast(parameter_names.At(index));
+}
+
+void FunctionType::SetParameterNameAt(intptr_t index,
+                                      const String& value) const {
   ASSERT(!value.IsNull() && value.IsSymbol());
   const Array& parameter_names = Array::Handle(raw_ptr()->parameter_names());
   parameter_names.SetAt(index, value);
 }
 
 void Function::set_parameter_names(const Array& value) const {
+  ASSERT(value.IsNull() || value.Length() > 0);
   raw_ptr()->set_parameter_names(value.raw());
 }
 
-void Function::CreateNameArrayIncludingFlags(Heap::Space space) const {
+void FunctionType::set_parameter_names(const Array& value) const {
+  ASSERT(value.IsNull() || value.Length() > 0);
+  raw_ptr()->set_parameter_names(value.raw());
+}
+
+void FunctionType::CreateNameArrayIncludingFlags(Heap::Space space) const {
   // Currently, we only store flags for named parameters that are required.
   const intptr_t num_parameters = NumParameters();
+  if (num_parameters == 0) return;
   intptr_t num_total_slots = num_parameters;
   if (HasOptionalNamedParameters()) {
     const intptr_t last_index = (NumOptionalNamedParameters() - 1) /
@@ -7440,8 +7419,8 @@
   set_parameter_names(array);
 }
 
-intptr_t Function::GetRequiredFlagIndex(intptr_t index,
-                                        intptr_t* flag_mask) const {
+intptr_t FunctionType::GetRequiredFlagIndex(intptr_t index,
+                                            intptr_t* flag_mask) const {
   // If these calculations change, also change
   // FlowGraphBuilder::BuildClosureCallHasRequiredNamedArgumentsCheck.
   ASSERT(flag_mask != nullptr);
@@ -7455,10 +7434,40 @@
          index / compiler::target::kNumParameterFlagsPerElement;
 }
 
+bool Function::HasRequiredNamedParameters() const {
+  const FunctionType& sig = FunctionType::Handle(signature());
+#if defined(DART_PRECOMPILED_RUNTIME)
+  if (sig.IsNull()) {
+    // Signature is not dropped in aot when any named parameter is required.
+    return false;
+  }
+#else
+  ASSERT(!sig.IsNull());
+#endif
+  const Array& parameter_names = Array::Handle(sig.parameter_names());
+  return parameter_names.Length() > NumParameters();
+}
+
 bool Function::IsRequiredAt(intptr_t index) const {
   if (index < num_fixed_parameters() + NumOptionalPositionalParameters()) {
     return false;
   }
+  const FunctionType& sig = FunctionType::Handle(signature());
+#if defined(DART_PRECOMPILED_RUNTIME)
+  if (sig.IsNull()) {
+    // Signature is not dropped in aot when any named parameter is required.
+    return false;
+  }
+#else
+  ASSERT(!sig.IsNull());
+#endif
+  return sig.IsRequiredAt(index);
+}
+
+bool FunctionType::IsRequiredAt(intptr_t index) const {
+  if (index < num_fixed_parameters() + NumOptionalPositionalParameters()) {
+    return false;
+  }
   intptr_t flag_mask;
   const intptr_t flag_index = GetRequiredFlagIndex(index, &flag_mask);
   const Array& parameter_names = Array::Handle(raw_ptr()->parameter_names());
@@ -7470,7 +7479,7 @@
   return (flags & flag_mask) != 0;
 }
 
-void Function::SetIsRequiredAt(intptr_t index) const {
+void FunctionType::SetIsRequiredAt(intptr_t index) const {
   intptr_t flag_mask;
   const intptr_t flag_index = GetRequiredFlagIndex(index, &flag_mask);
   const Array& parameter_names = Array::Handle(raw_ptr()->parameter_names());
@@ -7480,9 +7489,10 @@
   parameter_names.SetAt(flag_index, Smi::Handle(Smi::New(flags | flag_mask)));
 }
 
-void Function::TruncateUnusedParameterFlags() const {
-  const Array& parameter_names = Array::Handle(raw_ptr()->parameter_names());
+void FunctionType::TruncateUnusedParameterFlags() const {
   const intptr_t num_params = NumParameters();
+  if (num_params == 0) return;
+  const Array& parameter_names = Array::Handle(raw_ptr()->parameter_names());
   if (parameter_names.Length() == num_params) {
     // No flag slots to truncate.
     return;
@@ -7497,47 +7507,85 @@
   parameter_names.Truncate(last_used + 1);
 }
 
-void Function::set_type_parameters(const TypeArguments& value) const {
+void FunctionType::FinalizeNameArrays(const Function& function) const {
+  TruncateUnusedParameterFlags();
+  if (!function.IsNull()) {
+    function.SetParameterNamesFrom(*this);
+    // Unless the function is a dispatcher, its number of type parameters
+    // must match the number of type parameters in its signature.
+    ASSERT(function.kind() == FunctionLayout::kNoSuchMethodDispatcher ||
+           function.kind() == FunctionLayout::kInvokeFieldDispatcher ||
+           function.kind() == FunctionLayout::kDynamicInvocationForwarder ||
+           function.NumTypeParameters() == NumTypeParameters());
+  }
+}
+
+void FunctionType::set_type_parameters(const TypeArguments& value) const {
   raw_ptr()->set_type_parameters(value.raw());
 }
 
-intptr_t Function::NumTypeParameters(Thread* thread) const {
+static void ReportTooManyTypeParameters(const Function& function) {
+  Report::MessageF(Report::kError, Script::Handle(), TokenPosition::kNoSource,
+                   Report::AtLocation,
+                   "too many type parameters declared in function '%s'",
+                   function.UserVisibleNameCString());
+  UNREACHABLE();
+}
+
+static void ReportTooManyTypeParameters(const FunctionType& sig) {
+  Report::MessageF(Report::kError, Script::Handle(), TokenPosition::kNoSource,
+                   Report::AtLocation,
+                   "too many type parameters declared in signature '%s' or in "
+                   "its enclosing signatures",
+                   sig.ToUserVisibleCString());
+  UNREACHABLE();
+}
+
+void FunctionType::SetNumParentTypeArguments(intptr_t value) const {
+  ASSERT(value >= 0);
+  if (!Utils::IsUint(FunctionTypeLayout::kMaxParentTypeArgumentsBits, value)) {
+    ReportTooManyTypeParameters(*this);
+  }
+  const uint32_t* original = &raw_ptr()->packed_fields_;
+  StoreNonPointer(original,
+                  FunctionTypeLayout::PackedNumParentTypeArguments::update(
+                      value, *original));
+}
+
+void Function::SetNumTypeParameters(intptr_t value) const {
+  ASSERT(value >= 0);
+  if (!Utils::IsUint(FunctionLayout::kMaxTypeParametersBits, value)) {
+    ReportTooManyTypeParameters(*this);
+  }
+  const uint32_t* original = &raw_ptr()->packed_fields_;
+  StoreNonPointer(original, FunctionLayout::PackedNumTypeParameters::update(
+                                value, *original));
+}
+
+intptr_t FunctionType::NumTypeParameters(Thread* thread) const {
   if (type_parameters() == TypeArguments::null()) {
     return 0;
   }
   REUSABLE_TYPE_ARGUMENTS_HANDLESCOPE(thread);
   TypeArguments& type_params = thread->TypeArgumentsHandle();
   type_params = type_parameters();
-  // We require null to represent a non-generic function.
+  // We require null to represent a non-generic signature.
   ASSERT(type_params.Length() != 0);
   return type_params.Length();
 }
 
-intptr_t Function::NumParentTypeParameters() const {
+intptr_t Function::NumParentTypeArguments() const {
   if (IsImplicitClosureFunction()) {
     return 0;
   }
-  Thread* thread = Thread::Current();
   Function& parent = Function::Handle(parent_function());
-  intptr_t num_parent_type_params = 0;
+  intptr_t num_parent_type_args = 0;
   while (!parent.IsNull()) {
-    num_parent_type_params += parent.NumTypeParameters(thread);
+    num_parent_type_args += parent.NumTypeParameters();
     if (parent.IsImplicitClosureFunction()) break;
     parent = parent.parent_function();
   }
-  return num_parent_type_params;
-}
-
-void Function::PrintSignatureTypes() const {
-  Function& sig_fun = Function::Handle(raw());
-  Type& sig_type = Type::Handle();
-  while (!sig_fun.IsNull()) {
-    sig_type = sig_fun.SignatureType();
-    THR_Print("%s%s\n",
-              sig_fun.IsImplicitClosureFunction() ? "implicit closure: " : "",
-              sig_type.ToCString());
-    sig_fun = sig_fun.parent_function();
-  }
+  return num_parent_type_args;
 }
 
 TypeParameterPtr Function::LookupTypeParameter(const String& type_name,
@@ -7555,14 +7603,16 @@
 
   function = this->raw();
   while (!function.IsNull()) {
-    type_params = function.type_parameters();
-    if (!type_params.IsNull()) {
-      const intptr_t num_type_params = type_params.Length();
-      for (intptr_t i = 0; i < num_type_params; i++) {
-        type_param ^= type_params.TypeAt(i);
-        type_param_name = type_param.name();
-        if (type_param_name.Equals(type_name)) {
-          return type_param.raw();
+    if (function.signature() != FunctionType::null()) {
+      type_params = function.type_parameters();
+      if (!type_params.IsNull()) {
+        const intptr_t num_type_params = type_params.Length();
+        for (intptr_t i = 0; i < num_type_params; i++) {
+          type_param ^= type_params.TypeAt(i);
+          type_param_name = type_param.name();
+          if (type_param_name.Equals(type_name)) {
+            return type_param.raw();
+          }
         }
       }
     }
@@ -7610,25 +7660,6 @@
   StoreNonPointer(&raw_ptr()->packed_fields_, packed_fields);
 }
 
-void Function::set_num_fixed_parameters(intptr_t value) const {
-  ASSERT(value >= 0);
-  ASSERT(Utils::IsUint(FunctionLayout::kMaxFixedParametersBits, value));
-  const uint32_t* original = &raw_ptr()->packed_fields_;
-  StoreNonPointer(original, FunctionLayout::PackedNumFixedParameters::update(
-                                value, *original));
-}
-
-void Function::SetNumOptionalParameters(intptr_t value,
-                                        bool are_optional_positional) const {
-  ASSERT(Utils::IsUint(FunctionLayout::kMaxOptionalParametersBits, value));
-  uint32_t packed_fields = raw_ptr()->packed_fields_;
-  packed_fields = FunctionLayout::PackedHasNamedOptionalParameters::update(
-      !are_optional_positional, packed_fields);
-  packed_fields =
-      FunctionLayout::PackedNumOptionalParameters::update(value, packed_fields);
-  set_packed_fields(packed_fields);
-}
-
 bool Function::IsOptimizable() const {
   if (FLAG_precompiled_mode) {
     return true;
@@ -7698,7 +7729,6 @@
   }
   if ((k == FunctionLayout::kClosureFunction) ||
       (k == FunctionLayout::kImplicitClosureFunction) ||
-      (k == FunctionLayout::kSignatureFunction) ||
       (k == FunctionLayout::kFfiTrampoline)) {
     return 1;  // Closure object.
   }
@@ -7707,8 +7737,7 @@
     // marked as non-static, but they do not have a receiver.
     // Closures are handled above.
     ASSERT((k != FunctionLayout::kClosureFunction) &&
-           (k != FunctionLayout::kImplicitClosureFunction) &&
-           (k != FunctionLayout::kSignatureFunction));
+           (k != FunctionLayout::kImplicitClosureFunction));
     return 1;  // Receiver.
   }
   return 0;  // No implicit parameters.
@@ -7887,8 +7916,8 @@
     const ArgumentsDescriptor& args_desc) {
   ASSERT(!function.IsNull());
 
-  const intptr_t kNumCurrentTypeArgs = function.NumTypeParameters(thread);
-  const intptr_t kNumParentTypeArgs = function.NumParentTypeParameters();
+  const intptr_t kNumCurrentTypeArgs = function.NumTypeParameters();
+  const intptr_t kNumParentTypeArgs = function.NumParentTypeArguments();
   const intptr_t kNumTypeArgs = kNumCurrentTypeArgs + kNumParentTypeArgs;
   // Non-generic functions don't receive type arguments.
   if (kNumTypeArgs == 0) return Object::empty_type_arguments().raw();
@@ -7977,6 +8006,12 @@
 ObjectPtr Function::DoArgumentTypesMatch(
     const Array& args,
     const ArgumentsDescriptor& args_desc) const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  if (signature() == FunctionType::null()) {
+    // Precompiler deleted signature because of missing entry point pragma.
+    return EntryPointMemberInvocationError(*this);
+  }
+#endif
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
 
@@ -7994,6 +8029,12 @@
     const Array& args,
     const ArgumentsDescriptor& args_desc,
     const TypeArguments& instantiator_type_arguments) const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  if (signature() == FunctionType::null()) {
+    // Precompiler deleted signature because of missing entry point pragma.
+    return EntryPointMemberInvocationError(*this);
+  }
+#endif
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
 
@@ -8016,15 +8057,22 @@
     const ArgumentsDescriptor& args_desc,
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments) const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  if (signature() == FunctionType::null()) {
+    // Precompiler deleted signature because of missing entry point pragma.
+    return EntryPointMemberInvocationError(*this);
+  }
+#endif
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
 
   // Perform any non-covariant bounds checks on the provided function type
   // arguments to make sure they are appropriate subtypes of the bounds.
-  const intptr_t kNumLocalTypeArgs = NumTypeParameters(thread);
+  const intptr_t kNumLocalTypeArgs = NumTypeParameters();
   if (kNumLocalTypeArgs > 0) {
-    ASSERT(function_type_arguments.HasCount(kNumLocalTypeArgs +
-                                            NumParentTypeParameters()));
+    const intptr_t kNumParentTypeArgs = NumParentTypeArguments();
+    ASSERT(function_type_arguments.HasCount(kNumParentTypeArgs +
+                                            kNumLocalTypeArgs));
     const auto& params = TypeArguments::Handle(zone, type_parameters());
     auto& parameter = TypeParameter::Handle(zone);
     auto& type = AbstractType::Handle(zone);
@@ -8045,7 +8093,7 @@
       }
     }
   } else {
-    ASSERT(function_type_arguments.HasCount(NumParentTypeParameters()));
+    ASSERT(function_type_arguments.HasCount(NumParentTypeArguments()));
   }
 
   AbstractType& type = AbstractType::Handle(zone);
@@ -8218,46 +8266,39 @@
   return chars;
 }
 
-FunctionPtr Function::InstantiateSignatureFrom(
+AbstractTypePtr FunctionType::InstantiateFrom(
     const TypeArguments& instantiator_type_arguments,
     const TypeArguments& function_type_arguments,
     intptr_t num_free_fun_type_params,
-    Heap::Space space) const {
+    Heap::Space space,
+    TrailPtr trail) const {
+  ASSERT(IsFinalized() || IsBeingFinalized());
+  // A FunctionType cannot be part of a cycle (self-referencing typedefs are not
+  // allowed), therefore, the passed in trail does not need to be propagated to
+  // calls instantiating types of the signature.
   Zone* zone = Thread::Current()->zone();
-  const Object& owner = Object::Handle(zone, RawOwner());
-  // Note that parent pointers in newly instantiated signatures still points to
-  // the original uninstantiated parent signatures. That is not a problem.
-  const Function& parent = Function::Handle(zone, parent_function());
-  const intptr_t num_parent_type_params = NumParentTypeParameters();
-
   // See the comment on kCurrentAndEnclosingFree to understand why we don't
   // adjust 'num_free_fun_type_params' downward in this case.
+  const intptr_t num_parent_type_args = NumParentTypeArguments();
   bool delete_type_parameters = false;
   if (num_free_fun_type_params == kCurrentAndEnclosingFree) {
     num_free_fun_type_params = kAllFree;
     delete_type_parameters = true;
   } else {
-    ASSERT(!HasInstantiatedSignature(kAny, num_free_fun_type_params));
-
-    // A generic typedef may declare a non-generic function type and get
-    // instantiated with unrelated function type parameters. In that case, its
-    // signature is still uninstantiated, because these type parameters are
-    // free (they are not declared by the typedef).
-    // For that reason, we only adjust num_free_fun_type_params if this
-    // signature is generic or has a generic parent.
+    ASSERT(!IsInstantiated(kAny, num_free_fun_type_params));
     if (IsGeneric() || HasGenericParent()) {
       // We only consider the function type parameters declared by the parents
       // of this signature function as free.
-      if (num_parent_type_params < num_free_fun_type_params) {
-        num_free_fun_type_params = num_parent_type_params;
+      if (num_parent_type_args < num_free_fun_type_params) {
+        num_free_fun_type_params = num_parent_type_args;
       }
     }
   }
 
-  Function& sig = Function::Handle(Function::NewSignatureFunction(
-      owner, parent, TokenPosition::kNoSource, space));
-  const intptr_t offset =
-      sig.NumParentTypeParameters() - num_parent_type_params;
+  // TODO(regis): Is this correct to use num_parent_type_args here?
+  // Or should it be 0 after instantiation?
+  FunctionType& sig = FunctionType::Handle(
+      FunctionType::New(num_parent_type_args, nullability(), space));
   AbstractType& type = AbstractType::Handle(zone);
 
   // Copy the type parameters and instantiate their bounds (if necessary).
@@ -8267,11 +8308,10 @@
     if (!type_params.IsNull()) {
       TypeArguments& instantiated_type_params = TypeArguments::Handle(zone);
       TypeParameter& type_param = TypeParameter::Handle(zone);
-      const Class& null_class = Class::Handle(zone);
       String& param_name = String::Handle(zone);
       for (intptr_t i = 0; i < type_params.Length(); ++i) {
         type_param ^= type_params.TypeAt(i);
-        ASSERT(type_param.index() == num_parent_type_params + i);
+        ASSERT(type_param.index() == num_parent_type_args + i);
         type = type_param.bound();
         if (!type.IsInstantiated(kAny, num_free_fun_type_params)) {
           type = type.InstantiateFrom(instantiator_type_arguments,
@@ -8280,21 +8320,15 @@
           // A returned null type indicates a failed instantiation in dead code
           // that must be propagated up to the caller, the optimizing compiler.
           if (type.IsNull()) {
-            return Function::null();
+            return FunctionType::null();
           }
-        }
-        if (offset > 0 || type.raw() != type_param.bound()) {
-          param_name = type_param.name();
-          ASSERT(type_param.IsFunctionTypeParameter());
           ASSERT(type_param.IsFinalized());
-          ASSERT(type_param.IsCanonical());
+          param_name = type_param.name();
           type_param = TypeParameter::New(
-              null_class, sig, type_param.index() + offset, param_name, type,
-              type_param.IsGenericCovariantImpl(), type_param.nullability(),
-              type_param.token_pos());
+              Object::null_class(), type_param.base(), type_param.index(),
+              param_name, type, type_param.IsGenericCovariantImpl(),
+              type_param.nullability());
           type_param.SetIsFinalized();
-          type_param.SetCanonical();
-          type_param.SetDeclaration(true);
           if (instantiated_type_params.IsNull()) {
             instantiated_type_params = TypeArguments::New(type_params.Length());
             for (intptr_t j = 0; j < i; ++j) {
@@ -8321,11 +8355,12 @@
     // A returned null type indicates a failed instantiation in dead code that
     // must be propagated up to the caller, the optimizing compiler.
     if (type.IsNull()) {
-      return Function::null();
+      return FunctionType::null();
     }
   }
   sig.set_result_type(type);
   const intptr_t num_params = NumParameters();
+  sig.set_num_implicit_parameters(num_implicit_parameters());
   sig.set_num_fixed_parameters(num_fixed_parameters());
   sig.SetNumOptionalParameters(NumOptionalParameters(),
                                HasOptionalPositionalParameters());
@@ -8339,7 +8374,7 @@
       // A returned null type indicates a failed instantiation in dead code that
       // must be propagated up to the caller, the optimizing compiler.
       if (type.IsNull()) {
-        return Function::null();
+        return FunctionType::null();
       }
     }
     sig.SetParameterTypeAt(i, type);
@@ -8347,19 +8382,29 @@
   sig.set_parameter_names(Array::Handle(zone, parameter_names()));
 
   if (delete_type_parameters) {
-    ASSERT(sig.HasInstantiatedSignature(kFunctions));
+    ASSERT(sig.IsInstantiated(kFunctions));
   }
+
+  if (IsFinalized()) {
+    sig.SetIsFinalized();
+  } else {
+    if (IsBeingFinalized()) {
+      sig.SetIsBeingFinalized();
+    }
+  }
+
+  // Canonicalization is not part of instantiation.
   return sig.raw();
 }
 
-// Checks if the type of the specified parameter of this function is a supertype
-// of the type of the specified parameter of the other function (i.e. check
-// parameter contravariance).
+// Checks if the type of the specified parameter of this signature is a
+// supertype of the type of the specified parameter of the other signature
+// (i.e. check parameter contravariance).
 // Note that types marked as covariant are already dealt with in the front-end.
-bool Function::IsContravariantParameter(intptr_t parameter_position,
-                                        const Function& other,
-                                        intptr_t other_parameter_position,
-                                        Heap::Space space) const {
+bool FunctionType::IsContravariantParameter(intptr_t parameter_position,
+                                            const FunctionType& other,
+                                            intptr_t other_parameter_position,
+                                            Heap::Space space) const {
   const AbstractType& param_type =
       AbstractType::Handle(ParameterTypeAt(parameter_position));
   if (param_type.IsTopTypeForSubtyping()) {
@@ -8370,8 +8415,8 @@
   return other_param_type.IsSubtypeOf(param_type, space);
 }
 
-bool Function::HasSameTypeParametersAndBounds(const Function& other,
-                                              TypeEquality kind) const {
+bool FunctionType::HasSameTypeParametersAndBounds(const FunctionType& other,
+                                                  TypeEquality kind) const {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
 
@@ -8388,32 +8433,19 @@
     ASSERT(!other_type_params.IsNull());
     TypeParameter& type_param = TypeParameter::Handle(zone);
     TypeParameter& other_type_param = TypeParameter::Handle(zone);
-    AbstractType& bound = AbstractType::Handle(zone);
-    AbstractType& other_bound = AbstractType::Handle(zone);
     for (intptr_t i = 0; i < num_type_params; i++) {
       type_param ^= type_params.TypeAt(i);
       other_type_param ^= other_type_params.TypeAt(i);
-      bound = type_param.bound();
-      ASSERT(bound.IsFinalized());
-      other_bound = other_type_param.bound();
-      ASSERT(other_bound.IsFinalized());
-      if (kind == TypeEquality::kInSubtypeTest) {
-        // Bounds that are mutual subtypes are considered equal.
-        if (!bound.IsSubtypeOf(other_bound, Heap::kOld) ||
-            !other_bound.IsSubtypeOf(bound, Heap::kOld)) {
-          return false;
-        }
-      } else {
-        if (!bound.IsEquivalent(other_bound, kind)) {
-          return false;
-        }
+      if (!type_param.IsEquivalent(other_type_param, kind)) {
+        return false;
       }
     }
   }
   return true;
 }
 
-bool Function::IsSubtypeOf(const Function& other, Heap::Space space) const {
+bool FunctionType::IsSubtypeOf(const FunctionType& other,
+                               Heap::Space space) const {
   const intptr_t num_fixed_params = num_fixed_parameters();
   const intptr_t num_opt_pos_params = NumOptionalPositionalParameters();
   const intptr_t num_opt_named_params = NumOptionalNamedParameters();
@@ -8422,10 +8454,10 @@
       other.NumOptionalPositionalParameters();
   const intptr_t other_num_opt_named_params =
       other.NumOptionalNamedParameters();
-  // This function requires the same arguments or less and accepts the same
+  // This signature requires the same arguments or less and accepts the same
   // arguments or more. We can ignore implicit parameters.
-  const intptr_t num_ignored_params = NumImplicitParameters();
-  const intptr_t other_num_ignored_params = other.NumImplicitParameters();
+  const intptr_t num_ignored_params = num_implicit_parameters();
+  const intptr_t other_num_ignored_params = other.num_implicit_parameters();
   if (((num_fixed_params - num_ignored_params) >
        (other_num_fixed_params - other_num_ignored_params)) ||
       ((num_fixed_params - num_ignored_params + num_opt_pos_params) <
@@ -8537,7 +8569,8 @@
   return static_cast<FunctionPtr>(raw);
 }
 
-FunctionPtr Function::New(const String& name,
+FunctionPtr Function::New(const FunctionType& signature,
+                          const String& name,
                           FunctionLayout::Kind kind,
                           bool is_static,
                           bool is_const,
@@ -8547,11 +8580,10 @@
                           const Object& owner,
                           TokenPosition token_pos,
                           Heap::Space space) {
-  ASSERT(!owner.IsNull() || (kind == FunctionLayout::kSignatureFunction));
+  ASSERT(!owner.IsNull());
   const Function& result = Function::Handle(Function::New(space));
   result.set_kind_tag(0);
-  result.set_parameter_types(Object::empty_array());
-  result.set_parameter_names(Object::empty_array());
+  result.set_packed_fields(0);
   result.set_name(name);
   result.set_kind_tag(0);  // Ensure determinism of uninitialized bits.
   result.set_kind(kind);
@@ -8574,8 +8606,6 @@
   result.set_owner(owner);
   NOT_IN_PRECOMPILED(result.set_token_pos(token_pos));
   NOT_IN_PRECOMPILED(result.set_end_token_pos(token_pos));
-  result.set_num_fixed_parameters(0);
-  result.SetNumOptionalParameters(0, false);
   NOT_IN_PRECOMPILED(result.set_usage_counter(0));
   NOT_IN_PRECOMPILED(result.set_deoptimization_counter(0));
   NOT_IN_PRECOMPILED(result.set_optimized_instruction_count(0));
@@ -8592,10 +8622,6 @@
     ASSERT(space == Heap::kOld);
     const ClosureData& data = ClosureData::Handle(ClosureData::New());
     result.set_data(data);
-  } else if (kind == FunctionLayout::kSignatureFunction) {
-    const SignatureData& data =
-        SignatureData::Handle(SignatureData::New(space));
-    result.set_data(data);
   } else if (kind == FunctionLayout::kFfiTrampoline) {
     const FfiTrampolineData& data =
         FfiTrampolineData::Handle(FfiTrampolineData::New());
@@ -8616,7 +8642,12 @@
   if (result.ForceOptimize()) {
     result.set_is_debuggable(false);
   }
-
+  if (!signature.IsNull()) {
+    signature.set_num_implicit_parameters(result.NumImplicitParameters());
+    result.set_signature(signature);
+  } else {
+    ASSERT(kind == FunctionLayout::kFfiTrampoline);
+  }
   return result.raw();
 }
 
@@ -8629,8 +8660,11 @@
          (kind == FunctionLayout::kImplicitClosureFunction));
   ASSERT(!parent.IsNull());
   ASSERT(!owner.IsNull());
+  const FunctionType& signature = FunctionType::Handle(FunctionType::New(
+      kind == FunctionLayout::kClosureFunction ? parent.NumTypeArguments()
+                                               : 0));
   const Function& result = Function::Handle(
-      Function::New(name, kind,
+      Function::New(signature, name, kind,
                     /* is_static = */ parent.is_static(),
                     /* is_const = */ false,
                     /* is_abstract = */ false,
@@ -8658,46 +8692,6 @@
                                     name, parent, token_pos, parent_owner);
 }
 
-FunctionPtr Function::NewSignatureFunction(const Object& owner,
-                                           const Function& parent,
-                                           TokenPosition token_pos,
-                                           Heap::Space space) {
-  const Function& result = Function::Handle(Function::New(
-      Symbols::AnonymousSignature(), FunctionLayout::kSignatureFunction,
-      /* is_static = */ false,
-      /* is_const = */ false,
-      /* is_abstract = */ false,
-      /* is_external = */ false,
-      /* is_native = */ false,
-      owner,  // Same as function type scope class.
-      token_pos, space));
-  result.set_parent_function(parent);
-  result.set_is_reflectable(false);
-  result.set_is_visible(false);
-  result.set_is_debuggable(false);
-  return result.raw();
-}
-
-FunctionPtr Function::NewEvalFunction(const Class& owner,
-                                      const Script& script,
-                                      bool is_static) {
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
-  const Function& result = Function::Handle(
-      zone,
-      Function::New(String::Handle(Symbols::New(thread, ":Eval")),
-                    FunctionLayout::kRegularFunction, is_static,
-                    /* is_const = */ false,
-                    /* is_abstract = */ false,
-                    /* is_external = */ false,
-                    /* is_native = */ false, owner, TokenPosition::kMinSource));
-  ASSERT(!script.IsNull());
-  result.set_is_debuggable(false);
-  result.set_is_visible(true);
-  result.set_eval_script(script);
-  return result.raw();
-}
-
 bool Function::SafeToClosurize() const {
 #if defined(DART_PRECOMPILED_RUNTIME)
   return HasImplicitClosureFunction();
@@ -8726,8 +8720,7 @@
   FATAL("Cannot create implicit closure in AOT!");
   return Function::null();
 #else
-  ASSERT(!IsSignatureFunction() && !IsClosureFunction());
-
+  ASSERT(!IsClosureFunction());
   Thread* thread = Thread::Current();
   SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
 
@@ -8750,16 +8743,20 @@
     closure_function.set_context_scope(context_scope);
   }
 
+  FunctionType& closure_signature =
+      FunctionType::Handle(zone, closure_function.signature());
+
   // Set closure function's type parameters.
-  auto& type_args_handle = TypeArguments::Handle(zone, type_parameters());
   // This function cannot be local, therefore it has no generic parent.
   // Its implicit closure function therefore has no generic parent function
   // either. That is why it is safe to simply copy the type parameters.
-  closure_function.set_type_parameters(type_args_handle);
+  closure_signature.set_type_parameters(
+      TypeArguments::Handle(zone, type_parameters()));
+  closure_function.SetNumTypeParameters(NumTypeParameters());
   closure_function.UpdateCachedDefaultTypeArguments(thread);
 
   // Set closure function's result type to this result type.
-  closure_function.set_result_type(AbstractType::Handle(zone, result_type()));
+  closure_signature.set_result_type(AbstractType::Handle(zone, result_type()));
 
   // Set closure function's end token to this end token.
   closure_function.set_end_token_pos(end_token_pos());
@@ -8780,25 +8777,25 @@
   const int num_params = num_fixed_params + num_opt_params;
   closure_function.set_num_fixed_parameters(num_fixed_params);
   closure_function.SetNumOptionalParameters(num_opt_params, has_opt_pos_params);
-  closure_function.set_parameter_types(
+  closure_signature.set_parameter_types(
       Array::Handle(zone, Array::New(num_params, Heap::kOld)));
-  closure_function.CreateNameArrayIncludingFlags(Heap::kOld);
+  closure_signature.CreateNameArrayIncludingFlags(Heap::kOld);
   AbstractType& param_type = AbstractType::Handle(zone);
   String& param_name = String::Handle(zone);
   // Add implicit closure object parameter.
   param_type = Type::DynamicType();
-  closure_function.SetParameterTypeAt(0, param_type);
-  closure_function.SetParameterNameAt(0, Symbols::ClosureParameter());
+  closure_signature.SetParameterTypeAt(0, param_type);
+  closure_signature.SetParameterNameAt(0, Symbols::ClosureParameter());
   for (int i = kClosure; i < num_params; i++) {
     param_type = ParameterTypeAt(has_receiver - kClosure + i);
-    closure_function.SetParameterTypeAt(i, param_type);
+    closure_signature.SetParameterTypeAt(i, param_type);
     param_name = ParameterNameAt(has_receiver - kClosure + i);
-    closure_function.SetParameterNameAt(i, param_name);
+    closure_signature.SetParameterNameAt(i, param_name);
     if (IsRequiredAt(has_receiver - kClosure + i)) {
-      closure_function.SetIsRequiredAt(i);
+      closure_signature.SetIsRequiredAt(i);
     }
   }
-  closure_function.TruncateUnusedParameterFlags();
+  closure_signature.FinalizeNameArrays(closure_function);
   closure_function.InheritKernelOffsetFrom(*this);
 
   // Change covariant parameter types to either Object? for an opted-in implicit
@@ -8814,19 +8811,18 @@
     object_type = nnbd_mode() == NNBDMode::kOptedInLib
                       ? object_store->nullable_object_type()
                       : object_store->legacy_object_type();
+    ASSERT(object_type.IsCanonical());
     for (intptr_t i = kClosure; i < num_params; ++i) {
       const intptr_t original_param_index = has_receiver - kClosure + i;
       if (is_covariant.Contains(original_param_index) ||
           is_generic_covariant_impl.Contains(original_param_index)) {
-        closure_function.SetParameterTypeAt(i, object_type);
+        closure_signature.SetParameterTypeAt(i, object_type);
       }
     }
   }
-  const Type& signature_type =
-      Type::Handle(zone, closure_function.SignatureType());
-  if (!signature_type.IsFinalized()) {
-    ClassFinalizer::FinalizeType(signature_type);
-  }
+  ASSERT(!closure_signature.IsFinalized());
+  closure_signature ^= ClassFinalizer::FinalizeType(closure_signature);
+  closure_function.set_signature(closure_signature);
   set_implicit_closure_function(closure_function);
   ASSERT(closure_function.IsImplicitClosureFunction());
   return closure_function.raw();
@@ -8842,24 +8838,26 @@
   }
 }
 
-StringPtr Function::Signature() const {
+StringPtr Function::InternalSignature() const {
   Thread* thread = Thread::Current();
   ZoneTextBuffer printer(thread->zone());
-  PrintSignature(kInternalName, &printer);
+  const FunctionType& sig = FunctionType::Handle(signature());
+  sig.Print(kInternalName, &printer);
   return Symbols::New(thread, printer.buffer());
 }
 
 StringPtr Function::UserVisibleSignature() const {
   Thread* thread = Thread::Current();
   ZoneTextBuffer printer(thread->zone());
-  PrintSignature(kUserVisibleName, &printer);
+  const FunctionType& sig = FunctionType::Handle(signature());
+  sig.Print(kUserVisibleName, &printer);
   return Symbols::New(thread, printer.buffer());
 }
 
-void Function::PrintSignatureParameters(Thread* thread,
-                                        Zone* zone,
-                                        NameVisibility name_visibility,
-                                        BaseTextBuffer* printer) const {
+void FunctionType::PrintParameters(Thread* thread,
+                                   Zone* zone,
+                                   NameVisibility name_visibility,
+                                   BaseTextBuffer* printer) const {
   AbstractType& param_type = AbstractType::Handle(zone);
   const intptr_t num_params = NumParameters();
   const intptr_t num_fixed_params = num_fixed_parameters();
@@ -8870,7 +8868,7 @@
   intptr_t i = 0;
   if (name_visibility == kUserVisibleName) {
     // Hide implicit parameters.
-    i = NumImplicitParameters();
+    i = num_implicit_parameters();
   }
   String& name = String::Handle(zone);
   while (i < num_fixed_params) {
@@ -8976,23 +8974,27 @@
   ASSERT(IsClosureFunction());
   const Class& cls = Class::Handle(Owner());
   uintptr_t result = String::Handle(name()).Hash();
-  result += String::Handle(Signature()).Hash();
+  result += String::Handle(InternalSignature()).Hash();
   result += String::Handle(cls.Name()).Hash();
   return result;
 }
 
-void Function::PrintSignature(NameVisibility name_visibility,
-                              BaseTextBuffer* printer) const {
+void FunctionType::Print(NameVisibility name_visibility,
+                         BaseTextBuffer* printer) const {
+  if (IsNull()) {
+    printer->AddString("null");  // Signature optimized out in precompiler.
+    return;
+  }
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   auto isolate_group = thread->isolate_group();
-  String& name = String::Handle(zone);
   const TypeArguments& type_params =
       TypeArguments::Handle(zone, type_parameters());
   if (!type_params.IsNull()) {
     const intptr_t num_type_params = type_params.Length();
     ASSERT(num_type_params > 0);
     TypeParameter& type_param = TypeParameter::Handle(zone);
+    String& name = String::Handle(zone);
     AbstractType& bound = AbstractType::Handle(zone);
     printer->AddString("<");
     for (intptr_t i = 0; i < num_type_params; i++) {
@@ -9006,6 +9008,13 @@
            (isolate_group->null_safety() && bound.IsNonNullable()))) {
         printer->AddString(" extends ");
         bound.PrintName(name_visibility, printer);
+        if (FLAG_show_internal_names) {
+          bound = type_param.default_argument();
+          if (!bound.IsNull() && !bound.IsDynamicType()) {
+            printer->AddString(" defaults to ");
+            bound.PrintName(name_visibility, printer);
+          }
+        }
       }
       if (i < num_type_params - 1) {
         printer->AddString(", ");
@@ -9014,7 +9023,7 @@
     printer->AddString(">");
   }
   printer->AddString("(");
-  PrintSignatureParameters(thread, zone, name_visibility, printer);
+  PrintParameters(thread, zone, name_visibility, printer);
   printer->AddString(") => ");
   const AbstractType& res_type = AbstractType::Handle(zone, result_type());
   res_type.PrintName(name_visibility, printer);
@@ -9023,21 +9032,22 @@
 bool Function::HasInstantiatedSignature(Genericity genericity,
                                         intptr_t num_free_fun_type_params,
                                         TrailPtr trail) const {
+  return FunctionType::Handle(signature())
+      .IsInstantiated(genericity, num_free_fun_type_params, trail);
+}
+
+bool FunctionType::IsInstantiated(Genericity genericity,
+                                  intptr_t num_free_fun_type_params,
+                                  TrailPtr trail) const {
   if (num_free_fun_type_params == kCurrentAndEnclosingFree) {
     num_free_fun_type_params = kAllFree;
   } else if (genericity != kCurrentClass) {
-    // A generic typedef may declare a non-generic function type and get
-    // instantiated with unrelated function type parameters. In that case, its
-    // signature is still uninstantiated, because these type parameters are
-    // free (they are not declared by the typedef).
-    // For that reason, we only adjust num_free_fun_type_params if this
-    // signature is generic or has a generic parent.
     if (IsGeneric() || HasGenericParent()) {
       // We only consider the function type parameters declared by the parents
       // of this signature function as free.
-      const int num_parent_type_params = NumParentTypeParameters();
-      if (num_parent_type_params < num_free_fun_type_params) {
-        num_free_fun_type_params = num_parent_type_params;
+      const int num_parent_type_args = NumParentTypeArguments();
+      if (num_parent_type_args < num_free_fun_type_params) {
+        num_free_fun_type_params = num_parent_type_args;
       }
     }
   }
@@ -9065,10 +9075,7 @@
 }
 
 ClassPtr Function::Owner() const {
-  if (raw_ptr()->owner() == Object::null()) {
-    ASSERT(IsSignatureFunction());
-    return Class::null();
-  }
+  ASSERT(raw_ptr()->owner() != Object::null());
   if (raw_ptr()->owner()->IsClass()) {
     return Class::RawCast(raw_ptr()->owner());
   }
@@ -9078,10 +9085,7 @@
 }
 
 ClassPtr Function::origin() const {
-  if (raw_ptr()->owner() == Object::null()) {
-    ASSERT(IsSignatureFunction());
-    return Class::null();
-  }
+  ASSERT(raw_ptr()->owner() != Object::null());
   if (raw_ptr()->owner()->IsClass()) {
     return Class::RawCast(raw_ptr()->owner());
   }
@@ -9149,10 +9153,6 @@
   if (IsClosureFunction()) {
     return Function::Handle(parent_function()).script();
   }
-  if (obj.IsNull()) {
-    ASSERT(IsSignatureFunction());
-    return Script::null();
-  }
   ASSERT(obj.IsClass());
   return Class::Cast(obj).script();
 }
@@ -9352,7 +9352,7 @@
     if (fun.NumOptionalPositionalParameters() != 0) {
       printer->Printf(" [%" Pd "]", fun.NumOptionalPositionalParameters());
     }
-    if (fun.NumOptionalNamedParameters() != 0) {
+    if (fun.HasOptionalNamedParameters()) {
       printer->AddString(" {");
       String& name = String::Handle();
       for (intptr_t i = 0; i < fun.NumOptionalNamedParameters(); i++) {
@@ -9366,7 +9366,7 @@
 }
 
 StringPtr Function::GetSource() const {
-  if (IsImplicitConstructor() || IsSignatureFunction() || is_synthetic()) {
+  if (IsImplicitConstructor() || is_synthetic()) {
     // We may need to handle more cases when the restrictions on mixins are
     // relaxed. In particular we might start associating some source with the
     // forwarding constructors when it becomes possible to specify a particular
@@ -9705,9 +9705,6 @@
     case FunctionLayout::kGetterFunction:
     case FunctionLayout::kSetterFunction:
       break;
-    case FunctionLayout::kSignatureFunction:
-      buffer.AddString(" signature");
-      break;
     case FunctionLayout::kConstructor:
       buffer.AddString(is_static() ? " factory" : " constructor");
       break;
@@ -9758,22 +9755,21 @@
   return buffer.buffer();
 }
 
-void ClosureData::set_context_scope(const ContextScope& value) const {
-  raw_ptr()->set_context_scope(value.raw());
+void FunctionType::set_packed_fields(uint32_t packed_fields) const {
+  StoreNonPointer(&raw_ptr()->packed_fields_, packed_fields);
 }
 
-void ClosureData::set_implicit_static_closure(const Instance& closure) const {
-  ASSERT(!closure.IsNull());
-  ASSERT(raw_ptr()->closure() == Instance::null());
-  raw_ptr()->set_closure(closure.raw());
+intptr_t FunctionType::NumParameters() const {
+  return num_fixed_parameters() + NumOptionalParameters();
 }
 
-void ClosureData::set_parent_function(const Function& value) const {
-  raw_ptr()->set_parent_function(value.raw());
-}
-
-void ClosureData::set_signature_type(const Type& value) const {
-  raw_ptr()->set_signature_type(value.raw());
+void FunctionType::set_num_implicit_parameters(intptr_t value) const {
+  ASSERT(value >= 0);
+  ASSERT(Utils::IsUint(FunctionTypeLayout::kMaxImplicitParametersBits, value));
+  const uint32_t* original = &raw_ptr()->packed_fields_;
+  StoreNonPointer(original,
+                  FunctionTypeLayout::PackedNumImplicitParameters::update(
+                      value, *original));
 }
 
 void ClosureData::set_default_type_arguments(const TypeArguments& value) const {
@@ -9817,12 +9813,6 @@
   } else {
     buffer.AddString(Function::Handle(zone, parent_function()).ToCString());
   }
-  buffer.AddString(" signature_type: ");
-  if (signature_type() == Type::null()) {
-    buffer.AddString("null");
-  } else {
-    buffer.AddString(Type::Handle(zone, signature_type()).ToCString());
-  }
   buffer.Printf(" implicit_static_closure: 0x%" Px "",
                 static_cast<uword>(implicit_static_closure()));
   buffer.AddString(" default_type_arguments: ");
@@ -9835,45 +9825,136 @@
   return buffer.buffer();
 }
 
-void SignatureData::set_parent_function(const Function& value) const {
-  raw_ptr()->set_parent_function(value.raw());
+void Function::set_num_fixed_parameters(intptr_t value) const {
+  ASSERT(value >= 0);
+  ASSERT(Utils::IsUint(FunctionLayout::kMaxFixedParametersBits, value));
+  const uint32_t* original = &raw_ptr()->packed_fields_;
+  StoreNonPointer(original, FunctionLayout::PackedNumFixedParameters::update(
+                                value, *original));
+  // Also store in signature.
+  FunctionType::Handle(signature()).set_num_fixed_parameters(value);
 }
 
-void SignatureData::set_signature_type(const Type& value) const {
-  raw_ptr()->set_signature_type(value.raw());
+void FunctionType::set_num_fixed_parameters(intptr_t value) const {
+  ASSERT(value >= 0);
+  ASSERT(Utils::IsUint(FunctionTypeLayout::kMaxFixedParametersBits, value));
+  const uint32_t* original = &raw_ptr()->packed_fields_;
+  StoreNonPointer(
+      original,
+      FunctionTypeLayout::PackedNumFixedParameters::update(value, *original));
 }
 
-SignatureDataPtr SignatureData::New(Heap::Space space) {
-  ASSERT(Object::signature_data_class() != Class::null());
-  ObjectPtr raw = Object::Allocate(SignatureData::kClassId,
-                                   SignatureData::InstanceSize(), space);
-  return static_cast<SignatureDataPtr>(raw);
-}
-
-const char* SignatureData::ToCString() const {
-  if (IsNull()) {
-    return "SignatureData: null";
-  }
-  const Function& parent = Function::Handle(parent_function());
-  const Type& type = Type::Handle(signature_type());
-  return OS::SCreate(Thread::Current()->zone(),
-                     "SignatureData parent_function: %s signature_type: %s",
-                     parent.IsNull() ? "null" : parent.ToCString(),
-                     type.IsNull() ? "null" : type.ToCString());
-}
-
-void FfiTrampolineData::set_signature_type(const Type& value) const {
-  raw_ptr()->set_signature_type(value.raw());
-}
-
-void FfiTrampolineData::set_c_signature(const Function& value) const {
-  raw_ptr()->set_c_signature(value.raw());
+void Function::SetNumOptionalParameters(intptr_t value,
+                                        bool are_optional_positional) const {
+  ASSERT(Utils::IsUint(FunctionLayout::kMaxOptionalParametersBits, value));
+  uint32_t packed_fields = raw_ptr()->packed_fields_;
+  packed_fields = FunctionLayout::PackedHasNamedOptionalParameters::update(
+      (value > 0) && !are_optional_positional, packed_fields);
+  packed_fields =
+      FunctionLayout::PackedNumOptionalParameters::update(value, packed_fields);
+  StoreNonPointer(&raw_ptr()->packed_fields_, packed_fields);
+  // Also store in signature.
+  FunctionType::Handle(signature())
+      .SetNumOptionalParameters(value, are_optional_positional);
 }
 
 void FfiTrampolineData::set_callback_target(const Function& value) const {
   raw_ptr()->set_callback_target(value.raw());
 }
 
+void FunctionType::SetNumOptionalParameters(
+    intptr_t value,
+    bool are_optional_positional) const {
+  ASSERT(Utils::IsUint(FunctionTypeLayout::kMaxOptionalParametersBits, value));
+  uint32_t packed_fields = raw_ptr()->packed_fields_;
+  packed_fields = FunctionTypeLayout::PackedHasNamedOptionalParameters::update(
+      (value > 0) && !are_optional_positional, packed_fields);
+  packed_fields = FunctionTypeLayout::PackedNumOptionalParameters::update(
+      value, packed_fields);
+  StoreNonPointer(&raw_ptr()->packed_fields_, packed_fields);
+}
+
+FunctionTypePtr FunctionType::New(Heap::Space space) {
+  ObjectPtr raw = Object::Allocate(FunctionType::kClassId,
+                                   FunctionType::InstanceSize(), space);
+  return static_cast<FunctionTypePtr>(raw);
+}
+
+FunctionTypePtr FunctionType::New(intptr_t num_parent_type_arguments,
+                                  Nullability nullability,
+                                  Heap::Space space) {
+  Zone* Z = Thread::Current()->zone();
+  const FunctionType& result =
+      FunctionType::Handle(Z, FunctionType::New(space));
+  result.set_packed_fields(0);
+  result.SetNumParentTypeArguments(num_parent_type_arguments);
+  result.set_num_fixed_parameters(0);
+  result.SetNumOptionalParameters(0, false);
+  result.set_nullability(nullability);
+  result.SetHash(0);
+  result.StoreNonPointer(&result.raw_ptr()->type_state_,
+                         TypeLayout::kAllocated);
+  result.SetTypeTestingStub(
+      Code::Handle(Z, TypeTestingStubGenerator::DefaultCodeForType(result)));
+  return result.raw();
+}
+
+void FunctionType::set_type_state(uint8_t state) const {
+  ASSERT((state >= FunctionTypeLayout::kAllocated) &&
+         (state <= FunctionTypeLayout::kFinalizedUninstantiated));
+  StoreNonPointer(&raw_ptr()->type_state_, state);
+}
+
+const char* FunctionType::ToUserVisibleCString() const {
+  Zone* zone = Thread::Current()->zone();
+  ZoneTextBuffer printer(zone);
+  Print(kUserVisibleName, &printer);
+  return printer.buffer();
+}
+
+StringPtr FunctionType::ToUserVisibleString() const {
+  Thread* thread = Thread::Current();
+  ZoneTextBuffer printer(thread->zone());
+  Print(kUserVisibleName, &printer);
+  return Symbols::New(thread, printer.buffer());
+}
+
+const char* FunctionType::ToCString() const {
+  if (IsNull()) {
+    return "FunctionType: null";
+  }
+  Zone* zone = Thread::Current()->zone();
+  ZoneTextBuffer printer(zone);
+  const char* suffix = NullabilitySuffix(kInternalName);
+  if (suffix[0] != '\0') {
+    printer.AddString("(");
+  }
+  Print(kInternalName, &printer);
+  if (suffix[0] != '\0') {
+    printer.AddString(")");
+    printer.AddString(suffix);
+  }
+  return printer.buffer();
+}
+
+void ClosureData::set_context_scope(const ContextScope& value) const {
+  raw_ptr()->set_context_scope(value.raw());
+}
+
+void ClosureData::set_implicit_static_closure(const Instance& closure) const {
+  ASSERT(!closure.IsNull());
+  ASSERT(raw_ptr()->closure() == Instance::null());
+  raw_ptr()->set_closure(closure.raw());
+}
+
+void ClosureData::set_parent_function(const Function& value) const {
+  raw_ptr()->set_parent_function(value.raw());
+}
+
+void FfiTrampolineData::set_c_signature(const FunctionType& value) const {
+  raw_ptr()->set_c_signature(value.raw());
+}
+
 void FfiTrampolineData::set_callback_id(int32_t callback_id) const {
   StoreNonPointer(&raw_ptr()->callback_id_, callback_id);
 }
@@ -9894,12 +9975,10 @@
 }
 
 const char* FfiTrampolineData::ToCString() const {
-  Type& signature_type = Type::Handle(this->signature_type());
-  String& signature_type_name =
-      String::Handle(signature_type.UserVisibleName());
-  return OS::SCreate(
-      Thread::Current()->zone(), "TrampolineData: signature=%s",
-      signature_type_name.IsNull() ? "null" : signature_type_name.ToCString());
+  const FunctionType& c_sig = FunctionType::Handle(c_signature());
+  return OS::SCreate(Thread::Current()->zone(),
+                     "TrampolineData: c_signature=%s",
+                     c_sig.ToUserVisibleCString());
 }
 
 FieldPtr Field::CloneFromOriginal() const {
@@ -16689,7 +16768,8 @@
 
 bool Code::IsTypeTestStubCode() const {
   auto const cid = OwnerClassId();
-  return cid == kAbstractTypeCid || cid == kTypeCid || cid == kTypeRefCid ||
+  return cid == kAbstractTypeCid || cid == kTypeCid ||
+         cid == kFunctionTypeCid || cid == kTypeRefCid ||
          cid == kTypeParameterCid;
 }
 
@@ -17491,11 +17571,11 @@
           zone, destination_type.InstantiateFrom(instantiator_type_arguments,
                                                  function_type_arguments,
                                                  kAllFree, Heap::kNew));
-      const auto& type_class = Class::Handle(zone, test_type.type_class());
+      const auto type_class_id = test_type.type_class_id();
       buffer->Printf("%sinstantiated type: %s", separator,
                      test_type.ToCString());
-      buffer->Printf("%sinstantiated type class id: %" Pd "", separator,
-                     type_class.id());
+      buffer->Printf("%sinstantiated type class id: %d", separator,
+                     type_class_id);
     }
   }
   if (!instance_type_arguments.IsNull()) {
@@ -18343,14 +18423,13 @@
     cls.EnsureDeclarationLoaded();
   }
   if (cls.IsClosureClass()) {
-    Function& signature = Function::Handle(
-        zone, Closure::Cast(*this).GetInstantiatedSignature(zone));
-    Type& type = Type::Handle(zone, signature.SignatureType());
-    if (!type.IsFinalized()) {
-      type.SetIsFinalized();
+    FunctionType& signature = FunctionType::Handle(
+        Closure::Cast(*this).GetInstantiatedSignature(zone));
+    if (!signature.IsFinalized()) {
+      signature.SetIsFinalized();
     }
-    type ^= type.Canonicalize(thread, nullptr);
-    return type.raw();
+    signature ^= signature.Canonicalize(thread, nullptr);
+    return signature.raw();
   }
   Type& type = Type::Handle(zone);
   if (!cls.IsGeneric()) {
@@ -18361,8 +18440,7 @@
     if (cls.NumTypeArguments() > 0) {
       type_arguments = GetTypeArguments();
     }
-    type = Type::New(cls, type_arguments, TokenPosition::kNoSource,
-                     Nullability::kNonNullable, space);
+    type = Type::New(cls, type_arguments, Nullability::kNonNullable, space);
     type.SetIsFinalized();
     type ^= type.Canonicalize(thread, nullptr);
   }
@@ -18544,11 +18622,9 @@
     if (!instantiated_other.IsFunctionType()) {
       return false;
     }
-    Function& other_signature =
-        Function::Handle(zone, Type::Cast(instantiated_other).signature());
-    const Function& sig_fun =
-        Function::Handle(Closure::Cast(*this).GetInstantiatedSignature(zone));
-    return sig_fun.IsSubtypeOf(other_signature, Heap::kOld);
+    const FunctionType& sig = FunctionType::Handle(
+        Closure::Cast(*this).GetInstantiatedSignature(zone));
+    return sig.IsSubtypeOf(FunctionType::Cast(instantiated_other), Heap::kOld);
   }
   TypeArguments& type_arguments = TypeArguments::Handle(zone);
   if (cls.NumTypeArguments() > 0) {
@@ -18577,9 +18653,6 @@
       return true;
     }
   }
-  if (!instantiated_other.IsType()) {
-    return false;
-  }
   if (IsNull()) {
     ASSERT(isolate_group->use_strict_null_safety_checks());
     if (instantiated_other.IsNullType()) {
@@ -18588,8 +18661,12 @@
     if (RuntimeTypeIsSubtypeOfFutureOr(zone, instantiated_other)) {
       return true;
     }
+    // At this point, instantiated_other can be a function type.
     return !instantiated_other.IsNonNullable();
   }
+  if (!instantiated_other.IsType()) {
+    return false;
+  }
   // RuntimeType of non-null instance is non-nullable, so there is no need to
   // check nullability of other type.
   return Class::IsSubtypeOf(cls, type_arguments, Nullability::kNonNullable,
@@ -18828,12 +18905,6 @@
   UNREACHABLE();
 }
 
-TokenPosition AbstractType::token_pos() const {
-  // AbstractType is an abstract class.
-  UNREACHABLE();
-  return TokenPosition::kNoSource;
-}
-
 Nullability AbstractType::nullability() const {
   // AbstractType is an abstract class.
   UNREACHABLE();
@@ -18893,6 +18964,9 @@
   if (IsType()) {
     return Type::Cast(*this).ToNullability(result_nullability, space);
   }
+  if (IsFunctionType()) {
+    return FunctionType::Cast(*this).ToNullability(result_nullability, space);
+  }
   if (IsTypeParameter()) {
     return TypeParameter::Cast(*this).ToNullability(result_nullability, space);
   }
@@ -18980,7 +19054,7 @@
   return false;
 }
 
-bool AbstractType::IsRecursive() const {
+bool AbstractType::IsRecursive(TrailPtr trail) const {
   // AbstractType is an abstract class.
   UNREACHABLE();
   return false;
@@ -19159,73 +19233,43 @@
   return Symbols::New(thread, printer.buffer());
 }
 
-void AbstractType::PrintName(
-    NameVisibility name_visibility,
-    BaseTextBuffer* printer,
-    NameDisambiguation name_disambiguation /* = NameDisambiguation::kNo */)
-    const {
+void AbstractType::PrintName(NameVisibility name_visibility,
+                             BaseTextBuffer* printer) const {
+  if (IsTypeRef()) {
+    // Cycles via base class type arguments are not a problem (not printed).
+    const AbstractType& ref_type =
+        AbstractType::Handle(TypeRef::Cast(*this).type());
+    ref_type.PrintName(name_visibility, printer);
+    return;
+  }
   ASSERT(name_visibility != kScrubbedName);
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   Class& cls = Class::Handle(zone);
   String& name_str = String::Handle(zone);
   if (IsTypeParameter()) {
-    const TypeParameter& param = TypeParameter::Cast(*this);
-
-    // Type parameters might have the same name but be owned by different
-    // entities. If we want to disambiguate them we need to prefix
-    // type parameter name with the name of its owner.
-    if (name_disambiguation == NameDisambiguation::kYes) {
-      cls = param.parameterized_class();
-      if (cls.raw() != Class::null()) {
-        printer->AddString(cls.NameCString(name_visibility));
-        printer->AddString("::");
-      } else if (param.parameterized_function() != Function::null()) {
-        const Function& func =
-            Function::Handle(zone, param.parameterized_function());
-        func.PrintName(
-            NameFormattingParams(name_visibility, name_disambiguation),
-            printer);
-        printer->AddString("::");
-      }
-    }
-
-    name_str = param.name();
-    printer->AddString(name_str.ToCString());
+    const TypeParameter& type_param = TypeParameter::Cast(*this);
+    printer->AddString(String::Handle(type_param.name()).ToCString());
     printer->AddString(NullabilitySuffix(name_visibility));
     return;
   }
+  if (IsFunctionType()) {
+    const char* suffix = NullabilitySuffix(name_visibility);
+    if (suffix[0] != '\0') {
+      printer->AddString("(");
+    }
+    FunctionType::Cast(*this).Print(name_visibility, printer);
+    if (suffix[0] != '\0') {
+      printer->AddString(")");
+      printer->AddString(suffix);
+    }
+    return;
+  }
   const TypeArguments& args = TypeArguments::Handle(zone, arguments());
   const intptr_t num_args = args.IsNull() ? 0 : args.Length();
   intptr_t first_type_param_index;
   intptr_t num_type_params;  // Number of type parameters to print.
   cls = type_class();
-  if (IsFunctionType()) {
-    const Function& signature_function =
-        Function::Handle(zone, Type::Cast(*this).signature());
-    if (!cls.IsTypedefClass()) {
-      const char* suffix = NullabilitySuffix(name_visibility);
-      if (suffix[0] != '\0') {
-        printer->AddString("(");
-      }
-      signature_function.PrintSignature(name_visibility, printer);
-      if (suffix[0] != '\0') {
-        printer->AddString(")");
-        printer->AddString(suffix);
-      }
-      return;
-    }
-    // Instead of printing the actual signature, use the typedef name with
-    // its type arguments, if any.
-    name_str = cls.Name();  // Typedef name.
-    if (!IsFinalized() || IsBeingFinalized()) {
-      // TODO(regis): Check if this is dead code.
-      printer->AddString(name_str.ToCString());
-      printer->AddString(NullabilitySuffix(name_visibility));
-      return;
-    }
-    // Print the name of a typedef as a regular, possibly parameterized, class.
-  }
   // Do not print the full vector, but only the declared type parameters.
   num_type_params = cls.NumTypeParameters();
   if (name_visibility == kInternalName) {
@@ -19257,7 +19301,7 @@
     // Do nothing.
   } else {
     args.PrintSubvectorName(first_type_param_index, num_type_params,
-                            name_visibility, printer, name_disambiguation);
+                            name_visibility, printer);
   }
   printer->AddString(NullabilitySuffix(name_visibility));
   // The name is only used for type checking and debugging purposes.
@@ -19356,9 +19400,7 @@
 }
 
 bool AbstractType::IsDartClosureType() const {
-  // Non-typedef function types have '_Closure' class as type class, but are not
-  // the Dart '_Closure' type.
-  return !IsFunctionType() && (type_class_id() == kClosureCid);
+  return (type_class_id() == kClosureCid);
 }
 
 bool AbstractType::IsFfiPointerType() const {
@@ -19461,8 +19503,6 @@
   if (other.IsTypeParameter()) {
     return false;
   }
-  const Class& type_cls = Class::Handle(zone, type_class());
-  const Class& other_type_cls = Class::Handle(zone, other.type_class());
   // Function types cannot be handled by Class::IsSubtypeOf().
   const bool other_is_dart_function_type = other.IsDartFunctionType();
   if (other_is_dart_function_type || other.IsFunctionType()) {
@@ -19474,23 +19514,17 @@
       if (other_is_dart_function_type) {
         return true;
       }
-      const Function& other_fun =
-          Function::Handle(zone, Type::Cast(other).signature());
       // Check for two function types.
-      const Function& fun =
-          Function::Handle(zone, Type::Cast(*this).signature());
-      return fun.IsSubtypeOf(other_fun, space);
+      return FunctionType::Cast(*this).IsSubtypeOf(FunctionType::Cast(other),
+                                                   space);
     }
-    if (other.IsFunctionType() && !other_type_cls.IsTypedefClass()) {
+    if (other.IsFunctionType()) {
       // [this] is not a function type. Therefore, non-function type [this]
-      // cannot be a subtype of function type [other], unless [other] is not
-      // only a function type, but also a named typedef.
-      // Indeed a typedef also behaves as a regular class-based type (with
-      // type arguments when generic).
+      // cannot be a subtype of function type [other].
       // This check is needed to avoid falling through to class-based type
       // tests, which yield incorrect result if [this] = _Closure class,
       // and [other] is a function type, because class of a function type is
-      // also _Closure (unless [other] is a typedef).
+      // also _Closure.
       return false;
     }
   }
@@ -19501,6 +19535,7 @@
     }
     return false;
   }
+  const Class& type_cls = Class::Handle(zone, type_class());
   return Class::IsSubtypeOf(type_cls, TypeArguments::Handle(zone, arguments()),
                             nullability(), other, space, trail);
 }
@@ -19656,8 +19691,7 @@
   Type& type = Type::Handle(type_class.declaration_type());
   if (type.IsNull()) {
     type = Type::New(Class::Handle(type_class.raw()),
-                     Object::null_type_arguments(), TokenPosition::kNoSource,
-                     Nullability::kNonNullable);
+                     Object::null_type_arguments(), Nullability::kNonNullable);
     type.SetIsFinalized();
     type ^= type.Canonicalize(Thread::Current(), nullptr);
     type_class.set_declaration_type(type);
@@ -19675,10 +19709,13 @@
   }
 }
 
-void Type::ResetIsFinalized() const {
-  ASSERT(IsFinalized());
-  set_type_state(TypeLayout::kBeingFinalized);
-  SetIsFinalized();
+void FunctionType::SetIsFinalized() const {
+  ASSERT(!IsFinalized());
+  if (IsInstantiated()) {
+    set_type_state(FunctionTypeLayout::kFinalizedInstantiated);
+  } else {
+    set_type_state(FunctionTypeLayout::kFinalizedUninstantiated);
+  }
 }
 
 void Type::SetIsBeingFinalized() const {
@@ -19686,6 +19723,11 @@
   set_type_state(TypeLayout::kBeingFinalized);
 }
 
+void FunctionType::SetIsBeingFinalized() const {
+  ASSERT(!IsFinalized() && !IsBeingFinalized());
+  set_type_state(FunctionTypeLayout::kBeingFinalized);
+}
+
 TypePtr Type::ToNullability(Nullability value, Heap::Space space) const {
   if (nullability() == value) {
     return raw();
@@ -19718,17 +19760,26 @@
   return type.raw();
 }
 
-FunctionPtr Type::signature() const {
-  intptr_t cid = raw_ptr()->signature()->GetClassId();
-  if (cid == kNullCid) {
-    return Function::null();
+FunctionTypePtr FunctionType::ToNullability(Nullability value,
+                                            Heap::Space space) const {
+  if (nullability() == value) {
+    return raw();
   }
-  ASSERT(cid == kFunctionCid);
-  return Function::RawCast(raw_ptr()->signature());
-}
-
-void Type::set_signature(const Function& value) const {
-  raw_ptr()->set_signature(value.raw());
+  // Clone function type and set new nullability.
+  FunctionType& type = FunctionType::Handle();
+  // Always cloning in old space and removing space parameter would not satisfy
+  // currently existing requests for type instantiation in new space.
+  type ^= Object::Clone(*this, space);
+  type.set_nullability(value);
+  type.SetHash(0);
+  type.SetTypeTestingStub(
+      Code::Handle(TypeTestingStubGenerator::DefaultCodeForType(type)));
+  if (IsCanonical()) {
+    // Object::Clone does not clone canonical bit.
+    ASSERT(!type.IsCanonical());
+    type ^= type.Canonicalize(Thread::Current(), nullptr);
+  }
+  return type.raw();
 }
 
 classid_t Type::type_class_id() const {
@@ -19749,16 +19800,6 @@
       (raw_ptr()->type_state_ == TypeLayout::kFinalizedUninstantiated)) {
     return false;
   }
-  if (IsFunctionType()) {
-    const Function& sig_fun = Function::Handle(signature());
-    if (!sig_fun.HasInstantiatedSignature(genericity, num_free_fun_type_params,
-                                          trail)) {
-      return false;
-    }
-    // Because a generic typedef with an instantiated signature is considered
-    // uninstantiated, we still need to check the type arguments, even if the
-    // signature is instantiated.
-  }
   if (arguments() == TypeArguments::null()) {
     return true;
   }
@@ -19794,52 +19835,19 @@
   // finalizing the type argument vector of a recursive type.
   const Class& cls = Class::Handle(zone, type_class());
   TypeArguments& type_arguments = TypeArguments::Handle(zone, arguments());
-  Function& sig_fun = Function::Handle(zone, signature());
-  if (!type_arguments.IsNull() &&
-      (sig_fun.IsNull() || !type_arguments.IsInstantiated())) {
-    // This type is uninstantiated because either its type arguments or its
-    // signature, or both are uninstantiated.
-    // Note that the type arguments of a function type merely document the
-    // parameterization of a generic typedef. They are otherwise ignored.
-    ASSERT(type_arguments.Length() == cls.NumTypeArguments());
-    type_arguments = type_arguments.InstantiateFrom(
-        instantiator_type_arguments, function_type_arguments,
-        num_free_fun_type_params, space, trail);
-    // A returned empty_type_arguments indicates a failed instantiation in dead
-    // code that must be propagated up to the caller, the optimizing compiler.
-    if (type_arguments.raw() == Object::empty_type_arguments().raw()) {
-      return Type::null();
-    }
+  ASSERT(type_arguments.Length() == cls.NumTypeArguments());
+  type_arguments = type_arguments.InstantiateFrom(
+      instantiator_type_arguments, function_type_arguments,
+      num_free_fun_type_params, space, trail);
+  // A returned empty_type_arguments indicates a failed instantiation in dead
+  // code that must be propagated up to the caller, the optimizing compiler.
+  if (type_arguments.raw() == Object::empty_type_arguments().raw()) {
+    return Type::null();
   }
   // This uninstantiated type is not modified, as it can be instantiated
   // with different instantiators. Allocate a new instantiated version of it.
-  const Type& instantiated_type = Type::Handle(
-      zone, Type::New(cls, type_arguments, token_pos(), nullability(), space));
-  // For a function type, possibly instantiate and set its signature.
-  if (!sig_fun.IsNull()) {
-    // If we are finalizing a typedef, do not yet instantiate its signature,
-    // since it gets instantiated just before the type is marked as finalized.
-    // Other function types should never get instantiated while unfinalized,
-    // even while checking bounds of recursive types.
-    if (IsFinalized()) {
-      // A generic typedef may actually declare an instantiated signature.
-      if (!sig_fun.HasInstantiatedSignature(kAny, num_free_fun_type_params)) {
-        sig_fun = sig_fun.InstantiateSignatureFrom(
-            instantiator_type_arguments, function_type_arguments,
-            num_free_fun_type_params, space);
-        // A returned null signature indicates a failed instantiation in dead
-        // code that must be propagated up to the caller, the optimizing
-        // compiler.
-        if (sig_fun.IsNull()) {
-          return Type::null();
-        }
-      }
-    } else {
-      // The Kernel frontend does not keep the information that a function type
-      // is a typedef, so we cannot assert that cls.IsTypedefClass().
-    }
-    instantiated_type.set_signature(sig_fun);
-  }
+  const Type& instantiated_type =
+      Type::Handle(zone, Type::New(cls, type_arguments, nullability(), space));
   if (IsFinalized()) {
     instantiated_type.SetIsFinalized();
   } else {
@@ -19869,9 +19877,6 @@
     return false;
   }
   const Type& other_type = Type::Cast(other);
-  if (IsFunctionType() != other_type.IsFunctionType()) {
-    return false;
-  }
   if (type_class_id() != other_type.type_class_id()) {
     return false;
   }
@@ -19896,6 +19901,7 @@
       }
     } else {
       ASSERT(kind == TypeEquality::kCanonical);
+      ASSERT(IsFinalized() && other_type.IsFinalized());
     }
     if (this_type_nullability != other_type_nullability) {
       return false;
@@ -19904,8 +19910,7 @@
   if (!IsFinalized() || !other_type.IsFinalized()) {
     return false;  // Too early to decide if equal.
   }
-  if ((arguments() == other_type.arguments()) &&
-      (signature() == other_type.signature())) {
+  if (arguments() == other_type.arguments()) {
     return true;
   }
   if (arguments() != other_type.arguments()) {
@@ -19952,85 +19957,106 @@
 #endif
     }
   }
-  if (!IsFunctionType()) {
+  return true;
+}
+
+bool FunctionType::IsEquivalent(const Instance& other,
+                                TypeEquality kind,
+                                TrailPtr trail) const {
+  ASSERT(!IsNull());
+  if (raw() == other.raw()) {
     return true;
   }
-  ASSERT(Type::Cast(other).IsFunctionType());
+  if (other.IsTypeRef()) {
+    // Unfold right hand type. Divergence is controlled by left hand type.
+    const AbstractType& other_ref_type =
+        AbstractType::Handle(TypeRef::Cast(other).type());
+    ASSERT(!other_ref_type.IsTypeRef());
+    return IsEquivalent(other_ref_type, kind, trail);
+  }
+  if (!other.IsFunctionType()) {
+    return false;
+  }
+  const FunctionType& other_type = FunctionType::Cast(other);
+  if (packed_fields() != other_type.packed_fields()) {
+    // Different number of parent type arguments or of parameters.
+    return false;
+  }
+  Nullability this_type_nullability = nullability();
+  Nullability other_type_nullability = other_type.nullability();
+  Thread* thread = Thread::Current();
+  auto isolate_group = thread->isolate_group();
+  Zone* zone = thread->zone();
+  if (kind == TypeEquality::kInSubtypeTest) {
+    if (isolate_group->null_safety() &&
+        this_type_nullability == Nullability::kNullable &&
+        other_type_nullability == Nullability::kNonNullable) {
+      return false;
+    }
+  } else {
+    if (kind == TypeEquality::kSyntactical) {
+      if (this_type_nullability == Nullability::kLegacy) {
+        this_type_nullability = Nullability::kNonNullable;
+      }
+      if (other_type_nullability == Nullability::kLegacy) {
+        other_type_nullability = Nullability::kNonNullable;
+      }
+    } else {
+      ASSERT(kind == TypeEquality::kCanonical);
+      ASSERT(IsFinalized() && other_type.IsFinalized());
+    }
+    if (this_type_nullability != other_type_nullability) {
+      return false;
+    }
+  }
+  if (!IsFinalized() || !other_type.IsFinalized()) {
+    return false;  // Too early to decide if equal.
+  }
   // Equal function types must have equal signature types and equal optional
   // named arguments.
-  if (signature() == other_type.signature()) {
-    return true;
-  }
-  const Function& sig_fun = Function::Handle(zone, signature());
-  const Function& other_sig_fun =
-      Function::Handle(zone, other_type.signature());
 
   // Compare function type parameters and their bounds.
   // Check the type parameters and bounds of generic functions.
-  if (!sig_fun.HasSameTypeParametersAndBounds(other_sig_fun, kind)) {
-    return false;
-  }
-
-  // Compare number of function parameters.
-  const intptr_t num_fixed_params = sig_fun.num_fixed_parameters();
-  const intptr_t other_num_fixed_params = other_sig_fun.num_fixed_parameters();
-  if (num_fixed_params != other_num_fixed_params) {
-    return false;
-  }
-  const intptr_t num_opt_pos_params = sig_fun.NumOptionalPositionalParameters();
-  const intptr_t other_num_opt_pos_params =
-      other_sig_fun.NumOptionalPositionalParameters();
-  if (num_opt_pos_params != other_num_opt_pos_params) {
-    return false;
-  }
-  const intptr_t num_opt_named_params = sig_fun.NumOptionalNamedParameters();
-  const intptr_t other_num_opt_named_params =
-      other_sig_fun.NumOptionalNamedParameters();
-  if (num_opt_named_params != other_num_opt_named_params) {
-    return false;
-  }
-  const intptr_t num_ignored_params = sig_fun.NumImplicitParameters();
-  const intptr_t other_num_ignored_params =
-      other_sig_fun.NumImplicitParameters();
-  if (num_ignored_params != other_num_ignored_params) {
+  if (!HasSameTypeParametersAndBounds(other_type, kind)) {
     return false;
   }
   AbstractType& param_type = Type::Handle(zone);
   AbstractType& other_param_type = Type::Handle(zone);
   // Check the result type.
-  param_type = sig_fun.result_type();
-  other_param_type = other_sig_fun.result_type();
-  if (!param_type.IsEquivalent(other_param_type, kind)) {
+  param_type = result_type();
+  other_param_type = other_type.result_type();
+  if (!param_type.IsEquivalent(other_param_type, kind, trail)) {
     return false;
   }
   // Check the types of all parameters.
-  const intptr_t num_params = sig_fun.NumParameters();
-  ASSERT(other_sig_fun.NumParameters() == num_params);
+  const intptr_t num_params = NumParameters();
+  ASSERT(other_type.NumParameters() == num_params);
   for (intptr_t i = 0; i < num_params; i++) {
-    param_type = sig_fun.ParameterTypeAt(i);
-    other_param_type = other_sig_fun.ParameterTypeAt(i);
+    param_type = ParameterTypeAt(i);
+    other_param_type = other_type.ParameterTypeAt(i);
     // Use contravariant order in case we test for subtyping.
-    if (!other_param_type.IsEquivalent(param_type, kind)) {
+    if (!other_param_type.IsEquivalent(param_type, kind, trail)) {
       return false;
     }
   }
   // Check the names and types of optional named parameters.
-  if (num_opt_named_params == 0) {
+  if (!HasOptionalNamedParameters()) {
+    ASSERT(!other_type.HasOptionalNamedParameters());  // Same packed_fields.
     return true;
   }
-  for (intptr_t i = num_fixed_params; i < num_params; i++) {
-    if (sig_fun.ParameterNameAt(i) != other_sig_fun.ParameterNameAt(i)) {
+  for (intptr_t i = num_fixed_parameters(); i < num_params; i++) {
+    if (ParameterNameAt(i) != other_type.ParameterNameAt(i)) {
       return false;
     }
-    if (sig_fun.IsRequiredAt(i) != other_sig_fun.IsRequiredAt(i)) {
+    if (IsRequiredAt(i) != other_type.IsRequiredAt(i)) {
       return false;
     }
   }
   return true;
 }
 
-bool Type::IsRecursive() const {
-  return TypeArguments::Handle(arguments()).IsRecursive();
+bool Type::IsRecursive(TrailPtr trail) const {
+  return TypeArguments::Handle(arguments()).IsRecursive(trail);
 }
 
 bool Type::IsDeclarationTypeOf(const Class& cls) const {
@@ -20038,21 +20064,24 @@
   if (cls.IsNullClass()) {
     return true;
   }
-  if (cls.IsGeneric() || cls.IsClosureClass() || cls.IsTypedefClass()) {
+  if (cls.IsGeneric() || cls.IsClosureClass()) {
     return false;
   }
   return nullability() == Nullability::kNonNullable;
 }
 
 AbstractTypePtr Type::Canonicalize(Thread* thread, TrailPtr trail) const {
+  Zone* zone = thread->zone();
   ASSERT(IsFinalized());
   if (IsCanonical()) {
-    ASSERT(TypeArguments::Handle(arguments()).IsOld());
+#ifdef DEBUG
+    TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+    ASSERT(type_args.IsCanonical());
+    ASSERT(type_args.IsOld());
+#endif
     return this->raw();
   }
-  Zone* zone = thread->zone();
   auto isolate_group = thread->isolate_group();
-
   const classid_t cid = type_class_id();
   if (cid == kDynamicCid) {
     ASSERT(Object::dynamic_type().IsCanonical());
@@ -20068,7 +20097,6 @@
 
   // Fast canonical lookup/registry for simple types.
   if (IsDeclarationTypeOf(cls)) {
-    ASSERT(!IsFunctionType());
     ASSERT(!cls.IsNullClass() || IsNullable());
     Type& type = Type::Handle(zone, cls.declaration_type());
     if (type.IsNull()) {
@@ -20109,7 +20137,7 @@
     return type.raw();
   }
 
-  AbstractType& type = Type::Handle(zone);
+  Type& type = Type::Handle(zone);
   ObjectStore* object_store = isolate_group->object_store();
   {
     SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex());
@@ -20145,26 +20173,19 @@
     if (IsCanonical()) {
       // Canonicalizing type_args canonicalized this type as a side effect.
       ASSERT(IsRecursive());
-      // Cycles via typedefs are detected and disallowed, but a function type
-      // can be recursive due to a cycle in its type arguments.
+      // A type can be recursive due to a cycle in its type arguments.
       return this->raw();
     }
     set_arguments(type_args);
     ASSERT(type_args.IsNull() || type_args.IsOld());
 
-    // In case of a function type, the signature has already been canonicalized
-    // when finalizing the type and passing kCanonicalize as finalization.
-    // Therefore, we do not canonicalize the signature here, which would have no
-    // effect on selecting the canonical type anyway, because the function
-    // object is not replaced when canonicalizing the signature.
-
-    // Check to see if the type got added to canonical list as part of the
+    // Check to see if the type got added to canonical table as part of the
     // type arguments canonicalization.
     SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex());
     CanonicalTypeSet table(zone, object_store->canonical_types());
     type ^= table.GetOrNull(CanonicalTypeKey(*this));
     if (type.IsNull()) {
-      // Add this Type into the canonical list of types.
+      // Add this type into the canonical table of types.
       if (this->IsNew()) {
         type ^= Object::Clone(*this, Heap::kOld);
       } else {
@@ -20194,12 +20215,11 @@
   }
   Zone* zone = thread->zone();
   auto isolate_group = thread->isolate_group();
-  AbstractType& type = Type::Handle(zone);
+  Type& type = Type::Handle(zone);
   const Class& cls = Class::Handle(zone, type_class());
 
   // Fast canonical lookup/registry for simple types.
   if (IsDeclarationTypeOf(cls)) {
-    ASSERT(!IsFunctionType());
     type = cls.declaration_type();
     ASSERT(type.IsCanonical());
     return (raw() == type.raw());
@@ -20222,35 +20242,18 @@
   }
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
-  if (IsFunctionType()) {
-    // The scope class and type arguments do not appear explicitly in the user
-    // visible name. The type arguments were used to instantiate the function
-    // type prior to this call.
-    const Function& sig_fun = Function::Handle(zone, signature());
-    AbstractType& type = AbstractType::Handle(zone);
-    const intptr_t num_params = sig_fun.NumParameters();
-    for (intptr_t i = 0; i < num_params; i++) {
-      type = sig_fun.ParameterTypeAt(i);
-      type.EnumerateURIs(uris);
-    }
-    // Handle result type last, since it appears last in the user visible name.
-    type = sig_fun.result_type();
-    type.EnumerateURIs(uris);
-  } else {
-    const Class& cls = Class::Handle(zone, type_class());
-    const String& name = String::Handle(zone, cls.UserVisibleName());
-    const Library& library = Library::Handle(zone, cls.library());
-    const String& uri = String::Handle(zone, library.url());
-    AddURI(uris, name, uri);
-    const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
-    type_args.EnumerateURIs(uris);
-  }
+  const Class& cls = Class::Handle(zone, type_class());
+  const String& name = String::Handle(zone, cls.UserVisibleName());
+  const Library& library = Library::Handle(zone, cls.library());
+  const String& uri = String::Handle(zone, library.url());
+  AddURI(uris, name, uri);
+  const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
+  type_args.EnumerateURIs(uris);
 }
 
 intptr_t Type::ComputeHash() const {
   ASSERT(IsFinalized());
-  uint32_t result = 0;
-  result = CombineHashes(result, type_class_id());
+  uint32_t result = type_class_id();
   // A legacy type should have the same hash as its non-nullable version to be
   // consistent with the definition of type equality in Dart code.
   Nullability type_nullability = nullability();
@@ -20272,35 +20275,45 @@
     }
   }
   result = CombineHashes(result, type_args_hash);
-  if (IsFunctionType()) {
-    AbstractType& type = AbstractType::Handle();
-    const Function& sig_fun = Function::Handle(signature());
-    const intptr_t num_type_params = sig_fun.NumTypeParameters();
-    if (num_type_params > 0) {
-      const TypeArguments& type_params =
-          TypeArguments::Handle(sig_fun.type_parameters());
-      for (intptr_t i = 0; i < num_type_params; i++) {
-        type = type_params.TypeAt(i);
-        type = TypeParameter::Cast(type).bound();
-        result = CombineHashes(result, type.Hash());
-      }
-    }
-    type = sig_fun.result_type();
-    result = CombineHashes(result, type.Hash());
-    result = CombineHashes(result, sig_fun.NumOptionalPositionalParameters());
-    const intptr_t num_params = sig_fun.NumParameters();
-    for (intptr_t i = 0; i < num_params; i++) {
-      type = sig_fun.ParameterTypeAt(i);
+  result = FinalizeHash(result, kHashBits);
+  SetHash(result);
+  return result;
+}
+
+intptr_t FunctionType::ComputeHash() const {
+  ASSERT(IsFinalized());
+  uint32_t result = packed_fields();
+  // A legacy type should have the same hash as its non-nullable version to be
+  // consistent with the definition of type equality in Dart code.
+  Nullability type_nullability = nullability();
+  if (type_nullability == Nullability::kLegacy) {
+    type_nullability = Nullability::kNonNullable;
+  }
+  result = CombineHashes(result, static_cast<uint32_t>(type_nullability));
+  AbstractType& type = AbstractType::Handle();
+  const intptr_t num_type_params = NumTypeParameters();
+  if (num_type_params > 0) {
+    const TypeArguments& type_params = TypeArguments::Handle(type_parameters());
+    for (intptr_t i = 0; i < num_type_params; i++) {
+      type = type_params.TypeAt(i);
+      type = TypeParameter::Cast(type).bound();
       result = CombineHashes(result, type.Hash());
     }
-    if (sig_fun.NumOptionalNamedParameters() > 0) {
-      String& param_name = String::Handle();
-      for (intptr_t i = sig_fun.num_fixed_parameters(); i < num_params; i++) {
-        param_name = sig_fun.ParameterNameAt(i);
-        result = CombineHashes(result, param_name.Hash());
-      }
-      // Required flag is not hashed, see comment above.
+  }
+  type = result_type();
+  result = CombineHashes(result, type.Hash());
+  const intptr_t num_params = NumParameters();
+  for (intptr_t i = 0; i < num_params; i++) {
+    type = ParameterTypeAt(i);
+    result = CombineHashes(result, type.Hash());
+  }
+  if (HasOptionalNamedParameters()) {
+    String& param_name = String::Handle();
+    for (intptr_t i = num_fixed_parameters(); i < num_params; i++) {
+      param_name = ParameterNameAt(i);
+      result = CombineHashes(result, param_name.Hash());
     }
+    // Required flag is not hashed, see comment above about legacy type.
   }
   result = FinalizeHash(result, kHashBits);
   SetHash(result);
@@ -20324,7 +20337,6 @@
 
 TypePtr Type::New(const Class& clazz,
                   const TypeArguments& arguments,
-                  TokenPosition token_pos,
                   Nullability nullability,
                   Heap::Space space) {
   Zone* Z = Thread::Current()->zone();
@@ -20332,7 +20344,6 @@
   result.set_type_class(clazz);
   result.set_arguments(arguments);
   result.SetHash(0);
-  result.set_token_pos(token_pos);
   result.StoreNonPointer(&result.raw_ptr()->type_state_,
                          TypeLayout::kAllocated);
   result.set_nullability(nullability);
@@ -20342,12 +20353,7 @@
   return result.raw();
 }
 
-void Type::set_token_pos(TokenPosition token_pos) const {
-  ASSERT(!token_pos.IsClassifying());
-  StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
-}
-
-void Type::set_type_state(int8_t state) const {
+void Type::set_type_state(uint8_t state) const {
   ASSERT((state >= TypeLayout::kAllocated) &&
          (state <= TypeLayout::kFinalizedUninstantiated));
   StoreNonPointer(&raw_ptr()->type_state_, state);
@@ -20362,8 +20368,7 @@
   const TypeArguments& type_args = TypeArguments::Handle(zone, arguments());
   const char* args_cstr = "";
   if (!type_args.IsNull()) {
-    type_args.PrintSubvectorName(0, type_args.Length(), kInternalName, &args,
-                                 NameDisambiguation::kYes);
+    type_args.PrintSubvectorName(0, type_args.Length(), kInternalName, &args);
     args_cstr = args.buffer();
   }
   const Class& cls = Class::Handle(zone, type_class());
@@ -20371,24 +20376,6 @@
   const String& name = String::Handle(zone, cls.Name());
   class_name = name.IsNull() ? "<null>" : name.ToCString();
   const char* suffix = NullabilitySuffix(kInternalName);
-  if (IsFunctionType()) {
-    const Function& sig_fun = Function::Handle(zone, signature());
-    ZoneTextBuffer sig(zone);
-    if (suffix[0] != '\0') {
-      sig.AddString("(");
-    }
-    sig_fun.PrintSignature(kInternalName, &sig);
-    if (suffix[0] != '\0') {
-      sig.AddString(")");
-      sig.AddString(suffix);
-    }
-    if (cls.IsClosureClass()) {
-      ASSERT(type_args.IsNull());
-      return OS::SCreate(zone, "Function Type: %s", sig.buffer());
-    }
-    return OS::SCreate(zone, "Function Type: %s (%s%s%s)", sig.buffer(),
-                       class_name, args_cstr, suffix);
-  }
   if (IsFinalized() && IsRecursive()) {
     const intptr_t hash = Hash();
     return OS::SCreate(zone, "Type: (H%" Px ") %s%s%s", hash, class_name,
@@ -20398,6 +20385,171 @@
   }
 }
 
+bool FunctionType::IsRecursive(TrailPtr trail) const {
+  AbstractType& type = AbstractType::Handle();
+  const intptr_t num_type_params = NumTypeParameters();
+  if (num_type_params > 0) {
+    const TypeArguments& type_params = TypeArguments::Handle(type_parameters());
+    for (intptr_t i = 0; i < num_type_params; i++) {
+      type = type_params.TypeAt(i);
+      if (type.IsRecursive(trail)) {
+        return true;
+      }
+    }
+  }
+  type = result_type();
+  if (type.IsRecursive(trail)) {
+    return true;
+  }
+  const intptr_t num_params = NumParameters();
+  for (intptr_t i = 0; i < num_params; i++) {
+    type = ParameterTypeAt(i);
+    if (type.IsRecursive(trail)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+AbstractTypePtr FunctionType::Canonicalize(Thread* thread,
+                                           TrailPtr trail) const {
+  ASSERT(IsFinalized());
+  Zone* zone = thread->zone();
+  if (IsCanonical()) {
+#ifdef DEBUG
+    // Verify that all fields are allocated in old space and are canonical.
+    AbstractType& type = AbstractType::Handle(zone);
+    const intptr_t num_type_params = NumTypeParameters();
+    if (num_type_params > 0) {
+      const TypeArguments& type_params =
+          TypeArguments::Handle(zone, type_parameters());
+      ASSERT(type_params.IsOld());
+      for (intptr_t i = 0; i < num_type_params; i++) {
+        type = type_params.TypeAt(i);
+        ASSERT(type.IsOld());
+        ASSERT(type.IsCanonical());
+      }
+    }
+    type = result_type();
+    ASSERT(type.IsOld());
+    ASSERT(type.IsCanonical());
+    ASSERT(Array::Handle(zone, parameter_types()).IsOld());
+    ASSERT(Array::Handle(zone, parameter_names()).IsOld());
+    const intptr_t num_params = NumParameters();
+    for (intptr_t i = 0; i < num_params; i++) {
+      type = ParameterTypeAt(i);
+      ASSERT(type.IsOld());
+      ASSERT(type.IsCanonical());
+    }
+#endif
+    return raw();
+  }
+  auto isolate_group = thread->isolate_group();
+  ObjectStore* object_store = isolate_group->object_store();
+  FunctionType& sig = FunctionType::Handle(zone);
+  {
+    SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex());
+    CanonicalFunctionTypeSet table(zone,
+                                   object_store->canonical_function_types());
+    sig ^= table.GetOrNull(CanonicalFunctionTypeKey(*this));
+    ASSERT(object_store->canonical_function_types() == table.Release().raw());
+  }
+  if (sig.IsNull()) {
+    // The function type was not found in the table. It is not canonical yet.
+    // Canonicalize its type parameters and types.
+    const intptr_t num_type_params = NumTypeParameters();
+    if (num_type_params > 0) {
+      const TypeArguments& type_params =
+          TypeArguments::Handle(zone, type_parameters());
+      ASSERT(type_params.IsOld());
+      TypeParameter& type_param = TypeParameter::Handle(zone);
+      for (intptr_t i = 0; i < num_type_params; i++) {
+        type_param ^= type_params.TypeAt(i);
+        if (!type_param.IsCanonical()) {
+          type_param ^= type_param.Canonicalize(thread, trail);
+          type_params.SetTypeAt(i, type_param);
+          SetHash(0);
+        }
+      }
+    }
+    AbstractType& type = AbstractType::Handle(zone);
+    type = result_type();
+    if (!type.IsCanonical()) {
+      type = type.Canonicalize(thread, trail);
+      set_result_type(type);
+      SetHash(0);
+    }
+    ASSERT(Array::Handle(zone, parameter_types()).IsOld());
+    ASSERT(Array::Handle(zone, parameter_names()).IsOld());
+    const intptr_t num_params = NumParameters();
+    for (intptr_t i = 0; i < num_params; i++) {
+      type = ParameterTypeAt(i);
+      if (!type.IsCanonical()) {
+        type = type.Canonicalize(thread, trail);
+        SetParameterTypeAt(i, type);
+        SetHash(0);
+      }
+    }
+    if (IsCanonical()) {
+      // Canonicalizing signature types canonicalized this signature as a
+      // side effect.
+      ASSERT(IsRecursive());
+      return this->raw();
+    }
+    // Check to see if the function type got added to canonical table as part
+    // of the canonicalization of its signature types.
+    SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex());
+    CanonicalFunctionTypeSet table(zone,
+                                   object_store->canonical_function_types());
+    sig ^= table.GetOrNull(CanonicalFunctionTypeKey(*this));
+    if (sig.IsNull()) {
+      // Add this function type into the canonical table of function types.
+      if (this->IsNew()) {
+        sig ^= Object::Clone(*this, Heap::kOld);
+      } else {
+        sig = this->raw();
+      }
+      ASSERT(sig.IsOld());
+      sig.SetCanonical();  // Mark object as being canonical.
+      bool present = table.Insert(sig);
+      ASSERT(!present);
+    }
+    object_store->set_canonical_function_types(table.Release());
+  }
+  return sig.raw();
+}
+
+#if defined(DEBUG)
+bool FunctionType::CheckIsCanonical(Thread* thread) const {
+  Zone* zone = thread->zone();
+  auto isolate_group = thread->isolate_group();
+  FunctionType& type = FunctionType::Handle(zone);
+  ObjectStore* object_store = isolate_group->object_store();
+  {
+    SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex());
+    CanonicalFunctionTypeSet table(zone,
+                                   object_store->canonical_function_types());
+    type ^= table.GetOrNull(CanonicalFunctionTypeKey(*this));
+    object_store->set_canonical_function_types(table.Release());
+  }
+  return raw() == type.raw();
+}
+#endif  // DEBUG
+
+void FunctionType::EnumerateURIs(URIs* uris) const {
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  AbstractType& type = AbstractType::Handle(zone);
+  const intptr_t num_params = NumParameters();
+  for (intptr_t i = 0; i < num_params; i++) {
+    type = ParameterTypeAt(i);
+    type.EnumerateURIs(uris);
+  }
+  // Handle result type last, since it appears last in the user visible name.
+  type = result_type();
+  type.EnumerateURIs(uris);
+}
+
 bool TypeRef::IsInstantiated(Genericity genericity,
                              intptr_t num_free_fun_type_params,
                              TrailPtr trail) const {
@@ -20459,8 +20611,7 @@
 }
 
 void TypeRef::set_type(const AbstractType& value) const {
-  ASSERT(value.IsNull() || value.IsFunctionType() || value.HasTypeClass());
-  ASSERT(!value.IsTypeRef());
+  ASSERT(value.IsNull() || value.IsType() || value.IsFunctionType());
   raw_ptr()->set_type(value.raw());
 }
 
@@ -20511,8 +20662,14 @@
   //    type arguments are set).
   const AbstractType& ref_type = AbstractType::Handle(type());
   ASSERT(!ref_type.IsNull());
-  uint32_t result = Class::Handle(ref_type.type_class()).id();
-  result = CombineHashes(result, static_cast<uint32_t>(ref_type.nullability()));
+  uint32_t result = ref_type.type_class_id();
+  // A legacy type should have the same hash as its non-nullable version to be
+  // consistent with the definition of type equality in Dart code.
+  Nullability ref_type_nullability = ref_type.nullability();
+  if (ref_type_nullability == Nullability::kLegacy) {
+    ref_type_nullability = Nullability::kNonNullable;
+  }
+  result = CombineHashes(result, static_cast<uint32_t>(ref_type_nullability));
   return FinalizeHash(result, kHashBits);
 }
 
@@ -20550,7 +20707,15 @@
 
 void TypeParameter::SetIsFinalized() const {
   ASSERT(!IsFinalized());
-  set_flags(TypeParameterLayout::FinalizedBit::update(true, raw_ptr()->flags_));
+  set_flags(TypeParameterLayout::FinalizedBit::update(
+      true, TypeParameterLayout::BeingFinalizedBit::update(false,
+                                                           raw_ptr()->flags_)));
+}
+
+void TypeParameter::SetIsBeingFinalized() const {
+  ASSERT(!IsFinalized());
+  set_flags(
+      TypeParameterLayout::BeingFinalizedBit::update(true, raw_ptr()->flags_));
 }
 
 void TypeParameter::SetGenericCovariantImpl(bool value) const {
@@ -20558,13 +20723,8 @@
       value, raw_ptr()->flags_));
 }
 
-void TypeParameter::SetDeclaration(bool value) const {
-  set_flags(
-      TypeParameterLayout::DeclarationBit::update(value, raw_ptr()->flags_));
-}
-
 void TypeParameter::set_nullability(Nullability value) const {
-  StoreNonPointer(&raw_ptr()->nullability_, static_cast<int8_t>(value));
+  StoreNonPointer(&raw_ptr()->nullability_, static_cast<uint8_t>(value));
 }
 
 TypeParameterPtr TypeParameter::ToNullability(Nullability value,
@@ -20576,16 +20736,15 @@
   TypeParameter& type_parameter = TypeParameter::Handle();
   type_parameter ^= Object::Clone(*this, space);
   type_parameter.set_nullability(value);
-  type_parameter.SetDeclaration(false);
   type_parameter.SetHash(0);
   type_parameter.SetTypeTestingStub(Code::Handle(
       TypeTestingStubGenerator::DefaultCodeForType(type_parameter)));
   if (IsCanonical()) {
     // Object::Clone does not clone canonical bit.
     ASSERT(!type_parameter.IsCanonical());
-    if (IsFinalized()) {
-      type_parameter ^= type_parameter.Canonicalize(Thread::Current(), nullptr);
-    }
+    ASSERT(IsFinalized());
+    ASSERT(type_parameter.IsFinalized());
+    type_parameter ^= type_parameter.Canonicalize(Thread::Current(), nullptr);
   }
   return type_parameter.raw();
 }
@@ -20598,13 +20757,13 @@
     return genericity == kFunctions;
   }
   ASSERT(IsFunctionTypeParameter());
-  ASSERT(IsFinalized());
   if ((genericity != kCurrentClass) && (index() < num_free_fun_type_params)) {
     return false;
   }
   // Although the type parameter is instantiated, its bound may not be.
   const AbstractType& upper_bound = AbstractType::Handle(bound());
-  if (upper_bound.IsTypeParameter() ||
+  ASSERT(!upper_bound.IsTypeRef());
+  if (upper_bound.IsTypeParameter() || upper_bound.IsFunctionType() ||
       upper_bound.arguments() != TypeArguments::null()) {
     // Use trail to break cycles created by bound referring to type parameter.
     if (!TestAndAddToTrail(&trail) &&
@@ -20633,18 +20792,93 @@
     return false;
   }
   const TypeParameter& other_type_param = TypeParameter::Cast(other);
-  // Class type parameters must parameterize the same class to be equivalent.
-  // Note that this check will also reject a class type parameter being compared
-  // to a function type parameter.
-  if (parameterized_class_id() != other_type_param.parameterized_class_id()) {
-    return false;
+  // Compare index, name, bound, default argument, and flags.
+  if (IsFunctionTypeParameter()) {
+    if (!other_type_param.IsFunctionTypeParameter()) {
+      return false;
+    }
+    ASSERT(IsFinalized() && other_type_param.IsFinalized());
+    if (kind == TypeEquality::kInSubtypeTest) {
+      // To be equivalent, the function type parameters should be declared
+      // at the same position in the generic function. Their index therefore
+      // needs adjustment before comparison.
+      // Example: 'foo<F>(bar<B>(B b)) { }' and 'baz<Z>(Z z) { }', baz can
+      // be assigned to bar, although B has index 1 and Z index 0.
+      if (index() - base() !=
+          other_type_param.index() - other_type_param.base()) {
+        return false;
+      }
+      AbstractType& upper_bound = AbstractType::Handle(bound());
+      AbstractType& other_type_param_upper_bound =
+          AbstractType::Handle(other_type_param.bound());
+      // Bounds that are mutual subtypes are considered equal.
+      if (!upper_bound.IsSubtypeOf(other_type_param_upper_bound, Heap::kOld) ||
+          !other_type_param_upper_bound.IsSubtypeOf(upper_bound, Heap::kOld)) {
+        return false;
+      }
+    } else {
+      if (base() != other_type_param.base() ||
+          index() != other_type_param.index()) {
+        return false;
+      }
+      // Compare bounds.
+      AbstractType& type = AbstractType::Handle(bound());
+      AbstractType& other_type = AbstractType::Handle(other_type_param.bound());
+      if (!TestAndAddBuddyToTrail(&trail, other_type_param) &&
+          !type.IsEquivalent(other_type, kind, trail)) {
+        return false;
+      }
+      if (kind == TypeEquality::kCanonical) {
+        // Compare names.
+        if (name() != other_type_param.name()) {
+          return false;
+        }
+        // Compare default arguments.
+        type = default_argument();
+        other_type = other_type_param.default_argument();
+        if (type.IsNull()) {
+          if (!other_type.IsNull()) {
+            return false;
+          }
+        } else if (!type.IsEquivalent(other_type, kind, trail)) {
+          return false;
+        }
+      }
+    }
+    if (IsGenericCovariantImpl() != other_type_param.IsGenericCovariantImpl()) {
+      return false;
+    }
+  } else {
+    if (!other_type_param.IsClassTypeParameter()) {
+      return false;
+    }
+    if (kind == TypeEquality::kCanonical) {
+      if (parameterized_class_id() !=
+          other_type_param.parameterized_class_id()) {
+        // This also rejects finalized vs unfinalized comparison.
+        return false;
+      }
+      if (base() != other_type_param.base() ||
+          index() != other_type_param.index() ||
+          name() != other_type_param.name()) {
+        return false;
+      }
+    } else {
+      ASSERT(IsFinalized() && other_type_param.IsFinalized());
+      if (index() != other_type_param.index()) {
+        return false;
+      }
+    }
+    // Compare bounds.
+    AbstractType& upper_bound = AbstractType::Handle(bound());
+    AbstractType& other_type_param_upper_bound =
+        AbstractType::Handle(other_type_param.bound());
+    if (!TestAndAddBuddyToTrail(&trail, other_type_param) &&
+        !upper_bound.IsEquivalent(other_type_param_upper_bound, kind, trail)) {
+      return false;
+    }
   }
-  // The function does not matter in type tests or when comparing types with
-  // syntactical equality, but it does matter in canonicalization.
-  if (kind == TypeEquality::kCanonical &&
-      parameterized_function() != other_type_param.parameterized_function()) {
-    return false;
-  }
+  // Compare nullability.
   Nullability this_type_param_nullability = nullability();
   Nullability other_type_param_nullability = other_type_param.nullability();
   if (kind == TypeEquality::kInSubtypeTest) {
@@ -20668,30 +20902,23 @@
       return false;
     }
   }
-  if (kind == TypeEquality::kInSubtypeTest) {
-    if (IsFunctionTypeParameter() && IsFinalized() &&
-        other_type_param.IsFinalized()) {
-      ASSERT(other_type_param.IsFunctionTypeParameter());  // Checked above.
-      // To be equivalent, the function type parameters should be declared
-      // at the same position in the generic function. Their index therefore
-      // needs adjustement before comparison.
-      // Example: 'foo<F>(bar<B>(B b)) { }' and 'baz<Z>(Z z) { }', baz can
-      // be assigned to bar, although B has index 1 and Z index 0.
-      const Function& sig_fun = Function::Handle(parameterized_function());
-      const Function& other_sig_fun =
-          Function::Handle(other_type_param.parameterized_function());
-      const int offset = sig_fun.NumParentTypeParameters();
-      const int other_offset = other_sig_fun.NumParentTypeParameters();
-      return index() - offset == other_type_param.index() - other_offset;
-    } else if (IsFinalized() == other_type_param.IsFinalized()) {
-      return index() == other_type_param.index();
-    }
-    return false;
+  return true;
+}
+
+bool TypeParameter::IsRecursive(TrailPtr trail) const {
+  if (TestAndAddToTrail(&trail)) {
+    return true;
   }
-  if (IsFinalized() == other_type_param.IsFinalized()) {
-    return index() == other_type_param.index();
+  AbstractType& type = AbstractType::Handle();
+  type = bound();
+  if (type.IsRecursive(trail)) {
+    return true;
   }
-  return name() == other_type_param.name();
+  type = default_argument();
+  if (type.IsRecursive(trail)) {
+    return true;
+  }
+  return false;
 }
 
 void TypeParameter::set_parameterized_class(const Class& value) const {
@@ -20700,7 +20927,11 @@
   if (!value.IsNull()) {
     cid = value.id();
   }
-  StoreNonPointer(&raw_ptr()->parameterized_class_id_, cid);
+  set_parameterized_class_id(cid);
+}
+
+void TypeParameter::set_parameterized_class_id(classid_t value) const {
+  StoreNonPointer(&raw_ptr()->parameterized_class_id_, value);
 }
 
 classid_t TypeParameter::parameterized_class_id() const {
@@ -20709,19 +20940,22 @@
 
 ClassPtr TypeParameter::parameterized_class() const {
   classid_t cid = parameterized_class_id();
-  if (cid == kFunctionCid) {
+  // A canonicalized class type parameter does not refer to its class anymore.
+  if (cid == kClassCid || cid == kFunctionCid) {
     return Class::null();
   }
   return IsolateGroup::Current()->class_table()->At(cid);
 }
 
-void TypeParameter::set_parameterized_function(const Function& value) const {
-  raw_ptr()->set_parameterized_function(value.raw());
+void TypeParameter::set_base(intptr_t value) const {
+  ASSERT(value >= 0);
+  ASSERT(Utils::IsUint(16, value));
+  StoreNonPointer(&raw_ptr()->base_, value);
 }
 
 void TypeParameter::set_index(intptr_t value) const {
   ASSERT(value >= 0);
-  ASSERT(Utils::IsInt(16, value));
+  ASSERT(Utils::IsUint(16, value));
   StoreNonPointer(&raw_ptr()->index_, value);
 }
 
@@ -20731,10 +20965,12 @@
 }
 
 void TypeParameter::set_bound(const AbstractType& value) const {
+  ASSERT(!IsCanonical());
   raw_ptr()->set_bound(value.raw());
 }
 
 void TypeParameter::set_default_argument(const AbstractType& value) const {
+  ASSERT(!IsCanonical());
   raw_ptr()->set_default_argument(value.raw());
 }
 
@@ -20754,9 +20990,9 @@
     intptr_t num_free_fun_type_params,
     Heap::Space space,
     TrailPtr trail) const {
-  ASSERT(IsFinalized());
   AbstractType& result = AbstractType::Handle();
   if (IsFunctionTypeParameter()) {
+    ASSERT(IsFinalized());
     if (index() >= num_free_fun_type_params) {
       // Do not instantiate the function type parameter, but possibly its bound.
       result = raw();
@@ -20764,18 +21000,21 @@
       if (!upper_bound.IsInstantiated(kAny, num_free_fun_type_params,
                                       nullptr)) {
         // Use trail to break cycles created by bound referring to type param.
-        if (OnlyBuddyInTrail(trail) == Object::null()) {
-          AddOnlyBuddyToTrail(&trail, *this);
-          upper_bound = upper_bound.InstantiateFrom(
-              instantiator_type_arguments, function_type_arguments,
-              num_free_fun_type_params, space, trail);
-          if (upper_bound.raw() == Type::NeverType()) {
-            // Normalize 'X extends Never' to 'Never'.
-            result = Type::NeverType();
-          } else if (upper_bound.raw() != bound()) {
-            result ^= Object::Clone(result, space);
-            TypeParameter::Cast(result).set_bound(upper_bound);
-          }
+        // The instantiation trail must contain pairs, so add itself as buddy.
+        if (TestAndAddBuddyToTrail(&trail, *this)) {
+          // If the type parameter is already in the trail, it is returned
+          // unchanged here and will be processed when returning from recursion.
+          return raw();
+        }
+        upper_bound = upper_bound.InstantiateFrom(
+            instantiator_type_arguments, function_type_arguments,
+            num_free_fun_type_params, space, trail);
+        if (upper_bound.raw() == Type::NeverType()) {
+          // Normalize 'X extends Never' to 'Never'.
+          result = Type::NeverType();
+        } else if (upper_bound.raw() != bound()) {
+          result ^= Object::Clone(result, space);
+          TypeParameter::Cast(result).set_bound(upper_bound);
         }
       }
     } else if (function_type_arguments.IsNull()) {
@@ -20786,6 +21025,7 @@
     }
   } else {
     ASSERT(IsClassTypeParameter());
+    ASSERT(IsFinalized() || IsBeingFinalized());
     if (instantiator_type_arguments.IsNull()) {
       return Type::DynamicType();
     }
@@ -20811,40 +21051,66 @@
 AbstractTypePtr TypeParameter::Canonicalize(Thread* thread,
                                             TrailPtr trail) const {
   ASSERT(IsFinalized());
+  Zone* zone = thread->zone();
   if (IsCanonical()) {
+#ifdef DEBUG
+    // Verify that all fields are allocated in old space and are canonical.
+    AbstractType& type = AbstractType::Handle(zone);
+    type = bound();
+    ASSERT(type.IsOld());
+    ASSERT(type.IsCanonical());
+    type = default_argument();
+    ASSERT(type.IsOld());
+    ASSERT(type.IsCanonical());
+#endif
     return this->raw();
   }
-  Zone* zone = thread->zone();
   auto isolate_group = thread->isolate_group();
-
-  const Class& cls = Class::Handle(zone, parameterized_class());
-  const Function& function = Function::Handle(
-      zone, cls.IsNull() ? parameterized_function() : Function::null());
-  const TypeArguments& type_params = TypeArguments::Handle(
-      zone, cls.IsNull() ? function.type_parameters() : cls.type_parameters());
-  const intptr_t offset =
-      cls.IsNull() ? function.NumParentTypeParameters()
-                   : (cls.NumTypeArguments() - cls.NumTypeParameters());
-  TypeParameter& type_parameter = TypeParameter::Handle(zone);
-  type_parameter ^= type_params.TypeAt(index() - offset);
-  ASSERT(!type_parameter.IsNull());
-  if (type_parameter.nullability() == nullability()) {
-    ASSERT(this->Equals(type_parameter));
-    ASSERT(type_parameter.IsCanonical());
-    ASSERT(type_parameter.IsDeclaration());
-    ASSERT(type_parameter.IsOld());
-    return type_parameter.raw();
-  }
-
   ObjectStore* object_store = isolate_group->object_store();
+  TypeParameter& type_parameter = TypeParameter::Handle(zone);
   {
     SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex());
     CanonicalTypeParameterSet table(zone,
                                     object_store->canonical_type_parameters());
     type_parameter ^= table.GetOrNull(CanonicalTypeParameterKey(*this));
+    ASSERT(object_store->canonical_type_parameters() == table.Release().raw());
+  }
+  if (type_parameter.IsNull()) {
+    // The type parameter was not found in the table. It is not canonical yet.
+    // Canonicalize its bound and default argument.
+    // However, if the type parameter is already being canonicalized, it is part
+    // of a cycle via its bound. Return it now and let the caller finish
+    // canonicalizing it.
+    if (TestAndAddToTrail(&trail)) {
+      return raw();
+    }
+    AbstractType& type = AbstractType::Handle(zone);
+    type = bound();
+    type = type.Canonicalize(thread, trail);
+    if (IsCanonical()) {
+      // Canonicalizing bound or default argument canonicalized this type
+      // parameter as a side effect.
+      ASSERT(IsRecursive());  // Self-referring bound or default argument.
+      return raw();
+    }
+    set_bound(type);
+    type = default_argument();
+    type = type.Canonicalize(thread, trail);
+    if (IsCanonical()) {
+      // Canonicalizing bound or default argument canonicalized this type
+      // parameter as a side effect.
+      ASSERT(IsRecursive());  // Self-referring bound or default argument.
+      return this->raw();
+    }
+    set_default_argument(type);
+    // Check to see if the type parameter got added to canonical table as part
+    // of the canonicalization of its bound and default argument.
+    SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex());
+    CanonicalTypeParameterSet table(zone,
+                                    object_store->canonical_type_parameters());
+    type_parameter ^= table.GetOrNull(CanonicalTypeParameterKey(*this));
     if (type_parameter.IsNull()) {
-      // The type parameter was not found in the table. It is not canonical yet.
-      // Add this type parameter into the canonical list of type parameters.
+      // Add this type parameter into the canonical table of type parameters.
       if (this->IsNew()) {
         type_parameter ^= Object::Clone(*this, Heap::kOld);
       } else {
@@ -20857,7 +21123,6 @@
     }
     object_store->set_canonical_type_parameters(table.Release());
   }
-  ASSERT(!type_parameter.IsDeclaration());
   return type_parameter.raw();
 }
 
@@ -20866,24 +21131,7 @@
   Zone* zone = thread->zone();
   auto isolate_group = thread->isolate_group();
 
-  const Class& cls = Class::Handle(zone, parameterized_class());
-  const Function& function = Function::Handle(
-      zone, cls.IsNull() ? parameterized_function() : Function::null());
-  const TypeArguments& type_params = TypeArguments::Handle(
-      zone, cls.IsNull() ? function.type_parameters() : cls.type_parameters());
-  const intptr_t offset =
-      IsFinalized()
-          ? (cls.IsNull() ? function.NumParentTypeParameters()
-                          : (cls.NumTypeArguments() - cls.NumTypeParameters()))
-          : 0;
   TypeParameter& type_parameter = TypeParameter::Handle(zone);
-  type_parameter ^= type_params.TypeAt(index() - offset);
-  ASSERT(!type_parameter.IsNull());
-  if (type_parameter.nullability() == nullability()) {
-    ASSERT(type_parameter.IsCanonical());
-    return (raw() == type_parameter.raw());
-  }
-
   ObjectStore* object_store = isolate_group->object_store();
   {
     SafepointMutexLocker ml(isolate_group->type_canonicalization_mutex());
@@ -20896,41 +21144,26 @@
 }
 #endif  // DEBUG
 
-void TypeParameter::EnumerateURIs(URIs* uris) const {
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
-  GrowableHandlePtrArray<const String> pieces(zone, 4);
-  pieces.Add(String::Handle(zone, name()));
-  Class& cls = Class::Handle(zone, parameterized_class());
-  if (cls.IsNull()) {
-    const Function& fun = Function::Handle(zone, parameterized_function());
-    pieces.Add(Symbols::SpaceOfSpace());
-    pieces.Add(String::Handle(zone, fun.UserVisibleName()));
-    cls = fun.Owner();  // May be null.
-    // TODO(regis): Should we keep the function owner for better error messages?
-  }
-  if (!cls.IsNull()) {
-    pieces.Add(Symbols::SpaceOfSpace());
-    pieces.Add(String::Handle(zone, cls.UserVisibleName()));
-    const String& name =
-        String::Handle(zone, Symbols::FromConcatAll(thread, pieces));
-    const Library& library = Library::Handle(zone, cls.library());
-    const String& uri = String::Handle(zone, library.url());
-    AddURI(uris, name, uri);
-  }
-}
-
 intptr_t TypeParameter::ComputeHash() const {
-  ASSERT(IsFinalized());
-  uint32_t result;
-  if (IsClassTypeParameter()) {
-    result = parameterized_class_id();
+  ASSERT(IsFinalized() || IsBeingFinalized());  // Bound may not be finalized.
+  uint32_t result = parameterized_class_id();
+  // Hashing the bound reduces collisions, but may also create cycles.
+  // Therefore, we only hash the type_class_id of the bound,
+  // and do not use its full hash, as we do for TypeRef.
+  const AbstractType& upper_bound = AbstractType::Handle(bound());
+  if (upper_bound.IsTypeParameter()) {
+    ASSERT(upper_bound.IsFinalized() || upper_bound.IsBeingFinalized());
+    result = CombineHashes(result, TypeParameter::Cast(upper_bound).index());
   } else {
-    result = Function::Handle(parameterized_function()).Hash();
+    // Note that the bound may not be finalized yet.
+    result = CombineHashes(result, upper_bound.type_class_id());
   }
-  // No need to include the hash of the bound, since the type parameter is fully
-  // identified by its class and index.
+  // Since the default argument is ignored when comparing two generic function
+  // types for type equality, the hash does not depend on it.
+  result = CombineHashes(result, IsGenericCovariantImpl() ? 1 : 0);
+  result = CombineHashes(result, base());
   result = CombineHashes(result, index());
+  result = CombineHashes(result, String::Handle(name()).Hash());
   // A legacy type should have the same hash as its non-nullable version to be
   // consistent with the definition of type equality in Dart code.
   Nullability type_param_nullability = nullability();
@@ -20950,61 +21183,41 @@
 }
 
 TypeParameterPtr TypeParameter::New(const Class& parameterized_class,
-                                    const Function& parameterized_function,
+                                    intptr_t base,
                                     intptr_t index,
                                     const String& name,
                                     const AbstractType& bound,
                                     bool is_generic_covariant_impl,
-                                    Nullability nullability,
-                                    TokenPosition token_pos) {
-  ASSERT(parameterized_class.IsNull() != parameterized_function.IsNull());
+                                    Nullability nullability) {
   Zone* Z = Thread::Current()->zone();
   const TypeParameter& result = TypeParameter::Handle(Z, TypeParameter::New());
   result.set_parameterized_class(parameterized_class);
-  result.set_parameterized_function(parameterized_function);
+  result.set_base(base);
   result.set_index(index);
   result.set_name(name);
   result.set_bound(bound);
+  result.set_default_argument(Object::dynamic_type());
   result.set_flags(0);
   result.set_nullability(nullability);
   result.SetGenericCovariantImpl(is_generic_covariant_impl);
-  result.SetDeclaration(false);
   result.SetHash(0);
-  result.set_token_pos(token_pos);
 
   result.SetTypeTestingStub(
       Code::Handle(Z, TypeTestingStubGenerator::DefaultCodeForType(result)));
   return result.raw();
 }
 
-void TypeParameter::set_token_pos(TokenPosition token_pos) const {
-  ASSERT(!token_pos.IsClassifying());
-  StoreNonPointer(&raw_ptr()->token_pos_, token_pos);
-}
-
 void TypeParameter::set_flags(uint8_t flags) const {
   StoreNonPointer(&raw_ptr()->flags_, flags);
 }
 
 const char* TypeParameter::ToCString() const {
   Thread* thread = Thread::Current();
-  ZoneTextBuffer printer(thread->zone());
-  auto& name_str = String::Handle(thread->zone(), name());
-  printer.Printf("TypeParameter: name ");
-  printer.AddString(name_str.ToCString());
+  Zone* zone = thread->zone();
+  ZoneTextBuffer printer(zone);
+  printer.Printf("TypeParameter: ");
+  printer.AddString(String::Handle(zone, name()).ToCString());
   printer.AddString(NullabilitySuffix(kInternalName));
-  printer.Printf("; index: %" Pd ";", index());
-  if (IsFunctionTypeParameter()) {
-    const Function& function = Function::Handle(parameterized_function());
-    printer.Printf(" function: ");
-    name_str = function.name();
-    printer.AddString(name_str.ToCString());
-  } else {
-    const Class& cls = Class::Handle(parameterized_class());
-    printer.Printf(" class: ");
-    name_str = cls.Name();
-    printer.AddString(name_str.ToCString());
-  }
   printer.Printf("; bound: ");
   const AbstractType& upper_bound = AbstractType::Handle(bound());
   if (upper_bound.IsNull()) {
@@ -21012,6 +21225,15 @@
   } else {
     upper_bound.PrintName(kInternalName, &printer);
   }
+  if (FLAG_show_internal_names) {
+    printer.Printf("; default: ");
+    const AbstractType& default_arg = AbstractType::Handle(default_argument());
+    if (default_arg.IsNull()) {
+      printer.AddString("<null>");
+    } else {
+      default_arg.PrintName(kInternalName, &printer);
+    }
+  }
   return printer.buffer();
 }
 
@@ -22334,6 +22556,9 @@
 }
 
 const char* String::ToCString() const {
+  if (IsNull()) {
+    return "String: null";
+  }
   const intptr_t len = Utf8::Length(*this);
   Zone* zone = Thread::Current()->zone();
   uint8_t* result = zone->Alloc<uint8_t>(len + 1);
@@ -24052,7 +24277,7 @@
     return 0;
   } else {
     const auto& closure_function = Function::Handle(thread->zone(), function());
-    return closure_function.NumTypeParameters(thread);
+    return closure_function.NumTypeParameters();
   }
 }
 
@@ -24062,9 +24287,9 @@
   ZoneTextBuffer buffer(zone);
   buffer.AddString("Closure: ");
   const Function& fun = Function::Handle(zone, function());
-  const Function& sig_fun =
-      Function::Handle(zone, GetInstantiatedSignature(zone));
-  sig_fun.PrintSignature(NameVisibility::kUserVisibleName, &buffer);
+  const FunctionType& sig =
+      FunctionType::Handle(zone, GetInstantiatedSignature(zone));
+  sig.Print(kUserVisibleName, &buffer);
   if (fun.IsImplicitClosureFunction()) {
     buffer.Printf(" from %s", fun.ToCString());
   }
@@ -24145,8 +24370,9 @@
   return static_cast<ClosurePtr>(raw);
 }
 
-FunctionPtr Closure::GetInstantiatedSignature(Zone* zone) const {
-  Function& sig_fun = Function::Handle(zone, function());
+FunctionTypePtr Closure::GetInstantiatedSignature(Zone* zone) const {
+  Function& fun = Function::Handle(zone, function());
+  FunctionType& sig = FunctionType::Handle(zone, fun.signature());
   TypeArguments& fn_type_args =
       TypeArguments::Handle(zone, function_type_arguments());
   const TypeArguments& delayed_type_args =
@@ -24160,17 +24386,17 @@
   if (delayed_type_args.raw() != Object::empty_type_arguments().raw()) {
     num_free_params = kCurrentAndEnclosingFree;
     fn_type_args = delayed_type_args.Prepend(
-        zone, fn_type_args, sig_fun.NumParentTypeParameters(),
-        sig_fun.NumTypeParameters() + sig_fun.NumParentTypeParameters());
+        zone, fn_type_args, sig.NumParentTypeArguments(),
+        sig.NumTypeParameters() + sig.NumParentTypeArguments());
   } else {
     num_free_params = kAllFree;
   }
   if (num_free_params == kCurrentAndEnclosingFree ||
-      !sig_fun.HasInstantiatedSignature(kAny)) {
-    return sig_fun.InstantiateSignatureFrom(inst_type_args, fn_type_args,
-                                            num_free_params, Heap::kOld);
+      !sig.IsInstantiated(kAny)) {
+    sig ^= sig.InstantiateFrom(inst_type_args, fn_type_args, num_free_params,
+                               Heap::kOld);
   }
-  return sig_fun.raw();
+  return sig.raw();
 }
 
 bool StackTrace::skip_sync_start_in_parent_stack() const {
@@ -24694,6 +24920,11 @@
   return Function::Cast(Object::Handle(referent())).raw();
 }
 
+FunctionTypePtr MirrorReference::GetFunctionTypeReferent() const {
+  ASSERT(Object::Handle(referent()).IsFunctionType());
+  return FunctionType::Cast(Object::Handle(referent())).raw();
+}
+
 LibraryPtr MirrorReference::GetLibraryReferent() const {
   ASSERT(Object::Handle(referent()).IsLibrary());
   return Library::Cast(Object::Handle(referent())).raw();
@@ -24856,6 +25087,14 @@
   table.Release();
 }
 
+void DumpFunctionTypeTable(Isolate* isolate) {
+  OS::PrintErr("canonical function types:\n");
+  CanonicalFunctionTypeSet table(
+      isolate->group()->object_store()->canonical_function_types());
+  table.Dump();
+  table.Release();
+}
+
 void DumpTypeParameterTable(Isolate* isolate) {
   OS::PrintErr("canonical type parameters (cloned from declarations):\n");
   CanonicalTypeParameterSet table(
@@ -24945,22 +25184,7 @@
   }
 #endif
   if (!is_marked_entrypoint) {
-    const char* member_cstring =
-        member.IsFunction()
-            ? OS::SCreate(
-                  Thread::Current()->zone(), "%s (kind %s)",
-                  Function::Cast(member).ToLibNamePrefixedQualifiedCString(),
-                  Function::KindToCString(Function::Cast(member).kind()))
-            : member.ToCString();
-    char const* error = OS::SCreate(
-        Thread::Current()->zone(),
-        "ERROR: It is illegal to access '%s' through Dart C API.\n"
-        "ERROR: See "
-        "https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/"
-        "aot/entry_point_pragma.md\n",
-        member_cstring);
-    OS::PrintErr("%s", error);
-    return ApiError::New(String::Handle(String::New(error)));
+    return EntryPointMemberInvocationError(member);
   }
   return Error::null();
 }
@@ -24981,6 +25205,26 @@
   return ApiError::New(String::Handle(String::New(error)));
 }
 
+DART_WARN_UNUSED_RESULT
+ErrorPtr EntryPointMemberInvocationError(const Object& member) {
+  const char* member_cstring =
+      member.IsFunction()
+          ? OS::SCreate(
+                Thread::Current()->zone(), "%s (kind %s)",
+                Function::Cast(member).ToLibNamePrefixedQualifiedCString(),
+                Function::KindToCString(Function::Cast(member).kind()))
+          : member.ToCString();
+  char const* error = OS::SCreate(
+      Thread::Current()->zone(),
+      "ERROR: It is illegal to access '%s' through Dart C API.\n"
+      "ERROR: See "
+      "https://github.com/dart-lang/sdk/blob/master/runtime/docs/compiler/"
+      "aot/entry_point_pragma.md\n",
+      member_cstring);
+  OS::PrintErr("%s", error);
+  return ApiError::New(String::Handle(String::New(error)));
+}
+
 ErrorPtr Function::VerifyCallEntryPoint() const {
   if (!FLAG_verify_entry_points) return Error::null();
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 31f2632..1b8150e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -409,10 +409,12 @@
   // propagation constants.
 #define SHARED_READONLY_HANDLES_LIST(V)                                        \
   V(Object, null_object)                                                       \
+  V(Class, null_class)                                                         \
   V(Array, null_array)                                                         \
   V(String, null_string)                                                       \
   V(Instance, null_instance)                                                   \
   V(Function, null_function)                                                   \
+  V(FunctionType, null_function_type)                                          \
   V(TypeArguments, null_type_arguments)                                        \
   V(CompressedStackMaps, null_compressed_stackmaps)                            \
   V(TypeArguments, empty_type_arguments)                                       \
@@ -462,7 +464,6 @@
   static ClassPtr patch_class_class() { return patch_class_class_; }
   static ClassPtr function_class() { return function_class_; }
   static ClassPtr closure_data_class() { return closure_data_class_; }
-  static ClassPtr signature_data_class() { return signature_data_class_; }
   static ClassPtr ffi_trampoline_data_class() {
     return ffi_trampoline_data_class_;
   }
@@ -764,7 +765,6 @@
   static ClassPtr patch_class_class_;     // Class of the PatchClass vm object.
   static ClassPtr function_class_;        // Class of the Function vm object.
   static ClassPtr closure_data_class_;    // Class of ClosureData vm obj.
-  static ClassPtr signature_data_class_;  // Class of SignatureData vm obj.
   static ClassPtr ffi_trampoline_data_class_;  // Class of FfiTrampolineData
                                                // vm obj.
   static ClassPtr field_class_;                // Class of the Field vm object.
@@ -878,7 +878,7 @@
 // The third string in the triplet is "print" if the triplet should be printed.
 typedef ZoneGrowableHandlePtrArray<const String> URIs;
 
-enum class Nullability : int8_t {
+enum class Nullability : uint8_t {
   kNullable = 0,
   kNonNullable = 1,
   kLegacy = 2,
@@ -1044,12 +1044,6 @@
 
   int32_t SourceFingerprint() const;
 
-  // This class represents a typedef if the signature function is not null.
-  FunctionPtr signature_function() const {
-    return raw_ptr()->signature_function();
-  }
-  void set_signature_function(const Function& value) const;
-
   // Return the Type with type parameters declared by this class filled in with
   // dynamic and type parameters declared in superclasses filled in as declared
   // in superclass clauses.
@@ -1236,9 +1230,6 @@
     return cls->ptr()->id_ == kClosureCid;
   }
 
-  // Check if this class represents a typedef class.
-  bool IsTypedefClass() const { return signature_function() != Object::null(); }
-
   static bool IsInFullSnapshot(ClassPtr cls) {
     NoSafepointScope no_safepoint;
     return LibraryLayout::InFullSnapshotBit::decode(
@@ -2458,27 +2449,13 @@
 
   StringPtr GetSource() const;
 
-  // Return the type of this function's signature. It may not be canonical yet.
-  // For example, if this function has a signature of the form
-  // '(T, [B, C]) => R', where 'T' and 'R' are type parameters of the
-  // owner class of this function, then its signature type is a parameterized
-  // function type with uninstantiated type arguments 'T' and 'R' as elements of
-  // its type argument vector.
-  // A function type is non-nullable by default.
-  TypePtr SignatureType(
-      Nullability nullability = Nullability::kNonNullable) const;
-  TypePtr ExistingSignatureType() const;
-
-  // Update the signature type (with a canonical version).
-  void SetSignatureType(const Type& value) const;
-
-  // Set the "C signature" function for an FFI trampoline.
+  // Set the "C signature" for an FFI trampoline.
   // Can only be used on FFI trampolines.
-  void SetFfiCSignature(const Function& sig) const;
+  void SetFfiCSignature(const FunctionType& sig) const;
 
-  // Retrieves the "C signature" function for an FFI trampoline.
+  // Retrieves the "C signature" for an FFI trampoline.
   // Can only be used on FFI trampolines.
-  FunctionPtr FfiCSignature() const;
+  FunctionTypePtr FfiCSignature() const;
 
   bool FfiCSignatureContainsHandles() const;
   bool FfiCSignatureReturnsStruct() const;
@@ -2504,18 +2481,18 @@
   // Can only be called on FFI trampolines.
   void SetFfiCallbackExceptionalReturn(const Instance& value) const;
 
-  // Return a new function with instantiated result and parameter types.
-  FunctionPtr InstantiateSignatureFrom(
-      const TypeArguments& instantiator_type_arguments,
-      const TypeArguments& function_type_arguments,
-      intptr_t num_free_fun_type_params,
-      Heap::Space space) const;
+  // Return the signature of this function.
+  FunctionTypePtr signature() const { return raw_ptr()->signature(); }
+  void set_signature(const FunctionType& value) const;
+  static intptr_t signature_offset() {
+    return OFFSET_OF(FunctionLayout, signature_);
+  }
 
   // Build a string of the form '<T>(T, {B b, C c}) => R' representing the
   // internal signature of the given function. In this example, T is a type
   // parameter of this function and R is a type parameter of class C, the owner
   // of the function. B and C are not type parameters.
-  StringPtr Signature() const;
+  StringPtr InternalSignature() const;
 
   // Build a string of the form '<T>(T, {B b, C c}) => R' representing the
   // user visible signature of the given function. In this example, T is a type
@@ -2524,9 +2501,6 @@
   // Implicit parameters are hidden.
   StringPtr UserVisibleSignature() const;
 
-  void PrintSignature(NameVisibility name_visibility,
-                      BaseTextBuffer* printer) const;
-
   // Returns true if the signature of this function is instantiated, i.e. if it
   // does not involve generic parameter types or generic result type.
   // Note that function type parameters declared by this function do not make
@@ -2557,18 +2531,16 @@
   StringPtr native_name() const;
   void set_native_name(const String& name) const;
 
-  AbstractTypePtr result_type() const { return raw_ptr()->result_type(); }
-  void set_result_type(const AbstractType& value) const;
+  AbstractTypePtr result_type() const {
+    return raw_ptr()->signature()->ptr()->result_type();
+  }
 
   // The parameters, starting with NumImplicitParameters() parameters which are
   // only visible to the VM, but not to Dart users.
   // Note that type checks exclude implicit parameters.
   AbstractTypePtr ParameterTypeAt(intptr_t index) const;
-  void SetParameterTypeAt(intptr_t index, const AbstractType& value) const;
-  ArrayPtr parameter_types() const { return raw_ptr()->parameter_types(); }
-  void set_parameter_types(const Array& value) const;
-  static intptr_t parameter_types_offset() {
-    return OFFSET_OF(FunctionLayout, parameter_types_);
+  ArrayPtr parameter_types() const {
+    return raw_ptr()->signature()->ptr()->parameter_types();
   }
 
   // Parameter names are valid for all valid parameter indices, and are not
@@ -2577,54 +2549,36 @@
   // array isn't necessarily NumParameters(), but the first NumParameters()
   // elements are the names.
   StringPtr ParameterNameAt(intptr_t index) const;
-  void SetParameterNameAt(intptr_t index, const String& value) const;
   ArrayPtr parameter_names() const { return raw_ptr()->parameter_names(); }
+  void SetParameterNamesFrom(const FunctionType& signature) const;
   static intptr_t parameter_names_offset() {
     return OFFSET_OF(FunctionLayout, parameter_names_);
   }
 
-  // Sets up the function's parameter name array, including appropriate space
-  // for any possible parameter flags. This may be an overestimate if some
-  // parameters don't have flags, and so TruncateUnusedParameterFlags() should
-  // be called after all parameter flags have been appropriately set.
-  //
-  // Assumes that the number of fixed and optional parameters for the function
-  // has already been set.
-  void CreateNameArrayIncludingFlags(Heap::Space space) const;
-
-  // Truncate the parameter names array to remove any unused flag slots. Make
-  // sure to only do this after calling SetIsRequiredAt as necessary.
-  void TruncateUnusedParameterFlags() const;
-
   // The required flags are stored at the end of the parameter_names. The flags
-  // are packed into Smis.
+  // are packed into SMIs, but omitted if they're 0.
   bool IsRequiredAt(intptr_t index) const;
-  void SetIsRequiredAt(intptr_t index) const;
 
   // The type parameters (and their bounds) are specified as an array of
-  // TypeParameter.
+  // TypeParameter stored in the signature. They are part of the function type.
   TypeArgumentsPtr type_parameters() const {
-    return raw_ptr()->type_parameters();
+    return raw_ptr()->signature()->ptr()->type_parameters();
   }
-  void set_type_parameters(const TypeArguments& value) const;
-  static intptr_t type_parameters_offset() {
-    return OFFSET_OF(FunctionLayout, type_parameters_);
-  }
-  intptr_t NumTypeParameters(Thread* thread) const;
+
   intptr_t NumTypeParameters() const {
-    return NumTypeParameters(Thread::Current());
+    return FunctionLayout::PackedNumTypeParameters::decode(
+        raw_ptr()->packed_fields_);
   }
+  void SetNumTypeParameters(intptr_t value) const;
 
-  // Returns true if this function has the same number of type parameters with
-  // equal bounds as the other function. Type parameter names are ignored.
-  bool HasSameTypeParametersAndBounds(const Function& other,
-                                      TypeEquality kind) const;
+  // Return the cumulative number of type arguments in all parent functions.
+  intptr_t NumParentTypeArguments() const;
 
-  // Return the number of type parameters declared in parent generic functions.
-  intptr_t NumParentTypeParameters() const;
-
-  // Print the signature type of this function and of all of its parents.
-  void PrintSignatureTypes() const;
+  // Return the cumulative number of type arguments in all parent functions and
+  // own type arguments.
+  intptr_t NumTypeArguments() const {
+    return NumParentTypeArguments() + NumTypeParameters();
+  }
 
   // Return a TypeParameter if the type_name is a type parameter of this
   // function or of one of its parent functions.
@@ -2634,8 +2588,8 @@
                                        intptr_t* function_level) const;
 
   // Return true if this function declares type parameters.
-  bool IsGeneric() const { return NumTypeParameters(Thread::Current()) > 0; }
-
+  // Generic dispatchers only set the number without actual type parameters.
+  bool IsGeneric() const { return NumTypeParameters() > 0; }
   // Return true if any parent function of this function is generic.
   bool HasGenericParent() const;
 
@@ -2685,10 +2639,6 @@
 
   static intptr_t code_offset() { return OFFSET_OF(FunctionLayout, code_); }
 
-  static intptr_t result_type_offset() {
-    return OFFSET_OF(FunctionLayout, result_type_);
-  }
-
   static intptr_t entry_point_offset(
       CodeEntryKind entry_kind = CodeEntryKind::kNormal) {
     switch (entry_kind) {
@@ -2744,6 +2694,7 @@
                DefaultTypeArgumentsKind,
                0,
                kDefaultTypeArgumentsKindFieldSize>;
+  // TODO(regis): Rename to NumParentTypeArgumentsField.
   // Just use the rest of the space for the number of parent type parameters.
   using NumParentTypeParametersField =
       BitField<intptr_t,
@@ -2896,7 +2847,6 @@
         return true;
       case FunctionLayout::kClosureFunction:
       case FunctionLayout::kImplicitClosureFunction:
-      case FunctionLayout::kSignatureFunction:
       case FunctionLayout::kConstructor:
       case FunctionLayout::kImplicitStaticGetter:
       case FunctionLayout::kFieldInitializer:
@@ -2923,7 +2873,6 @@
         return true;
       case FunctionLayout::kClosureFunction:
       case FunctionLayout::kImplicitClosureFunction:
-      case FunctionLayout::kSignatureFunction:
       case FunctionLayout::kConstructor:
       case FunctionLayout::kMethodExtractor:
       case FunctionLayout::kNoSuchMethodDispatcher:
@@ -2978,17 +2927,6 @@
   // Returns the size of the source for this function.
   intptr_t SourceSize() const;
 
-  intptr_t num_fixed_parameters() const {
-    return FunctionLayout::PackedNumFixedParameters::decode(
-        raw_ptr()->packed_fields_);
-  }
-  void set_num_fixed_parameters(intptr_t value) const;
-
-  uint32_t packed_fields() const { return raw_ptr()->packed_fields_; }
-  void set_packed_fields(uint32_t packed_fields) const;
-  static intptr_t packed_fields_offset() {
-    return OFFSET_OF(FunctionLayout, packed_fields_);
-  }
   // Reexported so they can be used by the flow graph builders.
   using PackedHasNamedOptionalParameters =
       FunctionLayout::PackedHasNamedOptionalParameters;
@@ -2996,25 +2934,40 @@
   using PackedNumOptionalParameters =
       FunctionLayout::PackedNumOptionalParameters;
 
+  uint32_t packed_fields() const { return raw_ptr()->packed_fields_; }
+  void set_packed_fields(uint32_t packed_fields) const;
+  static intptr_t packed_fields_offset() {
+    return OFFSET_OF(FunctionLayout, packed_fields_);
+  }
+
+  intptr_t num_fixed_parameters() const {
+    return FunctionLayout::PackedNumFixedParameters::decode(
+        raw_ptr()->packed_fields_);
+  }
+  void set_num_fixed_parameters(intptr_t value) const;
+
   bool HasOptionalParameters() const {
-    return PackedNumOptionalParameters::decode(raw_ptr()->packed_fields_) > 0;
+    return FunctionLayout::PackedNumOptionalParameters::decode(
+               raw_ptr()->packed_fields_) > 0;
   }
   bool HasOptionalNamedParameters() const {
     return HasOptionalParameters() &&
-           PackedHasNamedOptionalParameters::decode(raw_ptr()->packed_fields_);
+           FunctionLayout::PackedHasNamedOptionalParameters::decode(
+               raw_ptr()->packed_fields_);
   }
+  bool HasRequiredNamedParameters() const;
   bool HasOptionalPositionalParameters() const {
     return HasOptionalParameters() && !HasOptionalNamedParameters();
   }
   intptr_t NumOptionalParameters() const {
-    return PackedNumOptionalParameters::decode(raw_ptr()->packed_fields_);
+    return FunctionLayout::PackedNumOptionalParameters::decode(
+        raw_ptr()->packed_fields_);
   }
-  void SetNumOptionalParameters(intptr_t num_optional_parameters,
-                                bool are_optional_positional) const;
-
   intptr_t NumOptionalPositionalParameters() const {
     return HasOptionalPositionalParameters() ? NumOptionalParameters() : 0;
   }
+  void SetNumOptionalParameters(intptr_t num_optional_parameters,
+                                bool are_optional_positional) const;
 
   intptr_t NumOptionalNamedParameters() const {
     return HasOptionalNamedParameters() ? NumOptionalParameters() : 0;
@@ -3309,10 +3262,6 @@
   }
 #endif  //  !defined(DART_PRECOMPILED_RUNTIME)
 
-  // Returns true if the type of this function is a subtype of the type of
-  // the other function.
-  bool IsSubtypeOf(const Function& other, Heap::Space space) const;
-
   bool IsDispatcherOrImplicitAccessor() const {
     switch (kind()) {
       case FunctionLayout::kImplicitGetter:
@@ -3399,16 +3348,6 @@
   // Returns true if this function represents a local function.
   bool IsLocalFunction() const { return parent_function() != Function::null(); }
 
-  // Returns true if this function represents a signature function without code.
-  bool IsSignatureFunction() const {
-    return kind() == FunctionLayout::kSignatureFunction;
-  }
-  static bool IsSignatureFunction(FunctionPtr function) {
-    NoSafepointScope no_safepoint;
-    return KindBits::decode(function->ptr()->kind_tag_) ==
-           FunctionLayout::kSignatureFunction;
-  }
-
   // Returns true if this function represents an ffi trampoline.
   bool IsFfiTrampoline() const {
     return kind() == FunctionLayout::kFfiTrampoline;
@@ -3537,7 +3476,8 @@
     return RoundedAllocationSize(sizeof(FunctionLayout));
   }
 
-  static FunctionPtr New(const String& name,
+  static FunctionPtr New(const FunctionType& signature,
+                         const String& name,
                          FunctionLayout::Kind kind,
                          bool is_static,
                          bool is_const,
@@ -3566,18 +3506,6 @@
                                                 const Function& parent,
                                                 TokenPosition token_pos);
 
-  // Allocates a new Function object representing a signature function.
-  // The owner is the scope class of the function type.
-  // The parent is the enclosing function or null if none.
-  static FunctionPtr NewSignatureFunction(const Object& owner,
-                                          const Function& parent,
-                                          TokenPosition token_pos,
-                                          Heap::Space space = Heap::kOld);
-
-  static FunctionPtr NewEvalFunction(const Class& owner,
-                                     const Script& script,
-                                     bool is_static);
-
   FunctionPtr CreateMethodExtractor(const String& getter_name) const;
   FunctionPtr GetMethodExtractor(const String& getter_name) const;
 
@@ -3723,22 +3651,22 @@
   //              some functions known to be execute infrequently and functions
   //              which have been de-optimized too many times.
   bool is_optimizable() const {
-    return FunctionLayout::OptimizableBit::decode(raw_ptr()->packed_fields_);
+    return FunctionLayout::PackedOptimizable::decode(raw_ptr()->packed_fields_);
   }
   void set_is_optimizable(bool value) const {
-    set_packed_fields(FunctionLayout::OptimizableBit::update(
+    set_packed_fields(FunctionLayout::PackedOptimizable::update(
         value, raw_ptr()->packed_fields_));
   }
 
   // Indicates whether this function can be optimized on the background compiler
   // thread.
   bool is_background_optimizable() const {
-    return FunctionLayout::BackgroundOptimizableBit::decode(
+    return FunctionLayout::PackedBackgroundOptimizable::decode(
         raw_ptr()->packed_fields_);
   }
 
   void set_is_background_optimizable(bool value) const {
-    set_packed_fields(FunctionLayout::BackgroundOptimizableBit::update(
+    set_packed_fields(FunctionLayout::PackedBackgroundOptimizable::update(
         value, raw_ptr()->packed_fields_));
   }
 
@@ -3788,6 +3716,7 @@
       const TypeArguments& defaults) const;
 
   void set_parameter_names(const Array& value) const;
+  void set_parameter_types(const Array& value) const;
   void set_ic_data_array(const Array& value) const;
   void SetInstructionsSafe(const Code& value) const;
   void set_name(const String& value) const;
@@ -3802,36 +3731,19 @@
   void set_num_optional_parameters(intptr_t value) const;  // Encoded value.
   void set_kind_tag(uint32_t value) const;
   void set_data(const Object& value) const;
+
   static FunctionPtr New(Heap::Space space = Heap::kOld);
 
-  void PrintSignatureParameters(Thread* thread,
-                                Zone* zone,
-                                NameVisibility name_visibility,
-                                BaseTextBuffer* printer) const;
-
-  // Returns true if the type of the formal parameter at the given position in
-  // this function is contravariant with the type of the other formal parameter
-  // at the given position in the other function.
-  bool IsContravariantParameter(intptr_t parameter_position,
-                                const Function& other,
-                                intptr_t other_parameter_position,
-                                Heap::Space space) const;
-
-  // Returns the index in the parameter names array of the corresponding flag
-  // for the given parametere index. Also returns (via flag_mask) the
-  // corresponding mask within the flag.
-  intptr_t GetRequiredFlagIndex(intptr_t index, intptr_t* flag_mask) const;
-
   FINAL_HEAP_OBJECT_IMPLEMENTATION(Function, Object);
   friend class Class;
   friend class SnapshotWriter;
   friend class Parser;  // For set_eval_script.
-  friend class ProgramVisitor;  // For set_parameter_names.
   // FunctionLayout::VisitFunctionPointers accesses the private constructor of
   // Function.
   friend class FunctionLayout;
   friend class ClassFinalizer;  // To reset parent_function.
   friend class Type;            // To adjust parent_function.
+  friend class ProgramVisitor;  // For set_parameter_types/names.
 };
 
 class ClosureData : public Object {
@@ -3855,10 +3767,6 @@
   FunctionPtr parent_function() const { return raw_ptr()->parent_function_; }
   void set_parent_function(const Function& value) const;
 
-  // Signature type of this closure function.
-  TypePtr signature_type() const { return raw_ptr()->signature_type_; }
-  void set_signature_type(const Type& value) const;
-
   InstancePtr implicit_static_closure() const { return raw_ptr()->closure_; }
   void set_implicit_static_closure(const Instance& closure) const;
 
@@ -3878,29 +3786,6 @@
   friend class HeapProfiler;
 };
 
-class SignatureData : public Object {
- public:
-  static intptr_t InstanceSize() {
-    return RoundedAllocationSize(sizeof(SignatureDataLayout));
-  }
-
- private:
-  // Enclosing function of this signature function.
-  FunctionPtr parent_function() const { return raw_ptr()->parent_function(); }
-  void set_parent_function(const Function& value) const;
-
-  // Signature type of this signature function.
-  TypePtr signature_type() const { return raw_ptr()->signature_type(); }
-  void set_signature_type(const Type& value) const;
-
-  static SignatureDataPtr New(Heap::Space space = Heap::kOld);
-
-  FINAL_HEAP_OBJECT_IMPLEMENTATION(SignatureData, Object);
-  friend class Class;
-  friend class Function;
-  friend class HeapProfiler;
-};
-
 enum class EntryPointPragma {
   kAlways,
   kNever,
@@ -3916,12 +3801,8 @@
   }
 
  private:
-  // Signature type of this closure function.
-  TypePtr signature_type() const { return raw_ptr()->signature_type(); }
-  void set_signature_type(const Type& value) const;
-
-  FunctionPtr c_signature() const { return raw_ptr()->c_signature(); }
-  void set_c_signature(const Function& value) const;
+  FunctionTypePtr c_signature() const { return raw_ptr()->c_signature(); }
+  void set_c_signature(const FunctionType& value) const;
 
   FunctionPtr callback_target() const { return raw_ptr()->callback_target(); }
   void set_callback_target(const Function& value) const;
@@ -7501,12 +7382,10 @@
 
   // Print the internal or public name of a subvector of this type argument
   // vector, e.g. "<T, dynamic, List<T>, int>".
-  void PrintSubvectorName(
-      intptr_t from_index,
-      intptr_t len,
-      NameVisibility name_visibility,
-      BaseTextBuffer* printer,
-      NameDisambiguation name_disambiguation = NameDisambiguation::kNo) const;
+  void PrintSubvectorName(intptr_t from_index,
+                          intptr_t len,
+                          NameVisibility name_visibility,
+                          BaseTextBuffer* printer) const;
   void PrintTo(BaseTextBuffer* printer) const;
 
   // Check if the subvector of length 'len' starting at 'from_index' of this
@@ -7583,7 +7462,7 @@
   bool IsFinalized() const;
 
   // Return true if this vector contains a recursive type argument.
-  bool IsRecursive() const;
+  bool IsRecursive(TrailPtr trail = nullptr) const;
 
   // Caller must hold Isolate::constant_canonicalization_mutex_.
   virtual InstancePtr CanonicalizeLocked(Thread* thread) const {
@@ -7740,7 +7619,6 @@
   virtual ClassPtr type_class() const;
   virtual TypeArgumentsPtr arguments() const;
   virtual void set_arguments(const TypeArguments& value) const;
-  virtual TokenPosition token_pos() const;
   virtual bool IsInstantiated(Genericity genericity = kAny,
                               intptr_t num_free_fun_type_params = kAllFree,
                               TrailPtr trail = nullptr) const;
@@ -7754,10 +7632,7 @@
   virtual bool IsEquivalent(const Instance& other,
                             TypeEquality kind,
                             TrailPtr trail = nullptr) const;
-  virtual bool IsRecursive() const;
-
-  // Check if this type represents a function type.
-  virtual bool IsFunctionType() const { return false; }
+  virtual bool IsRecursive(TrailPtr trail = nullptr) const;
 
   // Instantiate this type using the given type argument vectors.
   //
@@ -7831,10 +7706,7 @@
 
   // Return the internal or public name of this type, including the names of its
   // type arguments, if any.
-  void PrintName(
-      NameVisibility visibility,
-      BaseTextBuffer* printer,
-      NameDisambiguation name_disambiguation = NameDisambiguation::kNo) const;
+  void PrintName(NameVisibility visibility, BaseTextBuffer* printer) const;
 
   // Add the class name and URI of each occuring type to the uris
   // list and mark ambiguous triplets to be printed.
@@ -7949,6 +7821,14 @@
 
   void SetTypeTestingStub(const Code& stub) const;
 
+  // No instances of type AbstractType are allocated, but InstanceSize() and
+  // NextFieldOffset() are required to register class _AbstractType.
+  static intptr_t InstanceSize() {
+    return RoundedAllocationSize(sizeof(AbstractTypeLayout));
+  }
+
+  static intptr_t NextFieldOffset() { return -kWordSize; }
+
  private:
   // Returns true if this type is a subtype of FutureOr<T> specified by 'other'.
   // Returns false if other type is not a FutureOr.
@@ -7966,10 +7846,6 @@
 
 // A Type consists of a class, possibly parameterized with type
 // arguments. Example: C<T1, T2>.
-//
-// Caution: 'TypePtr' denotes a 'raw' pointer to a VM object of class Type, as
-// opposed to 'Type' denoting a 'handle' to the same object. 'RawType' does not
-// relate to a 'raw type', as opposed to a 'cooked type' or 'rare type'.
 class Type : public AbstractType {
  public:
   static intptr_t type_class_id_offset() {
@@ -7990,7 +7866,6 @@
            (raw_ptr()->type_state_ == TypeLayout::kFinalizedUninstantiated);
   }
   virtual void SetIsFinalized() const;
-  void ResetIsFinalized() const;  // Ignore current state and set again.
   virtual bool IsBeingFinalized() const {
     return raw_ptr()->type_state_ == TypeLayout::kBeingFinalized;
   }
@@ -8008,32 +7883,18 @@
   void set_type_class(const Class& value) const;
   virtual TypeArgumentsPtr arguments() const { return raw_ptr()->arguments(); }
   virtual void set_arguments(const TypeArguments& value) const;
-  virtual TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
   virtual bool IsInstantiated(Genericity genericity = kAny,
                               intptr_t num_free_fun_type_params = kAllFree,
                               TrailPtr trail = nullptr) const;
   virtual bool IsEquivalent(const Instance& other,
                             TypeEquality kind,
                             TrailPtr trail = nullptr) const;
-  virtual bool IsRecursive() const;
+  virtual bool IsRecursive(TrailPtr trail = nullptr) const;
 
   // Return true if this type can be used as the declaration type of cls after
   // canonicalization (passed-in cls must match type_class()).
   bool IsDeclarationTypeOf(const Class& cls) const;
 
-  // If signature is not null, this type represents a function type. Note that
-  // the signature fully represents the type and type arguments can be ignored.
-  // However, in case of a generic typedef, they document how the typedef class
-  // was parameterized to obtain the actual signature.
-  FunctionPtr signature() const;
-  void set_signature(const Function& value) const;
-  static intptr_t signature_offset() {
-    return OFFSET_OF(TypeLayout, signature_);
-  }
-
-  virtual bool IsFunctionType() const {
-    return signature() != Function::null();
-  }
   virtual AbstractTypePtr InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
@@ -8119,18 +7980,16 @@
 
   static TypePtr New(const Class& clazz,
                      const TypeArguments& arguments,
-                     TokenPosition token_pos,
                      Nullability nullability = Nullability::kLegacy,
                      Heap::Space space = Heap::kOld);
 
  private:
   void SetHash(intptr_t value) const;
 
-  void set_token_pos(TokenPosition token_pos) const;
-  void set_type_state(int8_t state) const;
+  void set_type_state(uint8_t state) const;
   void set_nullability(Nullability value) const {
     ASSERT(!IsCanonical());
-    StoreNonPointer(&raw_ptr()->nullability_, static_cast<int8_t>(value));
+    StoreNonPointer(&raw_ptr()->nullability_, static_cast<uint8_t>(value));
   }
 
   static TypePtr New(Heap::Space space = Heap::kOld);
@@ -8141,6 +8000,240 @@
   friend class ClearTypeHashVisitor;
 };
 
+// A FunctionType represents the type of a function. It describes most of the
+// signature of a function, excluding the names of type parameters and names
+// of parameters, but includes the names of optional named parameters.
+class FunctionType : public AbstractType {
+ public:
+  static intptr_t type_state_offset() {
+    return OFFSET_OF(FunctionTypeLayout, type_state_);
+  }
+  static intptr_t hash_offset() { return OFFSET_OF(FunctionTypeLayout, hash_); }
+  static intptr_t nullability_offset() {
+    return OFFSET_OF(FunctionTypeLayout, nullability_);
+  }
+  virtual bool IsFinalized() const {
+    return (raw_ptr()->type_state_ == TypeLayout::kFinalizedInstantiated) ||
+           (raw_ptr()->type_state_ == TypeLayout::kFinalizedUninstantiated);
+  }
+  virtual void SetIsFinalized() const;
+  virtual bool IsBeingFinalized() const {
+    return raw_ptr()->type_state_ == TypeLayout::kBeingFinalized;
+  }
+  virtual void SetIsBeingFinalized() const;
+  virtual bool HasTypeClass() const { return false; }
+  virtual Nullability nullability() const {
+    return static_cast<Nullability>(raw_ptr()->nullability_);
+  }
+  FunctionTypePtr ToNullability(Nullability value, Heap::Space space) const;
+  virtual classid_t type_class_id() const { return kIllegalCid; }
+  virtual bool IsInstantiated(Genericity genericity = kAny,
+                              intptr_t num_free_fun_type_params = kAllFree,
+                              TrailPtr trail = nullptr) const;
+  virtual bool IsEquivalent(const Instance& other,
+                            TypeEquality kind,
+                            TrailPtr trail = nullptr) const;
+  virtual bool IsRecursive(TrailPtr trail = nullptr) const;
+
+  virtual AbstractTypePtr InstantiateFrom(
+      const TypeArguments& instantiator_type_arguments,
+      const TypeArguments& function_type_arguments,
+      intptr_t num_free_fun_type_params,
+      Heap::Space space,
+      TrailPtr trail = nullptr) const;
+  virtual AbstractTypePtr Canonicalize(Thread* thread, TrailPtr trail) const;
+#if defined(DEBUG)
+  // Check if type is canonical.
+  virtual bool CheckIsCanonical(Thread* thread) const;
+#endif  // DEBUG
+  virtual void EnumerateURIs(URIs* uris) const;
+
+  virtual intptr_t Hash() const;
+  intptr_t ComputeHash() const;
+
+  bool IsSubtypeOf(const FunctionType& other, Heap::Space space) const;
+
+  intptr_t NumParameters() const;
+
+  // Return the number of type arguments in enclosing signature.
+  intptr_t NumParentTypeArguments() const {
+    return FunctionTypeLayout::PackedNumParentTypeArguments::decode(
+        raw_ptr()->packed_fields_);
+  }
+  void SetNumParentTypeArguments(intptr_t value) const;
+
+  intptr_t NumTypeArguments() const {
+    return NumParentTypeArguments() + NumTypeParameters();
+  }
+
+  intptr_t num_implicit_parameters() const {
+    return FunctionTypeLayout::PackedNumImplicitParameters::decode(
+        raw_ptr()->packed_fields_);
+  }
+  void set_num_implicit_parameters(intptr_t value) const;
+  intptr_t num_fixed_parameters() const {
+    return FunctionTypeLayout::PackedNumFixedParameters::decode(
+        raw_ptr()->packed_fields_);
+  }
+  void set_num_fixed_parameters(intptr_t value) const;
+
+  bool HasOptionalParameters() const {
+    return FunctionTypeLayout::PackedNumOptionalParameters::decode(
+               raw_ptr()->packed_fields_) > 0;
+  }
+  bool HasOptionalNamedParameters() const {
+    return HasOptionalParameters() &&
+           FunctionTypeLayout::PackedHasNamedOptionalParameters::decode(
+               raw_ptr()->packed_fields_);
+  }
+  bool HasOptionalPositionalParameters() const {
+    return HasOptionalParameters() && !HasOptionalNamedParameters();
+  }
+  intptr_t NumOptionalParameters() const {
+    return FunctionTypeLayout::PackedNumOptionalParameters::decode(
+        raw_ptr()->packed_fields_);
+  }
+  void SetNumOptionalParameters(intptr_t num_optional_parameters,
+                                bool are_optional_positional) const;
+
+  intptr_t NumOptionalPositionalParameters() const {
+    return HasOptionalPositionalParameters() ? NumOptionalParameters() : 0;
+  }
+
+  intptr_t NumOptionalNamedParameters() const {
+    return HasOptionalNamedParameters() ? NumOptionalParameters() : 0;
+  }
+  uint32_t packed_fields() const { return raw_ptr()->packed_fields_; }
+  void set_packed_fields(uint32_t packed_fields) const;
+  static intptr_t packed_fields_offset() {
+    return OFFSET_OF(FunctionTypeLayout, packed_fields_);
+  }
+
+  AbstractTypePtr result_type() const { return raw_ptr()->result_type(); }
+  void set_result_type(const AbstractType& value) const;
+
+  // The parameters, starting with NumImplicitParameters() parameters which are
+  // only visible to the VM, but not to Dart users.
+  // Note that type checks exclude implicit parameters.
+  AbstractTypePtr ParameterTypeAt(intptr_t index) const;
+  void SetParameterTypeAt(intptr_t index, const AbstractType& value) const;
+  ArrayPtr parameter_types() const { return raw_ptr()->parameter_types(); }
+  void set_parameter_types(const Array& value) const;
+  static intptr_t parameter_types_offset() {
+    return OFFSET_OF(FunctionTypeLayout, parameter_types_);
+  }
+  // Parameter names are valid for all valid parameter indices, and are not
+  // limited to named optional parameters. However, they are meaningless after
+  // canonicalization of the function type. Any particular signature may be
+  // selected as the canonical represent as the names are not part of the type.
+  // If there are parameter flags (eg required) they're stored at the end of
+  // this array, so the size of this array isn't necessarily NumParameters(),
+  // but the first NumParameters() elements are the names.
+  StringPtr ParameterNameAt(intptr_t index) const;
+  void SetParameterNameAt(intptr_t index, const String& value) const;
+  ArrayPtr parameter_names() const { return raw_ptr()->parameter_names(); }
+  void set_parameter_names(const Array& value) const;
+
+  // The required flags are stored at the end of the parameter_names. The flags
+  // are packed into SMIs, but omitted if they're 0.
+  bool IsRequiredAt(intptr_t index) const;
+  void SetIsRequiredAt(intptr_t index) const;
+
+  // Sets up the signature's parameter name array, including appropriate space
+  // for any possible parameter flags. This may be an overestimate if some
+  // parameters don't have flags, and so TruncateUnusedParameterFlags() should
+  // be called after all parameter flags have been appropriately set.
+  //
+  // Assumes that the number of fixed and optional parameters for the signature
+  // has already been set.
+  void CreateNameArrayIncludingFlags(Heap::Space space) const;
+
+  // Truncate the parameter names array to remove any unused flag slots. Make
+  // sure to only do this after calling SetIsRequiredAt as necessary.
+  void TruncateUnusedParameterFlags() const;
+
+  // Finalize the name arrays by truncating the parameter name array and copying
+  // the names in the given function.
+  void FinalizeNameArrays(const Function& function) const;
+
+  // Returns the length of the parameter names array that is required to store
+  // all the names plus all their flags. This may be an overestimate if some
+  // parameters don't have flags.
+  static intptr_t NameArrayLengthIncludingFlags(intptr_t num_parameters);
+
+  // The type parameters (and their bounds) are specified as an array of
+  // TypeParameter.
+  TypeArgumentsPtr type_parameters() const {
+    return raw_ptr()->type_parameters();
+  }
+  void set_type_parameters(const TypeArguments& value) const;
+  static intptr_t type_parameters_offset() {
+    return OFFSET_OF(FunctionTypeLayout, type_parameters_);
+  }
+  intptr_t NumTypeParameters(Thread* thread) const;
+  intptr_t NumTypeParameters() const {
+    return NumTypeParameters(Thread::Current());
+  }
+
+  // Returns true if this function type has the same number of type parameters
+  // with equal bounds as the other function type. Type parameter names and
+  // parameter names (unless optional named) are ignored.
+  bool HasSameTypeParametersAndBounds(const FunctionType& other,
+                                      TypeEquality kind) const;
+
+  // Return true if this function type declares type parameters.
+  bool IsGeneric() const { return NumTypeParameters(Thread::Current()) > 0; }
+
+  // Return true if any enclosing signature of this signature is generic.
+  bool HasGenericParent() const { return NumParentTypeArguments() > 0; }
+
+  // Returns true if the type of the formal parameter at the given position in
+  // this function type is contravariant with the type of the other formal
+  // parameter at the given position in the other function type.
+  bool IsContravariantParameter(intptr_t parameter_position,
+                                const FunctionType& other,
+                                intptr_t other_parameter_position,
+                                Heap::Space space) const;
+
+  // Returns the index in the parameter names array of the corresponding flag
+  // for the given parametere index. Also returns (via flag_mask) the
+  // corresponding mask within the flag.
+  intptr_t GetRequiredFlagIndex(intptr_t index, intptr_t* flag_mask) const;
+
+  void Print(NameVisibility name_visibility, BaseTextBuffer* printer) const;
+  void PrintParameters(Thread* thread,
+                       Zone* zone,
+                       NameVisibility name_visibility,
+                       BaseTextBuffer* printer) const;
+
+  StringPtr ToUserVisibleString() const;
+  const char* ToUserVisibleCString() const;
+
+  static intptr_t InstanceSize() {
+    return RoundedAllocationSize(sizeof(FunctionTypeLayout));
+  }
+
+  static FunctionTypePtr New(intptr_t num_parent_type_arguments = 0,
+                             Nullability nullability = Nullability::kLegacy,
+                             Heap::Space space = Heap::kOld);
+
+ private:
+  void SetHash(intptr_t value) const;
+
+  void set_type_state(uint8_t state) const;
+  void set_nullability(Nullability value) const {
+    ASSERT(!IsCanonical());
+    StoreNonPointer(&raw_ptr()->nullability_, static_cast<uint8_t>(value));
+  }
+
+  static FunctionTypePtr New(Heap::Space space);
+
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(FunctionType, AbstractType);
+  friend class Class;
+  friend class ClearTypeHashVisitor;
+  friend class Function;
+};
+
 // A TypeRef is used to break cycles in the representation of recursive types.
 // Its only field is the recursive AbstractType it refers to, which can
 // temporarily be null during finalization.
@@ -8177,20 +8270,13 @@
   virtual TypeArgumentsPtr arguments() const {
     return AbstractType::Handle(type()).arguments();
   }
-  virtual TokenPosition token_pos() const {
-    return AbstractType::Handle(type()).token_pos();
-  }
   virtual bool IsInstantiated(Genericity genericity = kAny,
                               intptr_t num_free_fun_type_params = kAllFree,
                               TrailPtr trail = nullptr) const;
   virtual bool IsEquivalent(const Instance& other,
                             TypeEquality kind,
                             TrailPtr trail = nullptr) const;
-  virtual bool IsRecursive() const { return true; }
-  virtual bool IsFunctionType() const {
-    const AbstractType& ref_type = AbstractType::Handle(type());
-    return !ref_type.IsNull() && ref_type.IsFunctionType();
-  }
+  virtual bool IsRecursive(TrailPtr trail = nullptr) const { return true; }
   virtual AbstractTypePtr InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
@@ -8235,19 +8321,18 @@
     return TypeParameterLayout::FinalizedBit::decode(raw_ptr()->flags_);
   }
   virtual void SetIsFinalized() const;
-  virtual bool IsBeingFinalized() const { return false; }
-  static intptr_t flags_offset() {
-    return OFFSET_OF(TypeParameterLayout, flags_);
+  virtual bool IsBeingFinalized() const {
+    return TypeParameterLayout::BeingFinalizedBit::decode(raw_ptr()->flags_);
   }
+  virtual void SetIsBeingFinalized() const;
   bool IsGenericCovariantImpl() const {
     return TypeParameterLayout::GenericCovariantImplBit::decode(
         raw_ptr()->flags_);
   }
   void SetGenericCovariantImpl(bool value) const;
-  bool IsDeclaration() const {
-    return TypeParameterLayout::DeclarationBit::decode(raw_ptr()->flags_);
+  static intptr_t flags_offset() {
+    return OFFSET_OF(TypeParameterLayout, flags_);
   }
-  void SetDeclaration(bool value) const;
   static intptr_t nullability_offset() {
     return OFFSET_OF(TypeParameterLayout, nullability_);
   }
@@ -8258,27 +8343,23 @@
   virtual bool HasTypeClass() const { return false; }
   virtual classid_t type_class_id() const { return kIllegalCid; }
   classid_t parameterized_class_id() const;
+  void set_parameterized_class_id(classid_t value) const;
   ClassPtr parameterized_class() const;
-  FunctionPtr parameterized_function() const {
-    return raw_ptr()->parameterized_function();
-  }
   bool IsClassTypeParameter() const {
     return parameterized_class_id() != kFunctionCid;
   }
   bool IsFunctionTypeParameter() const {
-    return parameterized_function() != Function::null();
-  }
-  ObjectPtr Owner() const {
-    if (IsClassTypeParameter()) {
-      return parameterized_class();
-    } else {
-      return parameterized_function();
-    }
+    return parameterized_class_id() == kFunctionCid;
   }
 
   static intptr_t parameterized_class_id_offset() {
     return OFFSET_OF(TypeParameterLayout, parameterized_class_id_);
   }
+
+  intptr_t base() const { return raw_ptr()->base_; }
+  void set_base(intptr_t value) const;
+  intptr_t index() const { return raw_ptr()->index_; }
+  void set_index(intptr_t value) const;
   static intptr_t index_offset() {
     return OFFSET_OF(TypeParameterLayout, index_);
   }
@@ -8287,25 +8368,24 @@
   static intptr_t name_offset() {
     return OFFSET_OF(TypeParameterLayout, name_);
   }
-  intptr_t index() const { return raw_ptr()->index_; }
-  void set_index(intptr_t value) const;
   AbstractTypePtr bound() const { return raw_ptr()->bound(); }
   void set_bound(const AbstractType& value) const;
+  static intptr_t bound_offset() {
+    return OFFSET_OF(TypeParameterLayout, bound_);
+  }
+
   AbstractTypePtr default_argument() const {
     return raw_ptr()->default_argument();
   }
   void set_default_argument(const AbstractType& value) const;
-  static intptr_t bound_offset() {
-    return OFFSET_OF(TypeParameterLayout, bound_);
-  }
-  virtual TokenPosition token_pos() const { return raw_ptr()->token_pos_; }
+
   virtual bool IsInstantiated(Genericity genericity = kAny,
                               intptr_t num_free_fun_type_params = kAllFree,
                               TrailPtr trail = nullptr) const;
   virtual bool IsEquivalent(const Instance& other,
                             TypeEquality kind,
                             TrailPtr trail = nullptr) const;
-  virtual bool IsRecursive() const { return false; }
+  virtual bool IsRecursive(TrailPtr trail = nullptr) const;
   virtual AbstractTypePtr InstantiateFrom(
       const TypeArguments& instantiator_type_arguments,
       const TypeArguments& function_type_arguments,
@@ -8317,7 +8397,7 @@
   // Check if type parameter is canonical.
   virtual bool CheckIsCanonical(Thread* thread) const;
 #endif  // DEBUG
-  virtual void EnumerateURIs(URIs* uris) const;
+  virtual void EnumerateURIs(URIs* uris) const { return; }
 
   virtual intptr_t Hash() const;
 
@@ -8333,24 +8413,21 @@
     return RoundedAllocationSize(sizeof(TypeParameterLayout));
   }
 
-  // Only one of parameterized_class and parameterized_function is non-null.
+  // 'parameterized_class' is null for a function type parameter.
   static TypeParameterPtr New(const Class& parameterized_class,
-                              const Function& parameterized_function,
+                              intptr_t base,
                               intptr_t index,
                               const String& name,
                               const AbstractType& bound,
                               bool is_generic_covariant_impl,
-                              Nullability nullability,
-                              TokenPosition token_pos);
+                              Nullability nullability);
 
  private:
   intptr_t ComputeHash() const;
   void SetHash(intptr_t value) const;
 
   void set_parameterized_class(const Class& value) const;
-  void set_parameterized_function(const Function& value) const;
   void set_name(const String& value) const;
-  void set_token_pos(TokenPosition token_pos) const;
   void set_flags(uint8_t flags) const;
   void set_nullability(Nullability value) const;
 
@@ -10560,8 +10637,8 @@
 
   bool IsGeneric(Thread* thread) const { return NumTypeParameters(thread) > 0; }
   intptr_t NumTypeParameters(Thread* thread) const;
-  // No need for NumParentTypeParameters, as a closure is always closed over
-  // its parents type parameters (i.e., function_type_parameters() above).
+  // No need for num_parent_type_arguments, as a closure is always closed
+  // over its parents type parameters (i.e., function_type_parameters() above).
 
   SmiPtr hash() const { return raw_ptr()->hash(); }
   static intptr_t hash_offset() { return OFFSET_OF(ClosureLayout, hash_); }
@@ -10590,7 +10667,7 @@
                         const Context& context,
                         Heap::Space space = Heap::kNew);
 
-  FunctionPtr GetInstantiatedSignature(Zone* zone) const;
+  FunctionTypePtr GetInstantiatedSignature(Zone* zone) const;
 
  private:
   static ClosurePtr New();
@@ -11023,6 +11100,8 @@
 
   FunctionPtr GetFunctionReferent() const;
 
+  FunctionTypePtr GetFunctionTypeReferent() const;
+
   LibraryPtr GetLibraryReferent() const;
 
   TypeParameterPtr GetTypeParameterReferent() const;
@@ -11270,6 +11349,7 @@
 }
 
 inline intptr_t Type::Hash() const {
+  ASSERT(IsFinalized());
   intptr_t result = Smi::Value(raw_ptr()->hash());
   if (result != 0) {
     return result;
@@ -11283,8 +11363,23 @@
   raw_ptr()->set_hash(Smi::New(value));
 }
 
-inline intptr_t TypeParameter::Hash() const {
+inline intptr_t FunctionType::Hash() const {
   ASSERT(IsFinalized());
+  intptr_t result = Smi::Value(raw_ptr()->hash_);
+  if (result != 0) {
+    return result;
+  }
+  return ComputeHash();
+}
+
+inline void FunctionType::SetHash(intptr_t value) const {
+  // This is only safe because we create a new Smi, which does not cause
+  // heap allocation.
+  StoreSmi(&raw_ptr()->hash_, Smi::New(value));
+}
+
+inline intptr_t TypeParameter::Hash() const {
+  ASSERT(IsFinalized() || IsBeingFinalized());  // Bound may not be finalized.
   intptr_t result = Smi::Value(raw_ptr()->hash());
   if (result != 0) {
     return result;
@@ -11488,6 +11583,9 @@
 DART_WARN_UNUSED_RESULT
 ErrorPtr EntryPointFieldInvocationError(const String& getter_name);
 
+DART_WARN_UNUSED_RESULT
+ErrorPtr EntryPointMemberInvocationError(const Object& member);
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_OBJECT_H_
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index 03f743b..d2b8a33 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -538,20 +538,6 @@
   }
 };
 
-class TypedefClassConflict : public ClassReasonForCancelling {
- public:
-  TypedefClassConflict(Zone* zone, const Class& from, const Class& to)
-      : ClassReasonForCancelling(zone, from, to) {}
-
-  StringPtr ToString() {
-    return String::NewFormatted(
-        from_.IsTypedefClass()
-            ? "Typedef class cannot be redefined to be a non-typedef class: %s"
-            : "Class cannot be redefined to be a typedef class: %s",
-        from_.ToCString());
-  }
-};
-
 class EnsureFinalizedError : public ClassReasonForCancelling {
  public:
   EnsureFinalizedError(Zone* zone,
@@ -699,14 +685,6 @@
     return;
   }
 
-  // Class cannot change typedef property.
-  if (IsTypedefClass() != replacement.IsTypedefClass()) {
-    context->group_reload_context()->AddReasonForCancelling(
-        new (context->zone())
-            TypedefClassConflict(context->zone(), *this, replacement));
-    return;
-  }
-
   if (is_finalized()) {
     // Ensure the replacement class is also finalized.
     const Error& error =
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index b35fb52..ac079da 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -228,11 +228,7 @@
 static void AddFunctionServiceId(const JSONObject& jsobj,
                                  const Function& f,
                                  const Class& cls) {
-  if (cls.IsNull()) {
-    ASSERT(f.IsSignatureFunction());
-    jsobj.AddServiceId(f);
-    return;
-  }
+  ASSERT(!cls.IsNull());
   // Special kinds of functions use indices in their respective lists.
   intptr_t id = -1;
   const char* selector = NULL;
@@ -283,13 +279,10 @@
 
 void Function::PrintJSONImpl(JSONStream* stream, bool ref) const {
   Class& cls = Class::Handle(Owner());
-  if (!cls.IsNull()) {
-    Error& err = Error::Handle();
-    err = cls.EnsureIsFinalized(Thread::Current());
-    ASSERT(err.IsNull());
-  } else {
-    ASSERT(IsSignatureFunction());
-  }
+  ASSERT(!cls.IsNull());
+  Error& err = Error::Handle();
+  err = cls.EnsureIsFinalized(Thread::Current());
+  ASSERT(err.IsNull());
   JSONObject jsobj(stream);
   AddCommonObjectProperties(&jsobj, "Function", ref);
   AddFunctionServiceId(jsobj, *this, cls);
@@ -1103,7 +1096,6 @@
 }
 
 void Type::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  // TODO(regis): Function types are not handled properly.
   JSONObject jsobj(stream);
   PrintSharedInstanceJSON(&jsobj, ref);
   jsobj.AddProperty("kind", "Type");
@@ -1127,6 +1119,13 @@
   }
 }
 
+void FunctionType::PrintJSONImpl(JSONStream* stream, bool ref) const {
+  JSONObject jsobj(stream);
+  PrintSharedInstanceJSON(&jsobj, ref);
+  jsobj.AddProperty("kind", "FunctionType");
+  // TODO(regis): Function types were not handled before, necessary now?
+}
+
 void TypeRef::PrintJSONImpl(JSONStream* stream, bool ref) const {
   JSONObject jsobj(stream);
   PrintSharedInstanceJSON(&jsobj, ref);
@@ -1149,6 +1148,7 @@
   const String& user_name = String::Handle(UserVisibleName());
   const String& vm_name = String::Handle(Name());
   AddNameProperties(&jsobj, user_name.ToCString(), vm_name.ToCString());
+  // TODO(regis): parameterizedClass is meaningless and always null.
   const Class& param_cls = Class::Handle(parameterized_class());
   jsobj.AddProperty("parameterizedClass", param_cls);
   if (ref) {
@@ -1472,10 +1472,6 @@
   Object::PrintJSONImpl(stream, ref);
 }
 
-void SignatureData::PrintJSONImpl(JSONStream* stream, bool ref) const {
-  Object::PrintJSONImpl(stream, ref);
-}
-
 void Closure::PrintJSONImpl(JSONStream* stream, bool ref) const {
   Instance::PrintJSONImpl(stream, ref);
 }
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 088c5ed..8b2995a 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -364,8 +364,7 @@
     ASSERT(!type.IsNull());
     type_args = TypeArguments::New(1);
     type_args.SetTypeAt(0, type);
-    type = Type::New(cls, type_args, TokenPosition::kNoSource,
-                     Nullability::kNonNullable);
+    type = Type::New(cls, type_args, Nullability::kNonNullable);
     type.SetIsFinalized();
     type ^= type.Canonicalize(thread, nullptr);
     set_non_nullable_future_never_type(type);
@@ -373,8 +372,7 @@
     ASSERT(!type.IsNull());
     type_args = TypeArguments::New(1);
     type_args.SetTypeAt(0, type);
-    type = Type::New(cls, type_args, TokenPosition::kNoSource,
-                     Nullability::kNullable);
+    type = Type::New(cls, type_args, Nullability::kNullable);
     type.SetIsFinalized();
     type ^= type.Canonicalize(thread, nullptr);
     set_nullable_future_null_type(type);
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 7ffcb71..0cac485 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -132,6 +132,7 @@
   RW(Class, weak_property_class)                                               \
   RW(Array, symbol_table)                                                      \
   RW(Array, canonical_types)                                                   \
+  RW(Array, canonical_function_types)                                          \
   RW(Array, canonical_type_parameters)                                         \
   RW(Array, canonical_type_arguments)                                          \
   RW(Library, async_library)                                                   \
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 0bd12fe..87513b2 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -78,17 +78,20 @@
 
   // Create and populate the function arrays.
   const Array& functions = Array::Handle(Array::New(6));
+  FunctionType& signature = FunctionType::Handle();
   Function& function = Function::Handle();
   String& function_name = String::Handle();
   function_name = Symbols::New(thread, "foo");
-  function =
-      Function::New(function_name, FunctionLayout::kRegularFunction, false,
-                    false, false, false, false, cls, TokenPosition::kMinSource);
+  signature = FunctionType::New();
+  function = Function::New(signature, function_name,
+                           FunctionLayout::kRegularFunction, false, false,
+                           false, false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(0, function);
   function_name = Symbols::New(thread, "bar");
-  function =
-      Function::New(function_name, FunctionLayout::kRegularFunction, false,
-                    false, false, false, false, cls, TokenPosition::kMinSource);
+  signature = FunctionType::New();
+  function = Function::New(signature, function_name,
+                           FunctionLayout::kRegularFunction, false, false,
+                           false, false, false, cls, TokenPosition::kMinSource);
 
   const int kNumFixedParameters = 2;
   const int kNumOptionalParameters = 3;
@@ -99,26 +102,30 @@
   functions.SetAt(1, function);
 
   function_name = Symbols::New(thread, "baz");
-  function =
-      Function::New(function_name, FunctionLayout::kRegularFunction, false,
-                    false, false, false, false, cls, TokenPosition::kMinSource);
+  signature = FunctionType::New();
+  function = Function::New(signature, function_name,
+                           FunctionLayout::kRegularFunction, false, false,
+                           false, false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(2, function);
 
   function_name = Symbols::New(thread, "Foo");
-  function =
-      Function::New(function_name, FunctionLayout::kRegularFunction, true,
-                    false, false, false, false, cls, TokenPosition::kMinSource);
+  signature = FunctionType::New();
+  function = Function::New(signature, function_name,
+                           FunctionLayout::kRegularFunction, true, false, false,
+                           false, false, cls, TokenPosition::kMinSource);
 
   functions.SetAt(3, function);
   function_name = Symbols::New(thread, "Bar");
-  function =
-      Function::New(function_name, FunctionLayout::kRegularFunction, true,
-                    false, false, false, false, cls, TokenPosition::kMinSource);
+  signature = FunctionType::New();
+  function = Function::New(signature, function_name,
+                           FunctionLayout::kRegularFunction, true, false, false,
+                           false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(4, function);
   function_name = Symbols::New(thread, "BaZ");
-  function =
-      Function::New(function_name, FunctionLayout::kRegularFunction, true,
-                    false, false, false, false, cls, TokenPosition::kMinSource);
+  signature = FunctionType::New();
+  function = Function::New(signature, function_name,
+                           FunctionLayout::kRegularFunction, true, false, false,
+                           false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(5, function);
 
   // Setup the functions in the class.
@@ -2631,9 +2638,10 @@
   const Context& context = Context::Handle(Context::New(0));
   Function& parent = Function::Handle();
   const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
-  parent =
-      Function::New(parent_name, FunctionLayout::kRegularFunction, false, false,
-                    false, false, false, cls, TokenPosition::kMinSource);
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
+  parent = Function::New(signature, parent_name,
+                         FunctionLayout::kRegularFunction, false, false, false,
+                         false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(0, parent);
   {
     SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
@@ -2708,9 +2716,10 @@
   const Library& owner_library = Library::Handle(CreateDummyLibrary(lib_name));
   owner_class.set_library(owner_library);
   const String& function_name = String::ZoneHandle(Symbols::New(thread, name));
-  return Function::New(function_name, FunctionLayout::kRegularFunction, true,
-                       false, false, false, false, owner_class,
-                       TokenPosition::kMinSource);
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
+  return Function::New(signature, function_name,
+                       FunctionLayout::kRegularFunction, true, false, false,
+                       false, false, owner_class, TokenPosition::kMinSource);
 }
 
 // Test for Code and Instruction object creation.
@@ -3107,9 +3116,11 @@
   const bool is_abstract = false;
   const bool is_external = false;
   const bool is_native = false;
-  return Function::New(function_name, FunctionLayout::kRegularFunction,
-                       is_static, is_const, is_abstract, is_external, is_native,
-                       cls, TokenPosition::kMinSource);
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
+  return Function::New(signature, function_name,
+                       FunctionLayout::kRegularFunction, is_static, is_const,
+                       is_abstract, is_external, is_native, cls,
+                       TokenPosition::kMinSource);
 }
 
 ISOLATE_UNIT_TEST_CASE(ICData) {
@@ -3948,9 +3959,10 @@
 
   Function& parent = Function::Handle();
   const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
-  parent =
-      Function::New(parent_name, FunctionLayout::kRegularFunction, false, false,
-                    false, false, false, cls, TokenPosition::kMinSource);
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
+  parent = Function::New(signature, parent_name,
+                         FunctionLayout::kRegularFunction, false, false, false,
+                         false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(0, parent);
   {
     SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
@@ -3992,9 +4004,10 @@
   const Array& functions = Array::Handle(Array::New(1));
   Function& parent = Function::Handle();
   const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
-  parent =
-      Function::New(parent_name, FunctionLayout::kRegularFunction, false, false,
-                    false, false, false, cls, TokenPosition::kMinSource);
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
+  parent = Function::New(signature, parent_name,
+                         FunctionLayout::kRegularFunction, false, false, false,
+                         false, false, cls, TokenPosition::kMinSource);
   functions.SetAt(0, parent);
   {
     SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index 09b1598..aecd13b 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -1023,7 +1023,7 @@
     explicit DedupListsVisitor(Zone* zone)
         : Dedupper(zone),
           list_(Array::Handle(zone)),
-          function_(Function::Handle(zone)) {}
+          field_(Field::Handle(zone)) {}
 
     void VisitCode(const Code& code) {
       if (!code.IsFunctionCode()) return;
@@ -1042,36 +1042,34 @@
     }
 
     void VisitFunction(const Function& function) {
-      list_ = PrepareParameterTypes(function);
-      list_ = Dedup(list_);
-      function.set_parameter_types(list_);
-
       list_ = PrepareParameterNames(function);
       list_ = Dedup(list_);
       function.set_parameter_names(list_);
+
+      // No need to dedup parameter types, as they are stored in the
+      // canonicalized function type of the function.
+      // However, the function type of the function is only needed in case of
+      // recompilation or if available to mirrors, or for copied types
+      // to lazily generated tear offs. Also avoid attempting to change
+      // read-only VM objects for de-duplication.
+      // We cannot check precisely if a function is an entry point here,
+      // because the metadata has been dropped already. However, we use the
+      // has_pragma flag on the function as a conservative approximation.
+      // Resolution requires the number of parameters (no signature needed) and
+      // their names if any named parameter is required (signature needed).
+      if (FLAG_precompiled_mode && !function.InVMIsolateHeap() &&
+          !function.IsClosureFunction() && !function.IsFfiTrampoline() &&
+          function.name() != Symbols::Call().raw() && !function.is_native() &&
+          !function.HasRequiredNamedParameters() &&
+          !MayBeEntryPoint(function)) {
+        // Function type not needed for function type tests or resolution.
+        function.set_signature(Object::null_function_type());
+      }
     }
 
    private:
     bool IsCorrectType(const Object& obj) const { return obj.IsArray(); }
 
-    ArrayPtr PrepareParameterTypes(const Function& function) {
-      list_ = function.parameter_types();
-      // Preserve parameter types in the JIT. Needed in case of recompilation
-      // in checked mode, or if available to mirrors, or for copied types to
-      // lazily generated tear offs. Also avoid attempting to change read-only
-      // VM objects for de-duplication.
-      if (FLAG_precompiled_mode && !list_.IsNull() &&
-          !list_.InVMIsolateHeap() && !function.IsSignatureFunction() &&
-          !function.IsClosureFunction() && !function.IsFfiTrampoline() &&
-          function.name() != Symbols::Call().raw()) {
-        // Parameter types not needed for function type tests.
-        for (intptr_t i = 0; i < list_.Length(); i++) {
-          list_.SetAt(i, Object::dynamic_type());
-        }
-      }
-      return list_.raw();
-    }
-
     ArrayPtr PrepareParameterNames(const Function& function) {
       list_ = function.parameter_names();
       // Preserve parameter names in case of recompilation for the JIT. Also
@@ -1087,8 +1085,23 @@
       return list_.raw();
     }
 
+    bool MayBeEntryPoint(const Function& function) {
+      // Metadata has been dropped already.
+      // Use presence of pragma as conservative approximation.
+      if (function.has_pragma()) return true;
+      auto kind = function.kind();
+      if ((kind == FunctionLayout::kImplicitGetter) ||
+          (kind == FunctionLayout::kImplicitSetter) ||
+          (kind == FunctionLayout::kImplicitStaticGetter) ||
+          (kind == FunctionLayout::kFieldInitializer)) {
+        field_ = function.accessor_field();
+        if (!field_.IsNull() && field_.has_pragma()) return true;
+      }
+      return false;
+    }
+
     Array& list_;
-    Function& function_;
+    Field& field_;
   };
 
   DedupListsVisitor visitor(zone);
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 0bc2ddb..41a97f5 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -500,13 +500,13 @@
 
 REGULAR_VISITOR(Class)
 REGULAR_VISITOR(Type)
+REGULAR_VISITOR(FunctionType)
 REGULAR_VISITOR(TypeRef)
 REGULAR_VISITOR(TypeParameter)
 REGULAR_VISITOR(PatchClass)
 REGULAR_VISITOR(Function)
 COMPRESSED_VISITOR(Closure)
 REGULAR_VISITOR(ClosureData)
-REGULAR_VISITOR(SignatureData)
 REGULAR_VISITOR(FfiTrampolineData)
 REGULAR_VISITOR(Script)
 REGULAR_VISITOR(Library)
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index f1367db..06e736a 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -819,8 +819,6 @@
   POINTER_FIELD(LibraryPtr, library)
   POINTER_FIELD(TypeArgumentsPtr, type_parameters)  // Array of TypeParameter.
   POINTER_FIELD(AbstractTypePtr, super_type)
-  POINTER_FIELD(FunctionPtr,
-                signature_function)  // Associated function for typedef class.
   POINTER_FIELD(ArrayPtr,
                 constants)  // Canonicalized const instances of this class.
   POINTER_FIELD(TypePtr, declaration_type)  // Declaration type for this class.
@@ -944,8 +942,6 @@
   /* an implicit closure (i.e., tear-off) */                                   \
   V(ImplicitClosureFunction)                                                   \
   /* a signature only without actual code */                                   \
-  V(SignatureFunction)                                                         \
-  /* getter functions e.g: get foo() { .. } */                                 \
   V(GetterFunction)                                                            \
   /* setter functions e.g: set foo(..) { .. } */                               \
   V(SetterFunction)                                                            \
@@ -1076,9 +1072,6 @@
     uint64_t bitmap_;
   };
 
-  static constexpr intptr_t kMaxFixedParametersBits = 14;
-  static constexpr intptr_t kMaxOptionalParametersBits = 13;
-
  private:
   friend class Class;
   friend class UnitDeserializationRoots;
@@ -1092,10 +1085,8 @@
   POINTER_FIELD(StringPtr, name)
   POINTER_FIELD(ObjectPtr, owner)  // Class or patch class or mixin class
                                    // where this function is defined.
-  POINTER_FIELD(AbstractTypePtr, result_type)
-  POINTER_FIELD(ArrayPtr, parameter_types)
   POINTER_FIELD(ArrayPtr, parameter_names)
-  POINTER_FIELD(TypeArgumentsPtr, type_parameters)  // Array of TypeParameter.
+  POINTER_FIELD(FunctionTypePtr, signature)
   POINTER_FIELD(ObjectPtr,
                 data)  // Additional data specific to the function kind. See
                        // Function::set_data() for details.
@@ -1135,17 +1126,35 @@
   uint32_t kind_tag_;  // See Function::KindTagBits.
   uint32_t packed_fields_;
 
-  typedef BitField<uint32_t, bool, 0, 1> PackedHasNamedOptionalParameters;
+  // TODO(regis): Split packed_fields_ in 2 uint32_t if max values are too low.
+
+  // Keep in sync with corresponding constants in FunctionTypeLayout.
+  static constexpr intptr_t kMaxOptimizableBits = 1;
+  static constexpr intptr_t kMaxBackgroundOptimizableBits = 1;
+  static constexpr intptr_t kMaxTypeParametersBits = 7;
+  static constexpr intptr_t kMaxHasNamedOptionalParametersBits = 1;
+  static constexpr intptr_t kMaxFixedParametersBits = 10;
+  static constexpr intptr_t kMaxOptionalParametersBits = 10;
+
+  typedef BitField<uint32_t, bool, 0, kMaxOptimizableBits> PackedOptimizable;
   typedef BitField<uint32_t,
                    bool,
-                   PackedHasNamedOptionalParameters::kNextBit,
-                   1>
-      OptimizableBit;
-  typedef BitField<uint32_t, bool, OptimizableBit::kNextBit, 1>
-      BackgroundOptimizableBit;
+                   PackedOptimizable::kNextBit,
+                   kMaxBackgroundOptimizableBits>
+      PackedBackgroundOptimizable;
+  typedef BitField<uint32_t,
+                   uint8_t,
+                   PackedBackgroundOptimizable::kNextBit,
+                   kMaxTypeParametersBits>
+      PackedNumTypeParameters;
+  typedef BitField<uint32_t,
+                   bool,
+                   PackedNumTypeParameters::kNextBit,
+                   kMaxHasNamedOptionalParametersBits>
+      PackedHasNamedOptionalParameters;
   typedef BitField<uint32_t,
                    uint16_t,
-                   BackgroundOptimizableBit::kNextBit,
+                   PackedHasNamedOptionalParameters::kNextBit,
                    kMaxFixedParametersBits>
       PackedNumFixedParameters;
   typedef BitField<uint32_t,
@@ -1154,8 +1163,8 @@
                    kMaxOptionalParametersBits>
       PackedNumOptionalParameters;
   static_assert(PackedNumOptionalParameters::kNextBit <=
-                    kBitsPerWord * sizeof(decltype(packed_fields_)),
-                "FunctionLayout::packed_fields_ bitfields don't align.");
+                    kBitsPerByte * sizeof(decltype(packed_fields_)),
+                "FunctionLayout::packed_fields_ bitfields don't fit.");
   static_assert(PackedNumOptionalParameters::kNextBit <=
                     compiler::target::kSmiBits,
                 "In-place mask for number of optional parameters cannot fit in "
@@ -1187,7 +1196,6 @@
   POINTER_FIELD(ContextScopePtr, context_scope)
   POINTER_FIELD(FunctionPtr,
                 parent_function)  // Enclosing function of this local function.
-  POINTER_FIELD(TypePtr, signature_type)
   POINTER_FIELD(InstancePtr,
                 closure)  // Closure object for static implicit closures.
   // Instantiate-to-bounds TAV for use when no TAV is provided.
@@ -1199,27 +1207,13 @@
   friend class Function;
 };
 
-class SignatureDataLayout : public ObjectLayout {
- private:
-  RAW_HEAP_OBJECT_IMPLEMENTATION(SignatureData);
-
-  VISIT_FROM(ObjectPtr, parent_function)
-  POINTER_FIELD(FunctionPtr,
-                parent_function);  // Enclosing function of this sig. function.
-  POINTER_FIELD(TypePtr, signature_type)
-  VISIT_TO(ObjectPtr, signature_type)
-  ObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
-
-  friend class Function;
-};
-
 class FfiTrampolineDataLayout : public ObjectLayout {
  private:
   RAW_HEAP_OBJECT_IMPLEMENTATION(FfiTrampolineData);
 
   VISIT_FROM(ObjectPtr, signature_type)
   POINTER_FIELD(TypePtr, signature_type)
-  POINTER_FIELD(FunctionPtr, c_signature)
+  POINTER_FIELD(FunctionTypePtr, c_signature)
 
   // Target Dart method for callbacks, otherwise null.
   POINTER_FIELD(FunctionPtr, callback_target)
@@ -2292,14 +2286,9 @@
   POINTER_FIELD(SmiPtr, type_class_id)
   POINTER_FIELD(TypeArgumentsPtr, arguments)
   POINTER_FIELD(SmiPtr, hash)
-  // This type object represents a function type if its signature field is a
-  // non-null function object.
-  POINTER_FIELD(FunctionPtr,
-                signature)  // If not null, this type is a function type.
-  VISIT_TO(ObjectPtr, signature)
-  TokenPosition token_pos_;
-  int8_t type_state_;
-  int8_t nullability_;
+  VISIT_TO(ObjectPtr, hash)
+  uint8_t type_state_;
+  uint8_t nullability_;
 
   ObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
 
@@ -2307,6 +2296,59 @@
   friend class TypeArgumentsLayout;
 };
 
+class FunctionTypeLayout : public AbstractTypeLayout {
+ private:
+  RAW_HEAP_OBJECT_IMPLEMENTATION(FunctionType);
+
+  VISIT_FROM(ObjectPtr, type_test_stub)
+  POINTER_FIELD(TypeArgumentsPtr, type_parameters)  // Array of TypeParameter.
+  POINTER_FIELD(AbstractTypePtr, result_type)
+  POINTER_FIELD(ArrayPtr, parameter_types)
+  POINTER_FIELD(ArrayPtr, parameter_names);
+  POINTER_FIELD(SmiPtr, hash)
+  VISIT_TO(ObjectPtr, hash)
+  uint32_t packed_fields_;  // Number of parent type args and own parameters.
+  uint8_t type_state_;
+  uint8_t nullability_;
+
+  // Keep in sync with corresponding constants in FunctionLayout.
+  static constexpr intptr_t kMaxParentTypeArgumentsBits = 8;
+  static constexpr intptr_t kMaxHasNamedOptionalParametersBits = 1;
+  static constexpr intptr_t kMaxImplicitParametersBits = 1;
+  static constexpr intptr_t kMaxFixedParametersBits = 10;
+  static constexpr intptr_t kMaxOptionalParametersBits = 10;
+
+  typedef BitField<uint32_t, uint8_t, 0, kMaxParentTypeArgumentsBits>
+      PackedNumParentTypeArguments;
+  typedef BitField<uint32_t,
+                   bool,
+                   PackedNumParentTypeArguments::kNextBit,
+                   kMaxHasNamedOptionalParametersBits>
+      PackedHasNamedOptionalParameters;
+  typedef BitField<uint32_t,
+                   uint8_t,
+                   PackedHasNamedOptionalParameters::kNextBit,
+                   kMaxImplicitParametersBits>
+      PackedNumImplicitParameters;
+  typedef BitField<uint32_t,
+                   uint16_t,
+                   PackedNumImplicitParameters::kNextBit,
+                   kMaxFixedParametersBits>
+      PackedNumFixedParameters;
+  typedef BitField<uint32_t,
+                   uint16_t,
+                   PackedNumFixedParameters::kNextBit,
+                   kMaxOptionalParametersBits>
+      PackedNumOptionalParameters;
+  static_assert(PackedNumOptionalParameters::kNextBit <=
+                    kBitsPerByte * sizeof(decltype(packed_fields_)),
+                "FunctionTypeLayout::packed_fields_ bitfields don't fit.");
+
+  ObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
+
+  friend class Function;
+};
+
 class TypeRefLayout : public AbstractTypeLayout {
  private:
   RAW_HEAP_OBJECT_IMPLEMENTATION(TypeRef);
@@ -2331,21 +2373,22 @@
   // TODO(dartbug.com/43901): Once a separate TypeParameters class has been
   // added, move these there and remove them from TypeParameter objects.
   POINTER_FIELD(AbstractTypePtr, default_argument)
-  POINTER_FIELD(FunctionPtr, parameterized_function)
-  VISIT_TO(ObjectPtr, parameterized_function)
-  ClassIdTagType parameterized_class_id_;
-  TokenPosition token_pos_;
-  int16_t index_;
+  VISIT_TO(ObjectPtr, default_argument)
+  ClassIdTagType parameterized_class_id_;  // Or kFunctionCid for function tp.
+  // TODO(regis): Can we use uint8_t twice below? Or keep uint16_t?
+  // Warning: BuildTypeParameterTypeTestStub assumes uint16_t.
+  uint16_t base_;  // Number of enclosing function type parameters.
+  uint16_t index_;
   uint8_t flags_;
-  int8_t nullability_;
+  uint8_t nullability_;
 
  public:
-  using FinalizedBit = BitField<decltype(flags_), bool, 0, 1>;
+  using BeingFinalizedBit = BitField<decltype(flags_), bool, 0, 1>;
+  using FinalizedBit =
+      BitField<decltype(flags_), bool, BeingFinalizedBit::kNextBit, 1>;
   using GenericCovariantImplBit =
       BitField<decltype(flags_), bool, FinalizedBit::kNextBit, 1>;
-  using DeclarationBit =
-      BitField<decltype(flags_), bool, GenericCovariantImplBit::kNextBit, 1>;
-  static constexpr intptr_t kFlagsBitSize = DeclarationBit::kNextBit;
+  static constexpr intptr_t kFlagsBitSize = GenericCovariantImplBit::kNextBit;
 
  private:
   ObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc
index 103611e..35917b6 100644
--- a/runtime/vm/raw_object_fields.cc
+++ b/runtime/vm/raw_object_fields.cc
@@ -20,7 +20,6 @@
   F(Class, library_)                                                           \
   F(Class, type_parameters_)                                                   \
   F(Class, super_type_)                                                        \
-  F(Class, signature_function_)                                                \
   F(Class, constants_)                                                         \
   F(Class, declaration_type_)                                                  \
   F(Class, invocation_dispatcher_cache_)                                       \
@@ -34,19 +33,12 @@
   F(PatchClass, library_kernel_data_)                                          \
   F(Function, name_)                                                           \
   F(Function, owner_)                                                          \
-  F(Function, result_type_)                                                    \
-  F(Function, parameter_types_)                                                \
-  F(Function, parameter_names_)                                                \
-  F(Function, type_parameters_)                                                \
   F(Function, data_)                                                           \
   F(Function, ic_data_array_)                                                  \
   F(Function, code_)                                                           \
   F(ClosureData, context_scope_)                                               \
   F(ClosureData, parent_function_)                                             \
-  F(ClosureData, signature_type_)                                              \
   F(ClosureData, closure_)                                                     \
-  F(SignatureData, parent_function_)                                           \
-  F(SignatureData, signature_type_)                                            \
   F(Field, name_)                                                              \
   F(Field, owner_)                                                             \
   F(Field, type_)                                                              \
@@ -137,14 +129,18 @@
   F(Type, type_class_id_)                                                      \
   F(Type, arguments_)                                                          \
   F(Type, hash_)                                                               \
-  F(Type, signature_)                                                          \
+  F(FunctionType, type_test_stub_)                                             \
+  F(FunctionType, hash_)                                                       \
+  F(FunctionType, result_type_)                                                \
+  F(FunctionType, parameter_types_)                                            \
+  F(FunctionType, parameter_names_)                                            \
+  F(FunctionType, type_parameters_)                                            \
   F(TypeRef, type_test_stub_)                                                  \
   F(TypeRef, type_)                                                            \
   F(TypeParameter, type_test_stub_)                                            \
   F(TypeParameter, name_)                                                      \
   F(TypeParameter, hash_)                                                      \
   F(TypeParameter, bound_)                                                     \
-  F(TypeParameter, parameterized_function_)                                    \
   F(Closure, instantiator_type_arguments_)                                     \
   F(Closure, function_type_arguments_)                                         \
   F(Closure, delayed_type_arguments_)                                          \
@@ -188,7 +184,6 @@
   F(PointerBase, data_)                                                        \
   F(Pointer, type_arguments_)                                                  \
   F(DynamicLibrary, handle_)                                                   \
-  F(FfiTrampolineData, signature_type_)                                        \
   F(FfiTrampolineData, c_signature_)                                           \
   F(FfiTrampolineData, callback_target_)                                       \
   F(FfiTrampolineData, callback_exceptional_return_)                           \
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index f492800..7f7f766 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -87,7 +87,6 @@
   reader->AddBackRef(object_id, &type, kIsDeserialized);
 
   // Set all non object fields.
-  type.set_token_pos(TokenPosition::Deserialize(reader->Read<int32_t>()));
   const uint8_t combined = reader->Read<uint8_t>();
   type.set_type_state(combined >> 4);
   type.set_nullability(static_cast<Nullability>(combined & 0xf));
@@ -122,13 +121,6 @@
                          bool as_reference) {
   ASSERT(writer != NULL);
 
-  if (signature() != Function::null()) {
-    writer->SetWriteException(Exceptions::kArgument,
-                              "Illegal argument in isolate message"
-                              " : (function types are not supported yet)");
-    UNREACHABLE();
-  }
-
   // Only resolved and finalized types should be written to a snapshot.
   ASSERT((type_state_ == TypeLayout::kFinalizedInstantiated) ||
          (type_state_ == TypeLayout::kFinalizedUninstantiated));
@@ -160,7 +152,6 @@
   writer->Write<bool>(typeclass_is_in_fullsnapshot);
 
   // Write out all the non object pointer fields.
-  writer->Write<int32_t>(token_pos_.Serialize());
   const uint8_t combined = (type_state_ << 4) | nullability_;
   ASSERT(type_state_ == (combined >> 4));
   ASSERT(nullability_ == (combined & 0xf));
@@ -233,9 +224,6 @@
   reader->AddBackRef(object_id, &type_parameter, kIsDeserialized);
 
   // Set all non object fields.
-  type_parameter.set_token_pos(
-      TokenPosition::Deserialize(reader->Read<int32_t>()));
-  type_parameter.set_index(reader->Read<int16_t>());
   const uint8_t combined = reader->Read<uint8_t>();
   type_parameter.set_flags(combined >> 4);
   type_parameter.set_nullability(static_cast<Nullability>(combined & 0xf));
@@ -247,11 +235,10 @@
   READ_OBJECT_FIELDS(type_parameter, type_parameter.raw()->ptr()->from(),
                      type_parameter.raw()->ptr()->to(), kAsReference);
 
-  if (type_parameter.parameterized_function() == Function::null()) {
-    // Read in the parameterized class.
-    (*reader->ClassHandle()) =
-        Class::RawCast(reader->ReadObjectImpl(kAsReference));
-  } else {
+  // Read in the parameterized class.
+  (*reader->ClassHandle()) =
+      Class::RawCast(reader->ReadObjectImpl(kAsReference));
+  if (reader->ClassHandle()->id() == kFunctionCid) {
     (*reader->ClassHandle()) = Class::null();
   }
   type_parameter.set_parameterized_class(*reader->ClassHandle());
@@ -285,8 +272,8 @@
   writer->WriteTags(writer->GetObjectTags(this));
 
   // Write out all the non object pointer fields.
-  writer->Write<int32_t>(token_pos_.Serialize());
-  writer->Write<int16_t>(index_);
+  writer->Write<uint16_t>(base_);
+  writer->Write<uint16_t>(index_);
   const uint8_t combined = (flags_ << 4) | nullability_;
   ASSERT(flags_ == (combined >> 4));
   ASSERT(nullability_ == (combined & 0xf));
@@ -296,15 +283,10 @@
   SnapshotWriterVisitor visitor(writer, kAsReference);
   visitor.VisitPointers(from(), to());
 
-  if (parameterized_class_id_ != kFunctionCid) {
-    ASSERT(parameterized_function() == Function::null());
-    // Write out the parameterized class.
-    ClassPtr param_class =
-        writer->isolate_group()->class_table()->At(parameterized_class_id_);
-    writer->WriteObjectImpl(param_class, kAsReference);
-  } else {
-    ASSERT(parameterized_function() != Function::null());
-  }
+  // Write out the parameterized class (or Function if cid == kFunctionCid).
+  ClassPtr param_class =
+      writer->isolate_group()->class_table()->At(parameterized_class_id_);
+  writer->WriteObjectImpl(param_class, kAsReference);
 }
 
 TypeArgumentsPtr TypeArguments::ReadFrom(SnapshotReader* reader,
@@ -568,7 +550,6 @@
 MESSAGE_SNAPSHOT_UNREACHABLE(PatchClass);
 MESSAGE_SNAPSHOT_UNREACHABLE(PcDescriptors);
 MESSAGE_SNAPSHOT_UNREACHABLE(Script);
-MESSAGE_SNAPSHOT_UNREACHABLE(SignatureData);
 MESSAGE_SNAPSHOT_UNREACHABLE(SingleTargetCache);
 MESSAGE_SNAPSHOT_UNREACHABLE(String);
 MESSAGE_SNAPSHOT_UNREACHABLE(SubtypeTestCache);
@@ -580,6 +561,7 @@
 MESSAGE_SNAPSHOT_UNREACHABLE(FutureOr);
 MESSAGE_SNAPSHOT_UNREACHABLE(WeakSerializationReference);
 
+MESSAGE_SNAPSHOT_ILLEGAL(FunctionType)
 MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary);
 MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference);
 MESSAGE_SNAPSHOT_ILLEGAL(Pointer);
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 0ffffe0..9de6262 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -5513,8 +5513,10 @@
                                       const Object& owner) {
   const intptr_t kParamCount = RegExpMacroAssembler::kParamCount;
 
+  const FunctionType& signature =
+      FunctionType::Handle(zone, FunctionType::New());
   Function& fn =
-      Function::Handle(zone, Function::New(Symbols::ColonMatcher(),
+      Function::Handle(zone, Function::New(signature, Symbols::ColonMatcher(),
                                            FunctionLayout::kIrregexpFunction,
                                            true,   // Static.
                                            false,  // Not const.
@@ -5524,24 +5526,25 @@
                                            owner, TokenPosition::kMinSource));
 
   // TODO(zerny): Share these arrays between all irregexp functions.
+  // TODO(regis): Better, share a common signature.
   fn.set_num_fixed_parameters(kParamCount);
-  fn.set_parameter_types(
+  signature.set_parameter_types(
       Array::Handle(zone, Array::New(kParamCount, Heap::kOld)));
-  fn.CreateNameArrayIncludingFlags(Heap::kOld);
-  fn.SetParameterTypeAt(RegExpMacroAssembler::kParamRegExpIndex,
-                        Object::dynamic_type());
-  fn.SetParameterNameAt(RegExpMacroAssembler::kParamRegExpIndex,
-                        Symbols::This());
-  fn.SetParameterTypeAt(RegExpMacroAssembler::kParamStringIndex,
-                        Object::dynamic_type());
-  fn.SetParameterNameAt(RegExpMacroAssembler::kParamStringIndex,
-                        Symbols::string_param());
-  fn.SetParameterTypeAt(RegExpMacroAssembler::kParamStartOffsetIndex,
-                        Object::dynamic_type());
-  fn.SetParameterNameAt(RegExpMacroAssembler::kParamStartOffsetIndex,
-                        Symbols::start_index_param());
-  fn.set_result_type(Type::Handle(zone, Type::ArrayType()));
-  fn.TruncateUnusedParameterFlags();
+  signature.CreateNameArrayIncludingFlags(Heap::kOld);
+  signature.SetParameterTypeAt(RegExpMacroAssembler::kParamRegExpIndex,
+                               Object::dynamic_type());
+  signature.SetParameterNameAt(RegExpMacroAssembler::kParamRegExpIndex,
+                               Symbols::This());
+  signature.SetParameterTypeAt(RegExpMacroAssembler::kParamStringIndex,
+                               Object::dynamic_type());
+  signature.SetParameterNameAt(RegExpMacroAssembler::kParamStringIndex,
+                               Symbols::string_param());
+  signature.SetParameterTypeAt(RegExpMacroAssembler::kParamStartOffsetIndex,
+                               Object::dynamic_type());
+  signature.SetParameterNameAt(RegExpMacroAssembler::kParamStartOffsetIndex,
+                               Symbols::start_index_param());
+  signature.set_result_type(Type::Handle(zone, Type::ArrayType()));
+  signature.FinalizeNameArrays(fn);
 
   // Cache the result.
   regexp.set_function(specialization_cid, sticky, fn);
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 4e038ae..a50f2ce 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -481,6 +481,9 @@
   // we can't guarantee the supertype isn't the top type.
   if (supertype.IsTopTypeForSubtyping()) return;
 
+  // TODO(regis): Support for FLAG_trace_type_checks is missing here. Is it
+  // still useful or should we remove it everywhere?
+
   // The supertype or subtype may not be instantiated.
   if (AbstractType::InstantiateAndTestSubtype(
           &subtype, &supertype, instantiator_type_args, function_type_args)) {
@@ -537,12 +540,12 @@
   ASSERT(instance_type.IsInstantiated() ||
          (instance.IsClosure() && instance_type.IsInstantiated(kCurrentClass)));
   if (type.IsInstantiated()) {
-    OS::PrintErr("%s: '%s' %" Pd " %s '%s' %" Pd " (pc: %#" Px ").\n", message,
+    OS::PrintErr("%s: '%s' %d %s '%s' %d (pc: %#" Px ").\n", message,
                  String::Handle(instance_type.Name()).ToCString(),
-                 Class::Handle(instance_type.type_class()).id(),
+                 instance_type.type_class_id(),
                  (result.raw() == Bool::True().raw()) ? "is" : "is !",
-                 String::Handle(type.Name()).ToCString(),
-                 Class::Handle(type.type_class()).id(), caller_frame->pc());
+                 String::Handle(type.Name()).ToCString(), type.type_class_id(),
+                 caller_frame->pc());
   } else {
     // Instantiate type before printing.
     const AbstractType& instantiated_type = AbstractType::Handle(
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index e9774c0..d174d7c 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -155,6 +155,8 @@
                              const ObjectPtr raw_type) {
   if (raw_type == object_store->legacy_object_type()) {
     return kLegacyObjectType;
+  } else if (raw_type == object_store->nullable_object_type()) {
+    return kNullableObjectType;
   } else if (raw_type == object_store->null_type()) {
     return kNullType;
   } else if (raw_type == object_store->never_type()) {
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 27f02fd..2a829f3 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -401,10 +401,10 @@
   friend class PatchClass;
   friend class RegExp;
   friend class Script;
-  friend class SignatureData;
   friend class SubtypeTestCache;
   friend class TransferableTypedData;
   friend class Type;
+  friend class FunctionType;
   friend class TypedDataView;
   friend class TypeArguments;
   friend class TypeParameter;
@@ -685,6 +685,7 @@
   friend class SubtypeTestCacheLayout;
   friend class TransferableTypedDataLayout;
   friend class TypeLayout;
+  friend class FunctionTypeLayout;
   friend class TypeArgumentsLayout;
   friend class TypeParameterLayout;
   friend class TypeRefLayout;
diff --git a/runtime/vm/stub_code_arm64_test.cc b/runtime/vm/stub_code_arm64_test.cc
index 0939ef2..d6fb518 100644
--- a/runtime/vm/stub_code_arm64_test.cc
+++ b/runtime/vm/stub_code_arm64_test.cc
@@ -28,9 +28,10 @@
       Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name =
       String::ZoneHandle(Symbols::New(Thread::Current(), name));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   Function& function = Function::ZoneHandle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kNoSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kNoSource));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_arm_test.cc b/runtime/vm/stub_code_arm_test.cc
index ea6a6bc..767e7ba 100644
--- a/runtime/vm/stub_code_arm_test.cc
+++ b/runtime/vm/stub_code_arm_test.cc
@@ -28,9 +28,10 @@
       Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name =
       String::ZoneHandle(Symbols::New(Thread::Current(), name));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   Function& function = Function::ZoneHandle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kNoSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kNoSource));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_ia32_test.cc b/runtime/vm/stub_code_ia32_test.cc
index b5c4388..202b487 100644
--- a/runtime/vm/stub_code_ia32_test.cc
+++ b/runtime/vm/stub_code_ia32_test.cc
@@ -28,9 +28,10 @@
       Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name =
       String::ZoneHandle(Symbols::New(Thread::Current(), name));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   Function& function = Function::ZoneHandle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kMinSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kMinSource));
   return &function;
 }
 
diff --git a/runtime/vm/stub_code_test.cc b/runtime/vm/stub_code_test.cc
index 4b8649b..37ca980 100644
--- a/runtime/vm/stub_code_test.cc
+++ b/runtime/vm/stub_code_test.cc
@@ -18,9 +18,10 @@
   const Class& owner_class = Class::Handle(
       Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name = String::ZoneHandle(Symbols::New(thread, name));
-  const Function& function = Function::ZoneHandle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kMinSource));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
+  Function& function = Function::ZoneHandle(Function::New(
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kNoSource));
   const Array& functions = Array::Handle(Array::New(1));
   functions.SetAt(0, function);
   {
diff --git a/runtime/vm/stub_code_x64_test.cc b/runtime/vm/stub_code_x64_test.cc
index b41ec88..290e106 100644
--- a/runtime/vm/stub_code_x64_test.cc
+++ b/runtime/vm/stub_code_x64_test.cc
@@ -28,9 +28,10 @@
       Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name =
       String::ZoneHandle(Symbols::New(Thread::Current(), name));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   Function& function = Function::ZoneHandle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kNoSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kNoSource));
   return &function;
 }
 
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 63bcae3..3ab0824 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -247,7 +247,6 @@
   V(SecondArg, "y")                                                            \
   V(Set, "set")                                                                \
   V(SetterPrefix, "set:")                                                      \
-  V(SignatureData, "SignatureData")                                            \
   V(SingleTargetCache, "SingleTargetCache")                                    \
   V(SizeOfStructField, "#sizeOf")                                              \
   V(SpaceExtendsSpace, " extends ")                                            \
@@ -401,11 +400,12 @@
   V(_SyncIterableConstructor, "_SyncIterable.")                                \
   V(_SyncIterator, "_SyncIterator")                                            \
   V(_TransferableTypedDataImpl, "_TransferableTypedDataImpl")                  \
+  V(_AbstractType, "_AbstractType")                                            \
   V(_Type, "_Type")                                                            \
+  V(_FunctionType, "_FunctionType")                                            \
   V(_TypeParameter, "_TypeParameter")                                          \
   V(_TypeRef, "_TypeRef")                                                      \
   V(_TypeVariableMirror, "_TypeVariableMirror")                                \
-  V(_TypedefMirror, "_TypedefMirror")                                          \
   V(_Uint16ArrayFactory, "Uint16List.")                                        \
   V(_Uint16ArrayView, "_Uint16ArrayView")                                      \
   V(_Uint16List, "_Uint16List")                                                \
diff --git a/runtime/vm/tagged_pointer.h b/runtime/vm/tagged_pointer.h
index 4954982..0e6cdfa 100644
--- a/runtime/vm/tagged_pointer.h
+++ b/runtime/vm/tagged_pointer.h
@@ -233,7 +233,6 @@
 DEFINE_TAGGED_POINTER(PatchClass, Object)
 DEFINE_TAGGED_POINTER(Function, Object)
 DEFINE_TAGGED_POINTER(ClosureData, Object)
-DEFINE_TAGGED_POINTER(SignatureData, Object)
 DEFINE_TAGGED_POINTER(FfiTrampolineData, Object)
 DEFINE_TAGGED_POINTER(Field, Object)
 DEFINE_TAGGED_POINTER(Script, Object)
@@ -270,6 +269,7 @@
 DEFINE_TAGGED_POINTER(TypeArguments, Instance)
 DEFINE_TAGGED_POINTER(AbstractType, Instance)
 DEFINE_TAGGED_POINTER(Type, AbstractType)
+DEFINE_TAGGED_POINTER(FunctionType, AbstractType)
 DEFINE_TAGGED_POINTER(TypeRef, AbstractType)
 DEFINE_TAGGED_POINTER(TypeParameter, AbstractType)
 DEFINE_TAGGED_POINTER(Closure, Instance)
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 4e4d17f..3e4eb24 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -431,9 +431,10 @@
       Class::New(lib, class_name, script, TokenPosition::kNoSource));
   const String& function_name =
       String::ZoneHandle(Symbols::New(Thread::Current(), name));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   Function& function = Function::ZoneHandle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, owner_class, TokenPosition::kNoSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, owner_class, TokenPosition::kNoSource));
   return &function;
 }
 
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index f9a7c85..d73c5b8 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -35,7 +35,7 @@
     const AbstractType& type) const {
   NoSafepointScope no_safepoint;
   Zone* Z = Thread::Current()->zone();
-  if (type.IsType() && !type.IsFunctionType()) {
+  if (type.IsType()) {
     const intptr_t cid = Type::Cast(type).type_class_id();
     ClassTable* class_table = IsolateGroup::Current()->class_table();
     klass_ = class_table->At(cid);
@@ -121,6 +121,12 @@
     }
   }
 
+  if (type.IsFunctionType()) {
+    const bool nullable = Instance::NullIsAssignableTo(type);
+    return nullable ? StubCode::DefaultNullableTypeTest().raw()
+                    : StubCode::DefaultTypeTest().raw();
+  }
+
   if (type.IsType()) {
     const bool should_specialize = !FLAG_precompiled_mode && lazy_specialize;
     const bool nullable = Instance::NullIsAssignableTo(type);
@@ -685,7 +691,7 @@
     ScopedHandle<TypeArguments> to_type_arguments(&type_arguments_handles_);
 
     *to_type_arguments = TypeArguments::null();
-    *to = Type::New(klass_, *to_type_arguments, type.token_pos());
+    *to = Type::New(klass_, *to_type_arguments);
 
     *to_type_arguments = from.arguments();
     to->set_arguments(InstantiateTypeArguments(klass_, *to_type_arguments));
diff --git a/runtime/vm/type_testing_stubs.h b/runtime/vm/type_testing_stubs.h
index 09c6f1d..36fc47d 100644
--- a/runtime/vm/type_testing_stubs.h
+++ b/runtime/vm/type_testing_stubs.h
@@ -193,17 +193,7 @@
  private:
   bool FindClassFromType(const AbstractType& type) {
     if (type.IsTypeParameter()) {
-      const TypeParameter& parameter = TypeParameter::Cast(type);
-      if (!parameter.IsClassTypeParameter()) {
-        return false;
-      }
-      if (klass_.IsNull()) {
-        klass_ = parameter.parameterized_class();
-      } else {
-        // Dart has no support for nested classes.
-        ASSERT(klass_.raw() == parameter.parameterized_class());
-      }
-      return true;
+      return false;
     } else if (type.IsFunctionType()) {
       // No support for function types yet.
       return false;
diff --git a/runtime/vm/type_testing_stubs_test.cc b/runtime/vm/type_testing_stubs_test.cc
index e2d0017..c0a3800 100644
--- a/runtime/vm/type_testing_stubs_test.cc
+++ b/runtime/vm/type_testing_stubs_test.cc
@@ -169,9 +169,10 @@
       Class::Handle(thread->isolate_group()->class_table()->At(kInstanceCid));
   const auto& symbol = String::Handle(
       Symbols::New(thread, OS::SCreate(thread->zone(), "TTSTest")));
-  const auto& function = Function::Handle(
-      Function::New(symbol, FunctionLayout::kRegularFunction, false, false,
-                    false, false, false, klass, TokenPosition::kNoSource));
+  const auto& signature = FunctionType::ZoneHandle(FunctionType::New());
+  const auto& function = Function::Handle(Function::New(
+      signature, symbol, FunctionLayout::kRegularFunction, false, false, false,
+      false, false, klass, TokenPosition::kNoSource));
   compiler::ObjectPoolBuilder pool_builder;
   const auto& invoke_tts = Code::Handle(
       StubCode::Generate("InvokeTTS", &pool_builder, &GenerateInvokeTTSStub));
@@ -484,8 +485,7 @@
              ExpectFailedViaTTS);
 
   // <...> as Base<Object>
-  auto& type_base = AbstractType::Handle(
-      Type::New(class_base, tav_object, TokenPosition::kNoSource));
+  auto& type_base = AbstractType::Handle(Type::New(class_base, tav_object));
   FinalizeAndCanonicalize(&type_base);
   RunTTSTest(obj_i, type_base, tav_null, tav_null, ExpectLazilyFailedViaTTS,
              ExpectFailedViaTTS);
@@ -528,8 +528,8 @@
              ExpectFailedViaTTS);
 
   // <...> as I<Object, dynamic>
-  auto& type_i_object_dynamic = AbstractType::Handle(
-      Type::New(class_i, tav_object_dynamic, TokenPosition::kNoSource));
+  auto& type_i_object_dynamic =
+      AbstractType::Handle(Type::New(class_i, tav_object_dynamic));
   FinalizeAndCanonicalize(&type_i_object_dynamic);
   RunTTSTest(obj_i, type_i_object_dynamic, tav_null, tav_null,
              ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
@@ -555,8 +555,8 @@
   //
   //   obj as I<dynamic, T>
   //
-  auto& type_dynamic_t = AbstractType::Handle(
-      Type::New(class_i, tav_dynamic_t, TokenPosition::kNoSource));
+  auto& type_dynamic_t =
+      AbstractType::Handle(Type::New(class_i, tav_dynamic_t));
   FinalizeAndCanonicalize(&type_dynamic_t);
   RunTTSTest(obj_i, type_dynamic_t, tav_object, tav_null,
              ExpectLazilyHandledViaSTC, ExpectHandledViaSTC);
@@ -658,8 +658,8 @@
   tav_int.SetTypeAt(0, type_int);
   CanonicalizeTAV(&tav_int);
 
-  auto& type_i_object_dynamic = AbstractType::Handle(
-      Type::New(class_i, tav_object_dynamic, TokenPosition::kNoSource));
+  auto& type_i_object_dynamic =
+      AbstractType::Handle(Type::New(class_i, tav_object_dynamic));
   FinalizeAndCanonicalize(&type_i_object_dynamic);
   const auto& tav_iod = TypeArguments::Handle(TypeArguments::New(1));
   tav_iod.SetTypeAt(0, type_i_object_dynamic);
@@ -677,8 +677,8 @@
   //
 
   // <...> as Base<I<Object, dynamic>>
-  auto& type_base_i_object_dynamic = AbstractType::Handle(
-      Type::New(class_base, tav_iod, TokenPosition::kNoSource));
+  auto& type_base_i_object_dynamic =
+      AbstractType::Handle(Type::New(class_base, tav_iod));
   FinalizeAndCanonicalize(&type_base_i_object_dynamic);
   RunTTSTest(obj_baseb2int, type_base_i_object_dynamic, tav_null, tav_null,
              ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
@@ -701,8 +701,7 @@
   const auto& tav_baset = TypeArguments::Handle(TypeArguments::New(1));
   tav_baset.SetTypeAt(
       0, TypeParameter::Handle(GetClassTypeParameter(class_base, "T")));
-  auto& type_base_t = AbstractType::Handle(
-      Type::New(class_base, tav_baset, TokenPosition::kNoSource));
+  auto& type_base_t = AbstractType::Handle(Type::New(class_base, tav_baset));
   FinalizeAndCanonicalize(&type_base_t);
   RunTTSTest(obj_baseint, type_base_t, tav_int, tav_null,
              ExpectLazilyHandledViaTTS, ExpectHandledViaTTS);
@@ -713,8 +712,7 @@
   const auto& tav_baseb = TypeArguments::Handle(TypeArguments::New(1));
   tav_baseb.SetTypeAt(
       0, TypeParameter::Handle(GetFunctionTypeParameter(fun_generic, "B")));
-  auto& type_base_b = AbstractType::Handle(
-      Type::New(class_base, tav_baseb, TokenPosition::kNoSource));
+  auto& type_base_b = AbstractType::Handle(Type::New(class_base, tav_baseb));
   FinalizeAndCanonicalize(&type_base_b);
   // With B == int
   RunTTSTest(obj_baseint, type_base_b, tav_null, tav_dynamic_int,
@@ -737,8 +735,8 @@
 
   //   <...> as I<dynamic, String>
   RELEASE_ASSERT(class_i.is_implemented());
-  auto& type_i_dynamic_string = Type::Handle(
-      Type::New(class_i, tav_dynamic_string, TokenPosition::kNoSource));
+  auto& type_i_dynamic_string =
+      Type::Handle(Type::New(class_i, tav_dynamic_string));
   type_i_dynamic_string = type_i_dynamic_string.ToNullability(
       Nullability::kNonNullable, Heap::kNew);
   FinalizeAndCanonicalize(&type_i_dynamic_string);
@@ -751,14 +749,12 @@
   const auto& tav_t = TypeArguments::Handle(TypeArguments::New(1));
   tav_t.SetTypeAt(
       0, TypeParameter::Handle(GetClassTypeParameter(class_base, "T")));
-  auto& type_a2_t =
-      Type::Handle(Type::New(class_a2, tav_t, TokenPosition::kNoSource));
+  auto& type_a2_t = Type::Handle(Type::New(class_a2, tav_t));
   type_a2_t = type_a2_t.ToNullability(Nullability::kLegacy, Heap::kNew);
   FinalizeAndCanonicalize(&type_a2_t);
   const auto& tav_a2_t = TypeArguments::Handle(TypeArguments::New(1));
   tav_a2_t.SetTypeAt(0, type_a2_t);
-  auto& type_base_a2_t =
-      Type::Handle(Type::New(class_base, tav_a2_t, TokenPosition::kNoSource));
+  auto& type_base_a2_t = Type::Handle(Type::New(class_base, tav_a2_t));
   type_base_a2_t =
       type_base_a2_t.ToNullability(Nullability::kNonNullable, Heap::kNew);
   FinalizeAndCanonicalize(&type_base_a2_t);
@@ -770,14 +766,12 @@
   //   <...> as Base<A2<A1>>
   const auto& tav_a1 = TypeArguments::Handle(TypeArguments::New(1));
   tav_a1.SetTypeAt(0, type_a1);
-  auto& type_a2_a1 =
-      Type::Handle(Type::New(class_a2, tav_a1, TokenPosition::kNoSource));
+  auto& type_a2_a1 = Type::Handle(Type::New(class_a2, tav_a1));
   type_a2_a1 = type_a2_a1.ToNullability(Nullability::kLegacy, Heap::kNew);
   FinalizeAndCanonicalize(&type_a2_a1);
   const auto& tav_a2_a1 = TypeArguments::Handle(TypeArguments::New(1));
   tav_a2_a1.SetTypeAt(0, type_a2_a1);
-  auto& type_base_a2_a1 =
-      Type::Handle(Type::New(class_base, tav_a2_a1, TokenPosition::kNoSource));
+  auto& type_base_a2_a1 = Type::Handle(Type::New(class_base, tav_a2_a1));
   type_base_a2_a1 =
       type_base_a2_a1.ToNullability(Nullability::kNonNullable, Heap::kNew);
   FinalizeAndCanonicalize(&type_base_a2_a1);
@@ -812,8 +806,7 @@
   const auto& dst_tav = TypeArguments::Handle(TypeArguments::New(1));
   dst_tav.SetTypeAt(0,
                     TypeParameter::Handle(GetClassTypeParameter(class_b, "T")));
-  auto& dst_type =
-      Type::Handle(Type::New(class_b, dst_tav, TokenPosition::kNoSource));
+  auto& dst_type = Type::Handle(Type::New(class_b, dst_tav));
   FinalizeAndCanonicalize(&dst_type);
   const auto& cint_tav =
       TypeArguments::Handle(Instance::Cast(acint).GetTypeArguments());
@@ -849,6 +842,7 @@
 
   const auto& dst_type_t =
       TypeParameter::Handle(GetClassTypeParameter(class_a, "T"));
+
   const auto& dst_type_h =
       TypeParameter::Handle(GetFunctionTypeParameter(fun_generic, "H"));
 
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 3364072..ac3dd5e 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -664,9 +664,10 @@
   const Library& lib = Library::Handle(Library::CoreLibrary());
   const Class& cls = Class::ZoneHandle(
       Class::New(lib, function_name, script, TokenPosition::kMinSource));
+  const FunctionType& signature = FunctionType::ZoneHandle(FunctionType::New());
   Function& function = Function::ZoneHandle(Function::New(
-      function_name, FunctionLayout::kRegularFunction, true, false, false,
-      false, false, cls, TokenPosition::kMinSource));
+      signature, function_name, FunctionLayout::kRegularFunction, true, false,
+      false, false, false, cls, TokenPosition::kMinSource));
   code_ = Code::FinalizeCodeAndNotify(function, nullptr, assembler_,
                                       Code::PoolAttachment::kAttachPool);
   code_.set_owner(function);
diff --git a/sdk/lib/_internal/vm/lib/mirrors_impl.dart b/sdk/lib/_internal/vm/lib/mirrors_impl.dart
index acd95e1..a938cf7 100644
--- a/sdk/lib/_internal/vm/lib/mirrors_impl.dart
+++ b/sdk/lib/_internal/vm/lib/mirrors_impl.dart
@@ -754,8 +754,8 @@
 }
 
 class _FunctionTypeMirror extends _ClassMirror implements FunctionTypeMirror {
-  final _functionReflectee;
-  _FunctionTypeMirror._(reflectee, this._functionReflectee, reflectedType)
+  final _signatureReflectee;
+  _FunctionTypeMirror._(reflectee, this._signatureReflectee, reflectedType)
       : super._(reflectee, reflectedType, null, null, false, false, false,
             false, false);
 
@@ -773,7 +773,7 @@
   MethodMirror get callMethod {
     var m = _callMethod;
     if (m != null) return m;
-    return _callMethod = _FunctionTypeMirror_call_method(_functionReflectee);
+    return _callMethod = _FunctionTypeMirror_call_method(_signatureReflectee);
   }
 
   TypeMirror? _returnType;
@@ -781,7 +781,7 @@
     var t = _returnType;
     if (t != null) return t;
     return _returnType =
-        reflectType(_FunctionTypeMirror_return_type(_functionReflectee));
+        reflectType(_FunctionTypeMirror_return_type(_signatureReflectee));
   }
 
   List<ParameterMirror>? _parameters;
@@ -789,7 +789,7 @@
     var p = _parameters;
     if (p != null) return p;
     return _parameters = new UnmodifiableListView<ParameterMirror>(
-        _FunctionTypeMirror_parameters(_functionReflectee)
+        _FunctionTypeMirror_parameters(_signatureReflectee)
             .cast<ParameterMirror>());
   }
 
@@ -802,13 +802,13 @@
 
   String toString() => "FunctionTypeMirror on '${_n(simpleName)}'";
 
-  MethodMirror _FunctionTypeMirror_call_method(functionReflectee)
+  MethodMirror _FunctionTypeMirror_call_method(signatureReflectee)
       native "FunctionTypeMirror_call_method";
 
-  static Type _FunctionTypeMirror_return_type(functionReflectee)
+  static Type _FunctionTypeMirror_return_type(signatureReflectee)
       native "FunctionTypeMirror_return_type";
 
-  List<dynamic> _FunctionTypeMirror_parameters(functionReflectee)
+  List<dynamic> _FunctionTypeMirror_parameters(signatureReflectee)
       native "FunctionTypeMirror_parameters";
 }
 
@@ -884,9 +884,8 @@
   String toString() => "TypeVariableMirror on '${_n(simpleName)}'";
 
   bool operator ==(Object other) {
-    return other is TypeVariableMirror &&
-        simpleName == other.simpleName &&
-        owner == other.owner;
+    return other is TypeVariableMirror && simpleName == other.simpleName;
+    // Type variables do not refer to owner.
   }
 
   int get hashCode => simpleName.hashCode;
@@ -914,110 +913,6 @@
       native "TypeVariableMirror_upper_bound";
 }
 
-class _TypedefMirror extends _DeclarationMirror
-    implements TypedefMirror, _TypeMirror {
-  final Type _reflectedType;
-  final bool _isGeneric;
-  final bool _isGenericDeclaration;
-
-  _TypedefMirror(reflectee, this._reflectedType, String simpleName,
-      this._isGeneric, this._isGenericDeclaration, this._owner)
-      : super._(reflectee, _s(simpleName));
-
-  bool get isTopLevel => true;
-
-  DeclarationMirror? _owner;
-  DeclarationMirror? get owner {
-    var o = _owner;
-    if (o != null) return o;
-    var uri = _ClassMirror._libraryUri(_reflectee);
-    return _owner = currentMirrorSystem().libraries[Uri.parse(uri)];
-  }
-
-  _FunctionTypeMirror? _referent;
-  FunctionTypeMirror get referent {
-    var r = _referent;
-    if (r != null) return r;
-    var result = _nativeReferent(_reflectedType) as _FunctionTypeMirror;
-    result._instantiator = _reflectedType;
-    return _referent = result;
-  }
-
-  bool get hasReflectedType => !_isGenericDeclaration;
-  Type get reflectedType {
-    if (!hasReflectedType) {
-      throw new UnsupportedError(
-          "Declarations of generics have no reflected type");
-    }
-    return _reflectedType;
-  }
-
-  bool get isOriginalDeclaration => !_isGeneric || _isGenericDeclaration;
-
-  TypedefMirror get originalDeclaration {
-    if (isOriginalDeclaration) {
-      return this;
-    } else {
-      return _nativeDeclaration(_reflectedType);
-    }
-  }
-
-  List<TypeVariableMirror>? _typeVariables;
-  List<TypeVariableMirror> get typeVariables {
-    var v = _typeVariables;
-    if (v != null) return v;
-
-    var result = <TypeVariableMirror>[];
-    List params = _ClassMirror._ClassMirror_type_variables(_reflectee);
-    TypedefMirror owner = originalDeclaration;
-    var mirror;
-    for (var i = 0; i < params.length; i += 2) {
-      mirror = new _TypeVariableMirror._(params[i + 1], params[i], owner);
-      result.add(mirror);
-    }
-    return _typeVariables =
-        new UnmodifiableListView<TypeVariableMirror>(result);
-  }
-
-  List<TypeMirror>? _typeArguments;
-  List<TypeMirror> get typeArguments {
-    var a = _typeArguments;
-    if (a != null) return a;
-
-    if (_isGenericDeclaration) {
-      return _typeArguments = const <TypeMirror>[];
-    } else {
-      return _typeArguments = new UnmodifiableListView<TypeMirror>(
-          _ClassMirror._computeTypeArguments(_reflectedType)
-              .cast<TypeMirror>());
-    }
-  }
-
-  String toString() => "TypedefMirror on '${_n(simpleName)}'";
-
-  bool isSubtypeOf(TypeMirror other) {
-    if (other == currentMirrorSystem().dynamicType) return true;
-    if (other == currentMirrorSystem().voidType) return true;
-    if (other == currentMirrorSystem().neverType) return false;
-    return _subtypeTest(_reflectedType, (other as _TypeMirror)._reflectedType);
-  }
-
-  bool isAssignableTo(TypeMirror other) {
-    if (other == currentMirrorSystem().dynamicType) return true;
-    if (other == currentMirrorSystem().voidType) return true;
-    if (other == currentMirrorSystem().neverType) return false;
-    final otherReflectedType = (other as _TypeMirror)._reflectedType;
-    return _subtypeTest(_reflectedType, otherReflectedType) ||
-        _subtypeTest(otherReflectedType, _reflectedType);
-  }
-
-  static FunctionTypeMirror _nativeReferent(reflectedType)
-      native "TypedefMirror_referent";
-
-  static TypedefMirror _nativeDeclaration(reflectedType)
-      native "TypedefMirror_declaration";
-}
-
 Symbol _asSetter(Symbol getter, LibraryMirror library) {
   var unwrapped = MirrorSystem.getName(getter);
   return MirrorSystem.getSymbol('${unwrapped}=', library);
diff --git a/sdk/lib/_internal/vm/lib/object_patch.dart b/sdk/lib/_internal/vm/lib/object_patch.dart
index fe23069..ac85705 100644
--- a/sdk/lib/_internal/vm/lib/object_patch.dart
+++ b/sdk/lib/_internal/vm/lib/object_patch.dart
@@ -56,7 +56,7 @@
 
   @patch
   @pragma("vm:recognized", "asm-intrinsic")
-  @pragma("vm:exact-result-type", "dart:core#_Type")
+  // Result type is either "dart:core#_Type" or "dart:core#_FunctionType".
   Type get runtimeType native "Object_runtimeType";
 
   @pragma("vm:recognized", "asm-intrinsic")
diff --git a/sdk/lib/_internal/vm/lib/type_patch.dart b/sdk/lib/_internal/vm/lib/type_patch.dart
index 52be775..c818922 100644
--- a/sdk/lib/_internal/vm/lib/type_patch.dart
+++ b/sdk/lib/_internal/vm/lib/type_patch.dart
@@ -6,12 +6,12 @@
 
 // These Dart classes correspond to the VM internal implementation classes.
 
-// Equivalent of RawAbstractType.
+// Equivalent of AbstractTypeLayout.
 abstract class _AbstractType implements Type {
   String toString() native "AbstractType_toString";
 }
 
-// Equivalent of RawType.
+// Equivalent of TypeLayout.
 @pragma("vm:entry-point")
 class _Type extends _AbstractType {
   factory _Type._uninstantiable() {
@@ -27,7 +27,23 @@
   bool operator ==(other) native "Type_equality";
 }
 
-// Equivalent of RawTypeRef.
+// Equivalent of FunctionTypeLayout.
+@pragma("vm:entry-point")
+class _FunctionType extends _AbstractType {
+  factory _FunctionType._uninstantiable() {
+    throw "Unreachable";
+  }
+
+  @pragma("vm:recognized", "asm-intrinsic")
+  @pragma("vm:exact-result-type", "dart:core#_Smi")
+  int get hashCode native "FunctionType_getHashCode";
+
+  @pragma("vm:recognized", "asm-intrinsic")
+  @pragma("vm:exact-result-type", bool)
+  bool operator ==(other) native "FunctionType_equality";
+}
+
+// Equivalent of TypeRefLayout.
 @pragma("vm:entry-point")
 class _TypeRef extends _AbstractType {
   factory _TypeRef._uninstantiable() {
@@ -35,7 +51,7 @@
   }
 }
 
-// Equivalent of RawTypeParameter.
+// Equivalent of TypeParameterLayout.
 @pragma("vm:entry-point")
 class _TypeParameter extends _AbstractType {
   factory _TypeParameter._uninstantiable() {
diff --git a/tests/lib/mirrors/class_mirror_type_variables_expect.dart b/tests/lib/mirrors/class_mirror_type_variables_expect.dart
index adee190..847bd7f 100644
--- a/tests/lib/mirrors/class_mirror_type_variables_expect.dart
+++ b/tests/lib/mirrors/class_mirror_type_variables_expect.dart
@@ -70,7 +70,6 @@
   Expect.isFalse(bZBound.isOriginalDeclaration);
   Expect.isFalse(cZBound.isOriginalDeclaration);
 
-  Expect.notEquals(bZBound, cZBound);
   Expect.equals(b, bZBound.originalDeclaration);
   Expect.equals(b, cZBound.originalDeclaration);
 
@@ -83,10 +82,7 @@
   Expect.equals(c, cZ.owner);
   Expect.equals(b, bZBoundTypeVariable.owner);
   Expect.equals(b, cZBoundTypeVariable.owner);
-  Expect.equals(b, bZBoundTypeArgument.owner);
-  Expect.equals(c, cZBoundTypeArgument.owner);
 
-  Expect.notEquals(bZ, cZ);
   Expect.equals(bZ, bZBoundTypeArgument);
   Expect.equals(cZ, cZBoundTypeArgument);
   Expect.equals(bZ, bZBoundTypeVariable);
diff --git a/tests/lib/mirrors/generics_test.dart b/tests/lib/mirrors/generics_test.dart
index fface13..ce9d8f0 100644
--- a/tests/lib/mirrors/generics_test.dart
+++ b/tests/lib/mirrors/generics_test.dart
@@ -158,8 +158,6 @@
 
   Expect.equals(reflectClass(A).typeVariables[0].owner, reflectClass(A));
   Expect.equals(reflectClass(Z).typeVariables[0].owner, reflectClass(Z));
-  Expect.notEquals(
-      reflectClass(A).typeVariables[0], reflectClass(Z).typeVariables[0]);
   Expect.equals(
       reflectClass(A).typeVariables[0], reflectClass(A).typeVariables[0]);
 }
diff --git a/tests/lib/mirrors/parameter_test.dart b/tests/lib/mirrors/parameter_test.dart
index d096711..2a5eff6 100644
--- a/tests/lib/mirrors/parameter_test.dart
+++ b/tests/lib/mirrors/parameter_test.dart
@@ -184,7 +184,7 @@
       '[Parameter(s(a) in s(foo),'
       ' type = Class(s(int) in s(dart.core), top-level)), '
       'Parameter(s(b) in s(foo),'
-      ' type = TypeVariable(s(S) in s(C),'
+      ' type = TypeVariable(s(S) in s(Null),'
       ' upperBound = Class(s(int) in s(dart.core), top-level)))]',
       fooInC.parameters);
 
@@ -192,10 +192,10 @@
   expect('Method(s(bar) in s(C))', barInC);
   expect(
       '[Parameter(s(a) in s(bar),'
-      ' type = TypeVariable(s(S) in s(C),'
+      ' type = TypeVariable(s(S) in s(Null),'
       ' upperBound = Class(s(int) in s(dart.core), top-level))), '
       'Parameter(s(b) in s(bar),'
-      ' type = TypeVariable(s(T) in s(C),'
+      ' type = TypeVariable(s(T) in s(Null),'
       ' upperBound = Class(s(Object) in s(dart.core), top-level))), '
       'Parameter(s(c) in s(bar),'
       ' type = Class(s(num) in s(dart.core), top-level))]',
diff --git a/tests/lib_2/mirrors/class_mirror_type_variables_expect.dart b/tests/lib_2/mirrors/class_mirror_type_variables_expect.dart
index adee190..847bd7f 100644
--- a/tests/lib_2/mirrors/class_mirror_type_variables_expect.dart
+++ b/tests/lib_2/mirrors/class_mirror_type_variables_expect.dart
@@ -70,7 +70,6 @@
   Expect.isFalse(bZBound.isOriginalDeclaration);
   Expect.isFalse(cZBound.isOriginalDeclaration);
 
-  Expect.notEquals(bZBound, cZBound);
   Expect.equals(b, bZBound.originalDeclaration);
   Expect.equals(b, cZBound.originalDeclaration);
 
@@ -83,10 +82,7 @@
   Expect.equals(c, cZ.owner);
   Expect.equals(b, bZBoundTypeVariable.owner);
   Expect.equals(b, cZBoundTypeVariable.owner);
-  Expect.equals(b, bZBoundTypeArgument.owner);
-  Expect.equals(c, cZBoundTypeArgument.owner);
 
-  Expect.notEquals(bZ, cZ);
   Expect.equals(bZ, bZBoundTypeArgument);
   Expect.equals(cZ, cZBoundTypeArgument);
   Expect.equals(bZ, bZBoundTypeVariable);
diff --git a/tests/lib_2/mirrors/generics_test.dart b/tests/lib_2/mirrors/generics_test.dart
index fface13..ce9d8f0 100644
--- a/tests/lib_2/mirrors/generics_test.dart
+++ b/tests/lib_2/mirrors/generics_test.dart
@@ -158,8 +158,6 @@
 
   Expect.equals(reflectClass(A).typeVariables[0].owner, reflectClass(A));
   Expect.equals(reflectClass(Z).typeVariables[0].owner, reflectClass(Z));
-  Expect.notEquals(
-      reflectClass(A).typeVariables[0], reflectClass(Z).typeVariables[0]);
   Expect.equals(
       reflectClass(A).typeVariables[0], reflectClass(A).typeVariables[0]);
 }
diff --git a/tests/lib_2/mirrors/parameter_test.dart b/tests/lib_2/mirrors/parameter_test.dart
index d096711..2a5eff6 100644
--- a/tests/lib_2/mirrors/parameter_test.dart
+++ b/tests/lib_2/mirrors/parameter_test.dart
@@ -184,7 +184,7 @@
       '[Parameter(s(a) in s(foo),'
       ' type = Class(s(int) in s(dart.core), top-level)), '
       'Parameter(s(b) in s(foo),'
-      ' type = TypeVariable(s(S) in s(C),'
+      ' type = TypeVariable(s(S) in s(Null),'
       ' upperBound = Class(s(int) in s(dart.core), top-level)))]',
       fooInC.parameters);
 
@@ -192,10 +192,10 @@
   expect('Method(s(bar) in s(C))', barInC);
   expect(
       '[Parameter(s(a) in s(bar),'
-      ' type = TypeVariable(s(S) in s(C),'
+      ' type = TypeVariable(s(S) in s(Null),'
       ' upperBound = Class(s(int) in s(dart.core), top-level))), '
       'Parameter(s(b) in s(bar),'
-      ' type = TypeVariable(s(T) in s(C),'
+      ' type = TypeVariable(s(T) in s(Null),'
       ' upperBound = Class(s(Object) in s(dart.core), top-level))), '
       'Parameter(s(c) in s(bar),'
       ' type = Class(s(num) in s(dart.core), top-level))]',
diff --git a/tools/VERSION b/tools/VERSION
index 947dc6d..5346579d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 203
+PRERELEASE 204
 PRERELEASE_PATCH 0
\ No newline at end of file