[vm/compiler] Move argument shape (not type) checks out of closures.

This CL performs the following checks in the invoke field dispatcher for
dynamic closure calls when lazy dispatchers are enabled:

* The provided function type arguments vector (if any) has the correct
  length.

* No function type arguments should be provided if the closure has
  delayed type arguments.

* All required arguments (positional in all modes, named in appropriate
  null safety modes) have been provided by the caller.

* If there are optional positional arguments, an appropriate number
  has been provided.

* If there are optional named arguments, their names are valid.

Since the runtime already handles checking the argument shapes when lazy
dispatchers are disabled, these checks are now completely removed from
closure bodies in all cases. Thus, the only remaining checks in closure
bodies are the type checks performed by AssertSubtype and
AssertAssignable when lazy dispatchers are enabled.

Changes in the Flutter Gallery:

* ARM7, release: -3.61% instructions, -2.19% total
* ARM7, sizeopt: -3.62% instructions, -2.55% total
* ARM8, release: -3.66% instructions, -1.98% total
* ARM8, sizeopt: -3.65% instructions, -2.37% total

Most of these changes are already exercised by existing tests such as
(but not limited to):

* corelib{,_2}/dynamic_nosuchmethod_test
* language{,_2}/call/call_test
* language{,_2}/closure/tearoff_dynamic_test
* language{,_2}/generic/function_bounds_test
* language{,_2}/parameter/named_with_conversions_test
* language{,_2}/vm/no_such_args_error_message_vm_test

I've added one test to specifically check the interaction between
dynamic calls and required named parameters. There is some coverage in
other NNBD tests, but those are not directly focused on testing this
specifically.

Other changes:

* Adds initial cached ranges for certain BinarySmiOp and ShiftIntegerOp
  instructions when the RHS is a constant, to avoid false negatives for
  deoptimization and throw checks prior to range analysis.

* Adds new slots for various Function fields.

* Adds the ability to define unboxed native slots, which are always
  unboxed after retrieval even in unoptimized code. In the first
  iteration, the backend only handles loads from Uint32 unboxed native
  slots. Part of https://github.com/dart-lang/sdk/issues/42793.

* Removed the special handling for loading from non-nullable int fields
  in AOT compilation. Instead, their treatment is unified with the
  treatment of the new unboxed native fields, since the source field is
  always unboxed and the result of the load is also always unboxed, as
  code involving them is always optimized.

Bug: https://github.com/dart-lang/sdk/issues/40813
Change-Id: Ia02aa3e872c1fefd906fd67b55021ea1797556e4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155604
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index 6a322f8..39ae12a 100644
--- a/pkg/vm/lib/bytecode/dbc.dart
+++ b/pkg/vm/lib/bytecode/dbc.dart
@@ -106,6 +106,7 @@
   // Prologue and stack management.
   kEntry,
   kEntry_Wide,
+  // TODO(alexmarkov): cleanup now unused EntryFixed instruction.
   kEntryFixed,
   kEntryFixed_Wide,
   kEntryOptional,
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 88cff2c..e2ddd4d 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -1988,8 +1988,6 @@
       }
 
       asm.emitFrame(locals.frameSize - locals.numParameters);
-    } else if (isClosure) {
-      asm.emitEntryFixed(locals.numParameters, locals.frameSize);
     } else {
       asm.emitEntry(locals.frameSize);
     }
@@ -2015,14 +2013,6 @@
       _handleDefaultTypeArguments(function, done);
 
       asm.bind(done);
-    } else if (isClosure &&
-        !(parentFunction != null &&
-            parentFunction.dartAsyncMarker != AsyncMarker.Sync)) {
-      // Closures can be called dynamically with arbitrary arguments,
-      // so they should check number of type arguments, even if
-      // closure is not generic.
-      // Synthetic async_op closures don't need this check.
-      asm.emitCheckFunctionTypeArgs(0, locals.scratchVarIndexInFrame);
     }
 
     // Open initial scope before the first CheckStack, as VM might
@@ -2218,8 +2208,9 @@
         initializedPosition);
   }
 
-  bool get canSkipTypeChecksForNonCovariantArguments =>
-      !isClosure && enclosingMember.name.name != 'call';
+  // TODO(dartbug.com/40813): Remove the closure case when we move the
+  // type checks out of closure bodies.
+  bool get canSkipTypeChecksForNonCovariantArguments => !isClosure;
 
   bool get skipTypeChecksForGenericCovariantImplArguments =>
       procedureAttributesMetadata != null &&
diff --git a/pkg/vm/testcases/bytecode/async.dart.expect b/pkg/vm/testcases/bytecode/async.dart.expect
index 7c448ee..54765bc 100644
--- a/pkg/vm/testcases/bytecode/async.dart.expect
+++ b/pkg/vm/testcases/bytecode/async.dart.expect
@@ -69,11 +69,10 @@
 }
 Closure #lib::asyncInFieldInitializer (field)::'<anonymous closure>' async (dart:async::Future < dart:core::int* >* x) -> dart:async::Future < dart:core::Null? >*
 ClosureCode {
-  EntryFixed           2, 4
+  Entry                4
   Push                 FP[-6]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   AllocateContext      0, 9
   PopLocal             r0
@@ -1551,11 +1550,10 @@
 }
 Closure #lib::closure::'nested' async () -> dart:async::Future < dart:core::int* >*
 ClosureCode {
-  EntryFixed           1, 4
+  Entry                4
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   AllocateContext      1, 9
   StoreLocal           r1
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index 711bace..1582f95 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -65,11 +65,10 @@
 }
 Closure #lib::simpleClosure::'<anonymous closure>' (dart:core::int* y) -> dart:core::Null?
 ClosureCode {
-  EntryFixed           2, 3
+  Entry                3
   Push                 FP[-6]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   JumpIfUnchecked      L1
   Push                 FP[-5]
@@ -312,7 +311,7 @@
 }
 Closure #lib::testPartialInstantiation::'foo' <dart:core::Object* T> (#lib::testPartialInstantiation::Closure/0::TypeParam/0* t) -> void
 ClosureCode {
-  EntryFixed           2, 3
+  Entry                3
   Push                 FP[-6]
   LoadFieldTOS         CP#1
   PopLocal             r1
@@ -975,7 +974,7 @@
 }
 Closure #lib::A::foo::'nested1' <dart:core::Object* T5, dart:core::Object* T6> () -> void
 ClosureCode {
-  EntryFixed           1, 5
+  Entry                5
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r1
@@ -1035,7 +1034,7 @@
 
 Closure #lib::A::foo::Closure/0::'nested2' <dart:core::Object* T7, dart:core::Object* T8> () -> void
 ClosureCode {
-  EntryFixed           1, 5
+  Entry                5
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r1
@@ -1085,11 +1084,10 @@
 
 Closure #lib::A::foo::Closure/1::'<anonymous closure>' () -> dart:core::Null?
 ClosureCode {
-  EntryFixed           1, 4
+  Entry                4
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r1
-  CheckFunctionTypeArgs 0, r2
   CheckStack           0
   Push                 FP[-5]
   LoadFieldTOS         CP#6
@@ -1345,11 +1343,10 @@
 }
 Closure #lib::B::topLevel::'<anonymous closure>' (dart:core::int* y) -> dart:core::Null?
 ClosureCode {
-  EntryFixed           2, 4
+  Entry                4
   Push                 FP[-6]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   AllocateContext      1, 2
   StoreLocal           r1
@@ -1416,11 +1413,10 @@
 
 Closure #lib::B::topLevel::Closure/0::'closure2' () -> void
 ClosureCode {
-  EntryFixed           1, 3
+  Entry                3
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   Push                 r0
   LoadContextParent
@@ -1445,11 +1441,10 @@
 
 Closure #lib::B::topLevel::'<anonymous closure>' () -> dart:core::Null?
 ClosureCode {
-  EntryFixed           1, 3
+  Entry                3
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   Push                 r0
   LoadContextVar       0, 0
@@ -1643,11 +1638,10 @@
 }
 Closure #lib::C::testForLoop::'<anonymous closure>' () -> dart:core::int*
 ClosureCode {
-  EntryFixed           1, 2
+  Entry                2
   Push                 FP[-5]
   LoadFieldTOS         CP#5
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   Push                 r0
   LoadContextVar       1, 0
@@ -1660,11 +1654,10 @@
 
 Closure #lib::C::testForLoop::'<anonymous closure>' (dart:core::int* ii) -> dart:core::Null?
 ClosureCode {
-  EntryFixed           2, 3
+  Entry                3
   Push                 FP[-6]
   LoadFieldTOS         CP#5
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   JumpIfUnchecked      L1
   Push                 FP[-5]
@@ -1764,11 +1757,10 @@
 }
 Closure #lib::C::testForInLoop::'<anonymous closure>' () -> dart:core::Null?
 ClosureCode {
-  EntryFixed           1, 3
+  Entry                3
   Push                 FP[-5]
   LoadFieldTOS         CP#7
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   Push                 r0
   Push                 r0
@@ -1902,11 +1894,10 @@
 }
 Closure #lib::D::foo::'<anonymous closure>' () -> #lib::D::TypeParam/0*
 ClosureCode {
-  EntryFixed           1, 2
+  Entry                2
   Push                 FP[-5]
   LoadFieldTOS         CP#5
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   Push                 r0
   LoadContextVar       0, 0
@@ -1961,11 +1952,10 @@
 }
 Closure #lib::D::bar::'<anonymous closure>' () -> dart:core::Null?
 ClosureCode {
-  EntryFixed           1, 4
+  Entry                4
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   AllocateClosure      CP#3
   StoreLocal           r3
@@ -1995,11 +1985,10 @@
 
 Closure #lib::D::bar::Closure/0::'inner' () -> dart:core::Null?
 ClosureCode {
-  EntryFixed           1, 2
+  Entry                2
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   PushNull
   ReturnTOS
diff --git a/pkg/vm/testcases/bytecode/try_blocks.dart.expect b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
index ecb97c5..8ce1cbf 100644
--- a/pkg/vm/testcases/bytecode/try_blocks.dart.expect
+++ b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
@@ -337,11 +337,10 @@
 }
 Closure #lib::testTryCatch3::'foo' () -> void
 ClosureCode {
-  EntryFixed           1, 6
+  Entry                6
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   Push                 r0
   PopLocal             r2
@@ -374,11 +373,10 @@
 
 Closure #lib::testTryCatch3::'bar' () -> void
 ClosureCode {
-  EntryFixed           1, 6
+  Entry                6
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   Push                 r0
   PopLocal             r2
@@ -721,11 +719,10 @@
 }
 Closure #lib::testTryFinally2::'foo' () -> void
 ClosureCode {
-  EntryFixed           1, 2
+  Entry                2
   Push                 FP[-5]
   LoadFieldTOS         CP#7
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   Push                 r0
   LoadContextVar       0, 0
@@ -830,11 +827,10 @@
 }
 Closure #lib::testTryFinally3::'<anonymous closure>' () -> dart:core::int*
 ClosureCode {
-  EntryFixed           1, 6
+  Entry                6
   Push                 FP[-5]
   LoadFieldTOS         CP#1
   PopLocal             r0
-  CheckFunctionTypeArgs 0, r1
   CheckStack           0
   Push                 r0
   LoadContextVar       0, 0
diff --git a/runtime/tests/vm/dart/causal_stacks/utils.dart b/runtime/tests/vm/dart/causal_stacks/utils.dart
index 0ffe25e..4a56ae7 100644
--- a/runtime/tests/vm/dart/causal_stacks/utils.dart
+++ b/runtime/tests/vm/dart/causal_stacks/utils.dart
@@ -253,9 +253,10 @@
     [String? debugInfoFilename]) async {
   // Caller catches but a then is set.
   try {
-    await f().then((e) {
-      // Ignore.
-    });
+    // Passing (e) {} to then() can cause the closure instructions to be
+    // dedupped, changing the stack trace to the dedupped owner, so we
+    // duplicate the Expect.fail() call in the closure.
+    await f().then((e) => Expect.fail('No exception thrown!'));
     Expect.fail('No exception thrown!');
   } on String catch (e, s) {
     assertStack(expectedStack, s, debugInfoFilename);
diff --git a/runtime/tests/vm/dart_2/causal_stacks/utils.dart b/runtime/tests/vm/dart_2/causal_stacks/utils.dart
index 6354b59..94db964 100644
--- a/runtime/tests/vm/dart_2/causal_stacks/utils.dart
+++ b/runtime/tests/vm/dart_2/causal_stacks/utils.dart
@@ -253,9 +253,10 @@
     [String debugInfoFilename]) async {
   // Caller catches but a then is set.
   try {
-    await f().then((e) {
-      // Ignore.
-    });
+    // Passing (e) {} to then() can cause the closure instructions to be
+    // dedupped, changing the stack trace to the dedupped owner, so we
+    // duplicate the Expect.fail() call in the closure.
+    await f().then((e) => Expect.fail('No exception thrown!'));
     Expect.fail('No exception thrown!');
   } on String catch (e, s) {
     assertStack(expectedStack, s, debugInfoFilename);
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index f4bacaf..9bb5958 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -2470,16 +2470,24 @@
   Representation rep = defn->representation();
   if ((rep == kUnboxedDouble) || (rep == kUnboxedFloat64x2) ||
       (rep == kUnboxedFloat32x4)) {
-    // LoadField instruction lies about its representation in the unoptimized
-    // code because Definition::representation() can't depend on the type of
-    // compilation but MakeLocationSummary and EmitNativeCode can.
-    ASSERT(defn->IsLoadField() && defn->AsLoadField()->IsUnboxedLoad());
+    // The LoadField instruction may lie about its representation in unoptimized
+    // code for Dart fields because Definition::representation() can't depend on
+    // the type of compilation but MakeLocationSummary and EmitNativeCode can.
+    ASSERT(defn->IsLoadField() &&
+           defn->AsLoadField()->IsUnboxedDartFieldLoad());
     ASSERT(defn->locs()->out(0).IsRegister());
     rep = kTagged;
   }
   ASSERT(!is_optimizing());
-  ASSERT((rep == kTagged) || (rep == kUntagged));
+  ASSERT((rep == kTagged) || (rep == kUntagged) || (rep == kUnboxedUint32));
   ASSERT(rep != kUntagged || flow_graph_.IsIrregexpFunction());
+  const auto& function = flow_graph_.parsed_function().function();
+  // Currently, we only allow unboxed uint32 on the stack in unoptimized code
+  // when building a dynamic closure call dispatcher, where any unboxed values
+  // on the stack are consumed before possible FrameStateIsSafeToCall() checks.
+  // See FlowGraphBuilder::BuildDynamicCallVarsInit().
+  ASSERT(rep != kUnboxedUint32 ||
+         function.IsDynamicClosureCallDispatcher(thread()));
   frame_state_.Add(rep);
 }
 
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 6a7523f..d066f11 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -876,18 +876,20 @@
   return mask;
 }
 
-bool LoadFieldInstr::IsUnboxedLoad() const {
-  return slot().IsDartField() &&
+bool LoadFieldInstr::IsUnboxedDartFieldLoad() const {
+  return slot().representation() == kTagged && slot().IsDartField() &&
          FlowGraphCompiler::IsUnboxedField(slot().field());
 }
 
-bool LoadFieldInstr::IsPotentialUnboxedLoad() const {
-  return slot().IsDartField() &&
+bool LoadFieldInstr::IsPotentialUnboxedDartFieldLoad() const {
+  return slot().representation() == kTagged && slot().IsDartField() &&
          FlowGraphCompiler::IsPotentialUnboxedField(slot().field());
 }
 
 Representation LoadFieldInstr::representation() const {
-  if (IsUnboxedLoad()) {
+  if (slot().representation() != kTagged) {
+    return slot().representation();
+  } else if (IsUnboxedDartFieldLoad()) {
     const Field& field = slot().field();
     const intptr_t cid = field.UnboxedFieldCid();
     switch (cid) {
@@ -898,11 +900,8 @@
       case kFloat64x2Cid:
         return kUnboxedFloat64x2;
       default:
-        if (field.is_non_nullable_integer()) {
-          return kUnboxedInt64;
-        } else {
-          UNREACHABLE();
-        }
+        UNREACHABLE();
+        break;
     }
   }
   return kTagged;
@@ -2215,28 +2214,42 @@
     Value* left,
     Value* right,
     intptr_t deopt_id,
-    bool can_overflow,
-    bool is_truncating,
-    Range* range,
     SpeculativeMode speculative_mode) {
-  BinaryIntegerOpInstr* op = NULL;
+  BinaryIntegerOpInstr* op = nullptr;
+  Range* right_range = nullptr;
+  switch (op_kind) {
+    case Token::kMOD:
+    case Token::kTRUNCDIV:
+      if (representation != kTagged) break;
+      FALL_THROUGH;
+    case Token::kSHR:
+    case Token::kSHL:
+      if (auto const const_def = right->definition()->AsConstant()) {
+        right_range = new Range();
+        const_def->InferRange(nullptr, right_range);
+      }
+      break;
+    default:
+      break;
+  }
   switch (representation) {
     case kTagged:
-      op = new BinarySmiOpInstr(op_kind, left, right, deopt_id);
+      op = new BinarySmiOpInstr(op_kind, left, right, deopt_id, right_range);
       break;
     case kUnboxedInt32:
       if (!BinaryInt32OpInstr::IsSupported(op_kind, left, right)) {
-        return NULL;
+        return nullptr;
       }
       op = new BinaryInt32OpInstr(op_kind, left, right, deopt_id);
       break;
     case kUnboxedUint32:
       if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
         if (speculative_mode == kNotSpeculative) {
-          op = new ShiftUint32OpInstr(op_kind, left, right, deopt_id);
+          op = new ShiftUint32OpInstr(op_kind, left, right, deopt_id,
+                                      right_range);
         } else {
-          op =
-              new SpeculativeShiftUint32OpInstr(op_kind, left, right, deopt_id);
+          op = new SpeculativeShiftUint32OpInstr(op_kind, left, right, deopt_id,
+                                                 right_range);
         }
       } else {
         op = new BinaryUint32OpInstr(op_kind, left, right, deopt_id);
@@ -2245,9 +2258,11 @@
     case kUnboxedInt64:
       if ((op_kind == Token::kSHR) || (op_kind == Token::kSHL)) {
         if (speculative_mode == kNotSpeculative) {
-          op = new ShiftInt64OpInstr(op_kind, left, right, deopt_id);
+          op = new ShiftInt64OpInstr(op_kind, left, right, deopt_id,
+                                     right_range);
         } else {
-          op = new SpeculativeShiftInt64OpInstr(op_kind, left, right, deopt_id);
+          op = new SpeculativeShiftInt64OpInstr(op_kind, left, right, deopt_id,
+                                                right_range);
         }
       } else {
         op = new BinaryInt64OpInstr(op_kind, left, right, deopt_id);
@@ -2255,9 +2270,28 @@
       break;
     default:
       UNREACHABLE();
-      return NULL;
+      return nullptr;
   }
 
+  ASSERT(op->representation() == representation);
+  return op;
+}
+
+BinaryIntegerOpInstr* BinaryIntegerOpInstr::Make(
+    Representation representation,
+    Token::Kind op_kind,
+    Value* left,
+    Value* right,
+    intptr_t deopt_id,
+    bool can_overflow,
+    bool is_truncating,
+    Range* range,
+    SpeculativeMode speculative_mode) {
+  BinaryIntegerOpInstr* op = BinaryIntegerOpInstr::Make(
+      representation, op_kind, left, right, deopt_id, speculative_mode);
+  if (op == nullptr) {
+    return nullptr;
+  }
   if (!Range::IsUnknown(range)) {
     op->set_range(*range);
   }
@@ -2267,7 +2301,6 @@
     op->mark_truncating();
   }
 
-  ASSERT(op->representation() == representation);
   return op;
 }
 
@@ -2601,6 +2634,10 @@
     case Slot::Kind::kClosure_hash:
     case Slot::Kind::kCapturedVariable:
     case Slot::Kind::kDartField:
+    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::kPointerBase_data_field:
     case Slot::Kind::kType_arguments:
     case Slot::Kind::kTypeArgumentsIndex:
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 92bc408..b3c6d69 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -3492,8 +3492,10 @@
 
   virtual TokenPosition token_pos() const { return token_pos_; }
 
+  // Returns whether the constant fits in an unboxed 64-bit signed integer.
   bool IsUnboxedSignedIntegerConstant() const {
-    return representation() == kUnboxedInt32 ||
+    return representation() == kUnboxedUint32 ||
+           representation() == kUnboxedInt32 ||
            representation() == kUnboxedInt64;
   }
 
@@ -6401,8 +6403,14 @@
 
   virtual Representation representation() const;
 
-  bool IsUnboxedLoad() const;
-  bool IsPotentialUnboxedLoad() const;
+  // Returns whether this instruction is an unboxed load from a _boxed_ Dart
+  // field. Unboxed Dart fields are handled similar to unboxed native fields.
+  bool IsUnboxedDartFieldLoad() const;
+
+  // Returns whether this instruction is an potential unboxed load from a
+  // _boxed_ Dart field. Unboxed Dart fields are handled similar to unboxed
+  // native fields.
+  bool IsPotentialUnboxedDartFieldLoad() const;
 
   DECLARE_INSTRUCTION(LoadField)
   virtual CompileType ComputeType() const;
@@ -6673,6 +6681,23 @@
     }
   }
 
+  static bool RequiresAllocation(Representation rep) {
+    switch (rep) {
+      case kUnboxedDouble:
+      case kUnboxedFloat32x4:
+      case kUnboxedFloat64x2:
+      case kUnboxedInt32x4:
+      case kUnboxedInt64:
+        return true;
+      case kUnboxedInt32:
+      case kUnboxedUint32:
+        return kBitsPerInt32 > compiler::target::kSmiBits;
+      default:
+        UNREACHABLE();
+        return true;
+    }
+  }
+
   static intptr_t ValueOffset(Representation rep) {
     switch (rep) {
       case kUnboxedFloat:
@@ -6691,6 +6716,14 @@
       case kUnboxedInt64:
         return Mint::value_offset();
 
+      case kUnboxedInt32:
+      case kUnboxedUint32:
+        if (RequiresAllocation(rep)) {
+          return Mint::value_offset();
+        }
+        UNREACHABLE();
+        return 0;
+
       default:
         UNREACHABLE();
         return 0;
@@ -6699,6 +6732,13 @@
 
   static intptr_t BoxCid(Representation rep) {
     switch (rep) {
+      case kUnboxedInt32:
+      case kUnboxedUint32:
+        if (RequiresAllocation(rep)) {
+          return kMintCid;
+        }
+        UNREACHABLE();
+        return kIllegalCid;
       case kUnboxedInt64:
         return kMintCid;
       case kUnboxedDouble:
@@ -7538,6 +7578,14 @@
       Value* left,
       Value* right,
       intptr_t deopt_id,
+      SpeculativeMode speculative_mode = kGuardInputs);
+
+  static BinaryIntegerOpInstr* Make(
+      Representation representation,
+      Token::Kind op_kind,
+      Value* left,
+      Value* right,
+      intptr_t deopt_id,
       bool can_overflow,
       bool is_truncating,
       Range* range,
@@ -7597,9 +7645,11 @@
   BinarySmiOpInstr(Token::Kind op_kind,
                    Value* left,
                    Value* right,
-                   intptr_t deopt_id)
+                   intptr_t deopt_id,
+                   // Provided by BinaryIntegerOpInstr::Make for constant RHS.
+                   Range* right_range = nullptr)
       : BinaryIntegerOpInstr(op_kind, left, right, deopt_id),
-        right_range_(NULL) {}
+        right_range_(right_range) {}
 
   virtual bool ComputeCanDeoptimize() const;
 
@@ -7765,9 +7815,11 @@
   ShiftIntegerOpInstr(Token::Kind op_kind,
                       Value* left,
                       Value* right,
-                      intptr_t deopt_id)
+                      intptr_t deopt_id,
+                      // Provided by BinaryIntegerOpInstr::Make for constant RHS
+                      Range* right_range = nullptr)
       : BinaryIntegerOpInstr(op_kind, left, right, deopt_id),
-        shift_range_(NULL) {
+        shift_range_(right_range) {
     ASSERT((op_kind == Token::kSHR) || (op_kind == Token::kSHL));
     mark_truncating();
   }
@@ -7801,8 +7853,9 @@
   ShiftInt64OpInstr(Token::Kind op_kind,
                     Value* left,
                     Value* right,
-                    intptr_t deopt_id)
-      : ShiftIntegerOpInstr(op_kind, left, right, deopt_id) {}
+                    intptr_t deopt_id,
+                    Range* right_range = nullptr)
+      : ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
 
   virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
     return kNotSpeculative;
@@ -7832,8 +7885,9 @@
   SpeculativeShiftInt64OpInstr(Token::Kind op_kind,
                                Value* left,
                                Value* right,
-                               intptr_t deopt_id)
-      : ShiftIntegerOpInstr(op_kind, left, right, deopt_id) {}
+                               intptr_t deopt_id,
+                               Range* right_range = nullptr)
+      : ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
 
   virtual bool ComputeCanDeoptimize() const {
     ASSERT(!can_overflow());
@@ -7862,8 +7916,9 @@
   ShiftUint32OpInstr(Token::Kind op_kind,
                      Value* left,
                      Value* right,
-                     intptr_t deopt_id)
-      : ShiftIntegerOpInstr(op_kind, left, right, deopt_id) {}
+                     intptr_t deopt_id,
+                     Range* right_range = nullptr)
+      : ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
 
   virtual SpeculativeMode SpeculativeModeOfInput(intptr_t index) const {
     return kNotSpeculative;
@@ -7895,8 +7950,9 @@
   SpeculativeShiftUint32OpInstr(Token::Kind op_kind,
                                 Value* left,
                                 Value* right,
-                                intptr_t deopt_id)
-      : ShiftIntegerOpInstr(op_kind, left, right, deopt_id) {}
+                                intptr_t deopt_id,
+                                Range* right_range = nullptr)
+      : ShiftIntegerOpInstr(op_kind, left, right, deopt_id, right_range) {}
 
   virtual bool ComputeCanDeoptimize() const { return !IsShiftCountInRange(); }
 
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 9a09341..bedb2ec 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -672,11 +672,18 @@
 void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
                                        const Location& destination,
                                        Register tmp) {
+  const bool is_unboxed_int =
+      representation() == kUnboxedUint32 || representation() == kUnboxedInt32;
   if (destination.IsRegister()) {
-    if (representation() == kUnboxedInt32) {
+    if (is_unboxed_int) {
       int64_t v;
       const bool ok = compiler::HasIntegerValue(value_, &v);
       RELEASE_ASSERT(ok);
+      if (value_.IsSmi() && representation() == kUnboxedUint32) {
+        // If the value is negative, then the sign bit was preserved during
+        // Smi untagging, which means the resulting value may be unexpected.
+        ASSERT(v >= 0);
+      }
       __ LoadImmediate(destination.reg(), v);
     } else {
       ASSERT(representation() == kTagged);
@@ -706,7 +713,7 @@
     ASSERT(destination.IsStackSlot());
     ASSERT(tmp != kNoRegister);
     const intptr_t dest_offset = destination.ToStackSlotOffset();
-    if (representation() == kUnboxedInt32) {
+    if (is_unboxed_int) {
       int64_t v;
       const bool ok = compiler::HasIntegerValue(value_, &v);
       RELEASE_ASSERT(ok);
@@ -720,11 +727,13 @@
 
 LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone,
                                                            bool opt) const {
+  const bool is_unboxed_int =
+      representation() == kUnboxedUint32 || representation() == kUnboxedInt32;
   const intptr_t kNumInputs = 0;
-  const intptr_t kNumTemps = (representation_ == kUnboxedInt32) ? 0 : 1;
+  const intptr_t kNumTemps = is_unboxed_int ? 0 : 1;
   LocationSummary* locs = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
-  if (representation_ == kUnboxedInt32) {
+  if (is_unboxed_int) {
     locs->set_out(0, Location::RequiresRegister());
   } else {
     ASSERT(representation_ == kUnboxedDouble);
@@ -3222,17 +3231,23 @@
 LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
                                                      bool opt) const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = (IsUnboxedLoad() && opt)
-                                 ? (FLAG_precompiled_mode ? 0 : 1)
-                                 : (IsPotentialUnboxedLoad() ? 3 : 0);
+
+  const intptr_t kNumTemps =
+      (slot().representation() != kTagged)
+          ? 0
+          : ((IsUnboxedDartFieldLoad() && opt)
+                 ? (FLAG_precompiled_mode ? 0 : 1)
+                 : (IsPotentialUnboxedDartFieldLoad() ? 3 : 0));
 
   const auto contains_call =
-      (IsUnboxedLoad() && opt)
+      (slot().representation() != kTagged)
           ? LocationSummary::kNoCall
-          : (IsPotentialUnboxedLoad()
-                 ? LocationSummary::kCallOnSlowPath
-                 : (calls_initializer() ? LocationSummary::kCall
-                                        : LocationSummary::kNoCall));
+          : ((IsUnboxedDartFieldLoad() && opt)
+                 ? LocationSummary::kNoCall
+                 : (IsPotentialUnboxedDartFieldLoad()
+                        ? LocationSummary::kCallOnSlowPath
+                        : (calls_initializer() ? LocationSummary::kCall
+                                               : LocationSummary::kNoCall)));
 
   LocationSummary* locs =
       new (zone) LocationSummary(zone, kNumInputs, kNumTemps, contains_call);
@@ -3241,19 +3256,27 @@
                                             InitInstanceFieldABI::kInstanceReg)
                                       : Location::RequiresRegister());
 
-  if (IsUnboxedLoad() && opt) {
+  if (slot().representation() != kTagged) {
+    switch (slot().representation()) {
+      case kUnboxedInt64:
+        ASSERT(FLAG_precompiled_mode);
+        locs->set_out(0, Location::Pair(Location::RequiresRegister(),
+                                        Location::RequiresRegister()));
+        break;
+      case kUnboxedUint32:
+        locs->set_out(0, Location::RequiresRegister());
+        break;
+      default:
+        UNIMPLEMENTED();
+        break;
+    }
+  } else if (IsUnboxedDartFieldLoad() && opt) {
     ASSERT(!calls_initializer());
     if (!FLAG_precompiled_mode) {
       locs->set_temp(0, Location::RequiresRegister());
     }
-    if (slot().field().is_non_nullable_integer()) {
-      ASSERT(FLAG_precompiled_mode);
-      locs->set_out(0, Location::Pair(Location::RequiresRegister(),
-                                      Location::RequiresRegister()));
-    } else {
-      locs->set_out(0, Location::RequiresFpuRegister());
-    }
-  } else if (IsPotentialUnboxedLoad()) {
+    locs->set_out(0, Location::RequiresFpuRegister());
+  } else if (IsPotentialUnboxedDartFieldLoad()) {
     ASSERT(!calls_initializer());
     locs->set_temp(0, opt ? Location::RequiresFpuRegister()
                           : Location::FpuRegisterLocation(Q1));
@@ -3275,21 +3298,38 @@
   ASSERT(sizeof(FieldLayout::is_nullable_) == 2);
 
   const Register instance_reg = locs()->in(0).reg();
-  if (IsUnboxedLoad() && compiler->is_optimizing()) {
+  if (slot().representation() != kTagged) {
     ASSERT(!calls_initializer());
-    if (slot().field().is_non_nullable_integer()) {
-      const PairLocation* out_pair = locs()->out(0).AsPairLocation();
-      const Register out_lo = out_pair->At(0).reg();
-      const Register out_hi = out_pair->At(1).reg();
-      __ Comment("UnboxedIntegerLoadFieldInstr");
-      __ LoadFromOffset(kWord, out_lo, instance_reg,
-                        OffsetInBytes() - kHeapObjectTag);
-      __ LoadFromOffset(
-          kWord, out_hi, instance_reg,
-          OffsetInBytes() - kHeapObjectTag + compiler::target::kWordSize);
-      return;
+    switch (slot().representation()) {
+      case kUnboxedInt64: {
+        const PairLocation* out_pair = locs()->out(0).AsPairLocation();
+        const Register out_lo = out_pair->At(0).reg();
+        const Register out_hi = out_pair->At(1).reg();
+        __ Comment("UnboxedInt64LoadFieldInstr");
+        __ LoadFromOffset(kWord, out_lo, instance_reg,
+                          OffsetInBytes() - kHeapObjectTag);
+        __ LoadFromOffset(
+            kWord, out_hi, instance_reg,
+            OffsetInBytes() - kHeapObjectTag + compiler::target::kWordSize);
+        break;
+      }
+      case kUnboxedUint32: {
+        Register result = locs()->out(0).reg();
+        __ Comment("UnboxedUint32LoadFieldInstr");
+        __ LoadFieldFromOffset(kWord, result, instance_reg, OffsetInBytes());
+        break;
+      }
+      default:
+        UNIMPLEMENTED();
+        break;
     }
+    return;
+  }
 
+  if (IsUnboxedDartFieldLoad() && compiler->is_optimizing()) {
+    ASSERT_EQUAL(slot().representation(), kTagged);
+    ASSERT(!calls_initializer());
+    ASSERT(!slot().field().is_non_nullable_integer());
     const intptr_t cid = slot().field().UnboxedFieldCid();
     const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
 
@@ -3344,7 +3384,8 @@
 
   compiler::Label done;
   const Register result_reg = locs()->out(0).reg();
-  if (IsPotentialUnboxedLoad()) {
+  if (IsPotentialUnboxedDartFieldLoad()) {
+    ASSERT_EQUAL(slot().representation(), kTagged);
     ASSERT(!calls_initializer());
     const DRegister value = EvenDRegisterOf(locs()->temp(0).fpu_reg());
     const Register temp = locs()->temp(1).reg();
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 2a9d946..51f6330 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -577,6 +577,7 @@
                                        Register tmp) {
   if (destination.IsRegister()) {
     if (representation() == kUnboxedInt32 ||
+        representation() == kUnboxedUint32 ||
         representation() == kUnboxedInt64) {
       const int64_t value = Integer::Cast(value_).AsInt64Value();
       __ LoadImmediate(destination.reg(), value);
@@ -604,6 +605,7 @@
     ASSERT(tmp != kNoRegister);
     const intptr_t dest_offset = destination.ToStackSlotOffset();
     if (representation() == kUnboxedInt32 ||
+        representation() == kUnboxedUint32 ||
         representation() == kUnboxedInt64) {
       const int64_t value = Integer::Cast(value_).AsInt64Value();
       __ LoadImmediate(tmp, value);
@@ -627,6 +629,7 @@
       locs->set_temp(0, Location::RequiresRegister());
       break;
     case kUnboxedInt32:
+    case kUnboxedUint32:
     case kUnboxedInt64:
       locs->set_out(0, Location::RequiresRegister());
       break;
@@ -2748,13 +2751,13 @@
 LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
                                                      bool opt) const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = (IsUnboxedLoad() && opt)
+  const intptr_t kNumTemps = (IsUnboxedDartFieldLoad() && opt)
                                  ? (FLAG_precompiled_mode ? 0 : 1)
-                                 : (IsPotentialUnboxedLoad() ? 1 : 0);
+                                 : (IsPotentialUnboxedDartFieldLoad() ? 1 : 0);
   const auto contains_call =
-      (IsUnboxedLoad() && opt)
+      (IsUnboxedDartFieldLoad() && opt)
           ? LocationSummary::kNoCall
-          : (IsPotentialUnboxedLoad()
+          : (IsPotentialUnboxedDartFieldLoad()
                  ? LocationSummary::kCallOnSlowPath
                  : (calls_initializer() ? LocationSummary::kCall
                                         : LocationSummary::kNoCall));
@@ -2766,18 +2769,13 @@
                                             InitInstanceFieldABI::kInstanceReg)
                                       : Location::RequiresRegister());
 
-  if (IsUnboxedLoad() && opt) {
+  if (IsUnboxedDartFieldLoad() && opt) {
     ASSERT(!calls_initializer());
     if (!FLAG_precompiled_mode) {
       locs->set_temp(0, Location::RequiresRegister());
     }
-    if (slot().field().is_non_nullable_integer()) {
-      ASSERT(FLAG_precompiled_mode);
-      locs->set_out(0, Location::RequiresRegister());
-    } else {
-      locs->set_out(0, Location::RequiresFpuRegister());
-    }
-  } else if (IsPotentialUnboxedLoad()) {
+    locs->set_out(0, Location::RequiresFpuRegister());
+  } else if (IsPotentialUnboxedDartFieldLoad()) {
     ASSERT(!calls_initializer());
     locs->set_temp(0, Location::RequiresRegister());
     locs->set_out(0, Location::RequiresRegister());
@@ -2796,15 +2794,10 @@
   ASSERT(sizeof(FieldLayout::is_nullable_) == 2);
 
   const Register instance_reg = locs()->in(0).reg();
-  if (IsUnboxedLoad() && compiler->is_optimizing()) {
+  if (IsUnboxedDartFieldLoad() && compiler->is_optimizing()) {
+    ASSERT_EQUAL(slot().representation(), kTagged);
     ASSERT(!calls_initializer());
-    if (slot().field().is_non_nullable_integer()) {
-      const Register result = locs()->out(0).reg();
-      __ Comment("UnboxedIntegerLoadFieldInstr");
-      __ LoadFieldFromOffset(result, instance_reg, OffsetInBytes());
-      return;
-    }
-
+    ASSERT(!slot().field().is_non_nullable_integer());
     const VRegister result = locs()->out(0).fpu_reg();
     const intptr_t cid = slot().field().UnboxedFieldCid();
 
@@ -2849,7 +2842,8 @@
 
   compiler::Label done;
   const Register result_reg = locs()->out(0).reg();
-  if (IsPotentialUnboxedLoad()) {
+  if (IsPotentialUnboxedDartFieldLoad()) {
+    ASSERT_EQUAL(slot().representation(), kTagged);
     ASSERT(!calls_initializer());
     const Register temp = locs()->temp(0).reg();
 
@@ -2921,6 +2915,26 @@
     __ Bind(&load_pointer);
   }
 
+  if (slot().representation() != kTagged) {
+    ASSERT(!calls_initializer());
+    const Register result = locs()->out(0).reg();
+    switch (slot().representation()) {
+      case kUnboxedInt64:
+        __ Comment("UnboxedInt64LoadFieldInstr");
+        __ LoadFieldFromOffset(result, instance_reg, OffsetInBytes());
+        break;
+      case kUnboxedUint32:
+        __ Comment("UnboxedUint32LoadFieldInstr");
+        __ LoadFieldFromOffset(result, instance_reg, OffsetInBytes(),
+                               kUnsignedWord);
+        break;
+      default:
+        UNIMPLEMENTED();
+        break;
+    }
+    return;
+  }
+
   __ LoadFieldFromOffset(result_reg, instance_reg, OffsetInBytes());
 
   if (calls_initializer()) {
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 5eb8db8..4a2ad85 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -397,12 +397,19 @@
 void ConstantInstr::EmitMoveToLocation(FlowGraphCompiler* compiler,
                                        const Location& destination,
                                        Register tmp) {
+  const bool is_unboxed_int =
+      representation() == kUnboxedUint32 || representation() == kUnboxedInt32;
   if (destination.IsRegister()) {
-    if (value_.IsSmi() && Smi::Cast(value_).Value() == 0) {
-      __ xorl(destination.reg(), destination.reg());
-    } else if (value_.IsSmi() && (representation() == kUnboxedInt32)) {
-      __ movl(destination.reg(),
-              compiler::Immediate(Smi::Cast(value_).Value()));
+    if (is_unboxed_int) {
+      int64_t v;
+      const bool ok = compiler::HasIntegerValue(value_, &v);
+      RELEASE_ASSERT(ok);
+      if (value_.IsSmi() && representation() == kUnboxedUint32) {
+        // If the value is negative, then the sign bit was preserved during
+        // Smi untagging, which means the resulting value may be unexpected.
+        ASSERT(v >= 0);
+      }
+      __ movl(destination.reg(), compiler::Immediate(v));
     } else {
       ASSERT(representation() == kTagged);
       __ LoadObjectSafely(destination.reg(), value_);
@@ -437,7 +444,7 @@
     __ movsd(LocationToStackSlotAddress(destination), FpuTMP);
   } else {
     ASSERT(destination.IsStackSlot());
-    if (value_.IsSmi() && representation() == kUnboxedInt32) {
+    if (value_.IsSmi() && is_unboxed_int) {
       __ movl(LocationToStackSlotAddress(destination),
               compiler::Immediate(Smi::Cast(value_).Value()));
     } else {
@@ -456,15 +463,17 @@
 
 LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Zone* zone,
                                                            bool opt) const {
+  const bool is_unboxed_int =
+      representation() == kUnboxedUint32 || representation() == kUnboxedInt32;
   const intptr_t kNumInputs = 0;
   const intptr_t kNumTemps =
-      (constant_address() == 0) && (representation() != kUnboxedInt32) ? 1 : 0;
+      (constant_address() == 0) && !is_unboxed_int ? 1 : 0;
   LocationSummary* locs = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   if (representation() == kUnboxedDouble) {
     locs->set_out(0, Location::RequiresFpuRegister());
   } else {
-    ASSERT(representation() == kUnboxedInt32);
+    ASSERT(is_unboxed_int);
     locs->set_out(0, Location::RequiresRegister());
   }
   if (kNumTemps == 1) {
@@ -2526,11 +2535,14 @@
                                                      bool opt) const {
   const intptr_t kNumInputs = 1;
   const intptr_t kNumTemps =
-      (IsUnboxedLoad() && opt) ? 1 : ((IsPotentialUnboxedLoad()) ? 2 : 0);
+      (IsUnboxedDartFieldLoad() && opt)
+          ? 1
+          : ((IsPotentialUnboxedDartFieldLoad()) ? 2 : 0);
+
   const auto contains_call =
-      (IsUnboxedLoad() && opt)
+      (IsUnboxedDartFieldLoad() && opt)
           ? LocationSummary::kNoCall
-          : (IsPotentialUnboxedLoad()
+          : (IsPotentialUnboxedDartFieldLoad()
                  ? LocationSummary::kCallOnSlowPath
                  : (calls_initializer() ? LocationSummary::kCall
                                         : LocationSummary::kNoCall));
@@ -2542,10 +2554,10 @@
                                             InitInstanceFieldABI::kInstanceReg)
                                       : Location::RequiresRegister());
 
-  if (IsUnboxedLoad() && opt) {
+  if (IsUnboxedDartFieldLoad() && opt) {
     ASSERT(!calls_initializer());
     locs->set_temp(0, Location::RequiresRegister());
-  } else if (IsPotentialUnboxedLoad()) {
+  } else if (IsPotentialUnboxedDartFieldLoad()) {
     ASSERT(!calls_initializer());
     locs->set_temp(0, opt ? Location::RequiresFpuRegister()
                           : Location::FpuRegisterLocation(XMM1));
@@ -2562,8 +2574,9 @@
   ASSERT(sizeof(FieldLayout::guarded_cid_) == 2);
   ASSERT(sizeof(FieldLayout::is_nullable_) == 2);
 
-  Register instance_reg = locs()->in(0).reg();
-  if (IsUnboxedLoad() && compiler->is_optimizing()) {
+  const Register instance_reg = locs()->in(0).reg();
+  if (IsUnboxedDartFieldLoad() && compiler->is_optimizing()) {
+    ASSERT_EQUAL(slot().representation(), kTagged);
     ASSERT(!calls_initializer());
     XmmRegister result = locs()->out(0).fpu_reg();
     Register temp = locs()->temp(0).reg();
@@ -2592,7 +2605,8 @@
 
   compiler::Label done;
   Register result = locs()->out(0).reg();
-  if (IsPotentialUnboxedLoad()) {
+  if (IsPotentialUnboxedDartFieldLoad()) {
+    ASSERT_EQUAL(slot().representation(), kTagged);
     ASSERT(!calls_initializer());
     Register temp = locs()->temp(1).reg();
     XmmRegister value = locs()->temp(0).fpu_reg();
@@ -2663,6 +2677,22 @@
     __ Bind(&load_pointer);
   }
 
+  if (slot().representation() != kTagged) {
+    ASSERT(!calls_initializer());
+    Register result = locs()->out(0).reg();
+    compiler::FieldAddress address(instance_reg, OffsetInBytes());
+    switch (slot().representation()) {
+      case kUnboxedUint32:
+        __ Comment("UnboxedUint32LoadFieldInstr");
+        __ movl(result, address);
+        break;
+      default:
+        UNIMPLEMENTED();
+        break;
+    }
+    return;
+  }
+
   __ movl(result, compiler::FieldAddress(instance_reg, OffsetInBytes()));
 
   if (calls_initializer()) {
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 128012a..a803165 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -511,6 +511,7 @@
                                        Register tmp) {
   if (destination.IsRegister()) {
     if (representation() == kUnboxedInt32 ||
+        representation() == kUnboxedUint32 ||
         representation() == kUnboxedInt64) {
       const int64_t value = Integer::Cast(value_).AsInt64Value();
       if (value == 0) {
@@ -543,6 +544,7 @@
   } else {
     ASSERT(destination.IsStackSlot());
     if (representation() == kUnboxedInt32 ||
+        representation() == kUnboxedUint32 ||
         representation() == kUnboxedInt64) {
       const int64_t value = Integer::Cast(value_).AsInt64Value();
       __ movq(LocationToStackSlotAddress(destination),
@@ -566,6 +568,7 @@
       locs->set_temp(0, Location::RequiresRegister());
       break;
     case kUnboxedInt32:
+    case kUnboxedUint32:
     case kUnboxedInt64:
       locs->set_out(0, Location::RequiresRegister());
       break;
@@ -2775,13 +2778,14 @@
 LocationSummary* LoadFieldInstr::MakeLocationSummary(Zone* zone,
                                                      bool opt) const {
   const intptr_t kNumInputs = 1;
-  const intptr_t kNumTemps = (IsUnboxedLoad() && opt)
+  const intptr_t kNumTemps = (IsUnboxedDartFieldLoad() && opt)
                                  ? (FLAG_precompiled_mode ? 0 : 1)
-                                 : (IsPotentialUnboxedLoad() ? 2 : 0);
+                                 : (IsPotentialUnboxedDartFieldLoad() ? 2 : 0);
+
   const auto contains_call =
-      (IsUnboxedLoad() && opt)
+      (IsUnboxedDartFieldLoad() && opt)
           ? LocationSummary::kNoCall
-          : (IsPotentialUnboxedLoad()
+          : (IsPotentialUnboxedDartFieldLoad()
                  ? LocationSummary::kCallOnSlowPath
                  : (calls_initializer() ? LocationSummary::kCall
                                         : LocationSummary::kNoCall));
@@ -2793,18 +2797,13 @@
                                             InitInstanceFieldABI::kInstanceReg)
                                       : Location::RequiresRegister());
 
-  if (IsUnboxedLoad() && opt) {
+  if (IsUnboxedDartFieldLoad() && opt) {
     ASSERT(!calls_initializer());
     if (!FLAG_precompiled_mode) {
       locs->set_temp(0, Location::RequiresRegister());
     }
-    if (slot().field().is_non_nullable_integer()) {
-      ASSERT(FLAG_precompiled_mode);
-      locs->set_out(0, Location::RequiresRegister());
-    } else {
-      locs->set_out(0, Location::RequiresFpuRegister());
-    }
-  } else if (IsPotentialUnboxedLoad()) {
+    locs->set_out(0, Location::RequiresFpuRegister());
+  } else if (IsPotentialUnboxedDartFieldLoad()) {
     ASSERT(!calls_initializer());
     locs->set_temp(0, opt ? Location::RequiresFpuRegister()
                           : Location::FpuRegisterLocation(XMM1));
@@ -2824,16 +2823,11 @@
   ASSERT(sizeof(FieldLayout::guarded_cid_) == 2);
   ASSERT(sizeof(FieldLayout::is_nullable_) == 2);
 
-  Register instance_reg = locs()->in(0).reg();
-  if (IsUnboxedLoad() && compiler->is_optimizing()) {
+  const Register instance_reg = locs()->in(0).reg();
+  if (IsUnboxedDartFieldLoad() && compiler->is_optimizing()) {
+    ASSERT_EQUAL(slot().representation(), kTagged);
     ASSERT(!calls_initializer());
-    if (slot().field().is_non_nullable_integer()) {
-      const Register result = locs()->out(0).reg();
-      __ Comment("UnboxedIntegerLoadFieldInstr");
-      __ movq(result, compiler::FieldAddress(instance_reg, OffsetInBytes()));
-      return;
-    }
-
+    ASSERT(!slot().field().is_non_nullable_integer());
     XmmRegister result = locs()->out(0).fpu_reg();
     const intptr_t cid = slot().field().UnboxedFieldCid();
 
@@ -2886,7 +2880,8 @@
 
   compiler::Label done;
   Register result = locs()->out(0).reg();
-  if (IsPotentialUnboxedLoad()) {
+  if (IsPotentialUnboxedDartFieldLoad()) {
+    ASSERT_EQUAL(slot().representation(), kTagged);
     ASSERT(!calls_initializer());
     Register temp = locs()->temp(1).reg();
     XmmRegister value = locs()->temp(0).fpu_reg();
@@ -2957,6 +2952,26 @@
     __ Bind(&load_pointer);
   }
 
+  if (slot().representation() != kTagged) {
+    ASSERT(!calls_initializer());
+    const Register result = locs()->out(0).reg();
+    const compiler::FieldAddress address(instance_reg, OffsetInBytes());
+    switch (slot().representation()) {
+      case kUnboxedInt64:
+        __ Comment("UnboxedInt64LoadFieldInstr");
+        __ movq(result, address);
+        break;
+      case kUnboxedUint32:
+        __ Comment("UnboxedUint32LoadFieldInstr");
+        __ movl(result, address);
+        break;
+      default:
+        UNIMPLEMENTED();
+        break;
+    }
+    return;
+  }
+
   __ movq(result, compiler::FieldAddress(instance_reg, OffsetInBytes()));
 
   if (calls_initializer()) {
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 281e3c9..65d99f1 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -2665,6 +2665,21 @@
   *range = result;
 }
 
+static RangeBoundary::RangeSize RepresentationToRangeSize(Representation r) {
+  switch (r) {
+    case kTagged:
+      return RangeBoundary::kRangeBoundarySmi;
+    case kUnboxedInt32:
+      return RangeBoundary::kRangeBoundaryInt32;
+    case kUnboxedInt64:
+    case kUnboxedUint32:  // Overapproximate Uint32 as Int64.
+      return RangeBoundary::kRangeBoundaryInt64;
+    default:
+      UNREACHABLE();
+      return RangeBoundary::kRangeBoundarySmi;
+  }
+}
+
 void LoadFieldInstr::InferRange(RangeAnalysis* analysis, Range* range) {
   switch (slot().kind()) {
     case Slot::Kind::kArray_length:
@@ -2701,6 +2716,9 @@
     case Slot::Kind::kClosure_function:
     case Slot::Kind::kClosure_function_type_arguments:
     case Slot::Kind::kClosure_instantiator_type_arguments:
+    case Slot::Kind::kFunction_parameter_names:
+    case Slot::Kind::kFunction_parameter_types:
+    case Slot::Kind::kFunction_type_parameters:
     case Slot::Kind::kPointerBase_data_field:
     case Slot::Kind::kTypedDataView_data:
     case Slot::Kind::kType_arguments:
@@ -2711,6 +2729,10 @@
       UNREACHABLE();
       break;
 
+    case Slot::Kind::kFunction_packed_fields:
+      *range = Range::Full(RepresentationToRangeSize(slot().representation()));
+      break;
+
     case Slot::Kind::kClosure_hash:
     case Slot::Kind::kLinkedHashMap_hash_mask:
     case Slot::Kind::kLinkedHashMap_used_data:
@@ -2802,21 +2824,6 @@
       Range(RangeBoundary::FromConstant(min), RangeBoundary::FromConstant(max));
 }
 
-static RangeBoundary::RangeSize RepresentationToRangeSize(Representation r) {
-  switch (r) {
-    case kTagged:
-      return RangeBoundary::kRangeBoundarySmi;
-    case kUnboxedInt32:
-      return RangeBoundary::kRangeBoundaryInt32;
-    case kUnboxedInt64:
-    case kUnboxedUint32:  // Overapproximate Uint32 as Int64.
-      return RangeBoundary::kRangeBoundaryInt64;
-    default:
-      UNREACHABLE();
-      return RangeBoundary::kRangeBoundarySmi;
-  }
-}
-
 void BinaryIntegerOpInstr::InferRangeHelper(const Range* left_range,
                                             const Range* right_range,
                                             Range* range) {
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index b54bc57..a8a9ec0 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -4,6 +4,8 @@
 
 #include "vm/compiler/backend/slot.h"
 
+#include "vm/compiler/backend/flow_graph_compiler.h"
+#include "vm/compiler/backend/il.h"
 #include "vm/compiler/compiler_state.h"
 #include "vm/hash_map.h"
 #include "vm/parser.h"
@@ -52,7 +54,8 @@
 #define NATIVE_CASE(C, U, F, id, M)                                            \
   case NATIVE_SLOT_NAME(C, F, id, M):                                          \
     return NATIVE_TO_STR(C, F, id, M);
-    NATIVE_SLOTS_LIST(NATIVE_CASE)
+    BOXED_NATIVE_SLOTS_LIST(NATIVE_CASE)
+    UNBOXED_NATIVE_SLOTS_LIST(NATIVE_CASE)
 #undef NATIVE_CASE
     case Kind::kTypeArguments:
       return "TypeArguments";
@@ -73,7 +76,8 @@
     *out = NATIVE_SLOT_NAME(C, F, id, M);                                      \
     return true;                                                               \
   }
-  NATIVE_SLOTS_LIST(NATIVE_CASE)
+  BOXED_NATIVE_SLOTS_LIST(NATIVE_CASE)
+  UNBOXED_NATIVE_SLOTS_LIST(NATIVE_CASE)
 #undef NATIVE_CASE
   if (strcmp(str, "TypeArguments") == 0) {
     *out = Kind::kTypeArguments;
@@ -93,21 +97,61 @@
 #undef NATIVE_TO_STR
 #undef NATIVE_SLOT_NAME
 
+static Representation CheckFit(Representation rep) {
+  ASSERT(Boxing::Supports(rep));
+  switch (rep) {
+    case kUnboxedInt64:
+    case kUnboxedInt32:
+    case kUnboxedUint32:
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+  return rep;
+}
+
+static classid_t GetUnboxedNativeSlotCid(Representation rep) {
+  ASSERT(Boxing::Supports(rep));
+  if (Boxing::RequiresAllocation(rep)) {
+    return Boxing::BoxCid(rep);
+  }
+#if defined(TARGET_ARCH_IS_64_BIT)
+  // On 64-bit platforms, these always fit in Smis.
+  if (rep == kUnboxedInt32 || rep == kUnboxedUint32) {
+    return kSmiCid;
+  }
+#endif
+  UNREACHABLE();
+  return kIllegalCid;
+}
+
 const Slot& Slot::GetNativeSlot(Kind kind) {
   // There is a fixed statically known number of native slots so we cache
   // them statically.
   static const Slot fields[] = {
 #define FIELD_FINAL (IsImmutableBit::encode(true))
 #define FIELD_VAR (0)
-#define DEFINE_NATIVE_FIELD(ClassName, UnderlyingType, FieldName, cid,         \
-                            mutability)                                        \
+#define DEFINE_BOXED_NATIVE_FIELD(ClassName, UnderlyingType, FieldName, cid,   \
+                                  mutability)                                  \
   Slot(Kind::k##ClassName##_##FieldName, FIELD_##mutability, k##cid##Cid,      \
        compiler::target::ClassName::FieldName##_offset(),                      \
-       #ClassName "." #FieldName, nullptr),
+       #ClassName "." #FieldName, nullptr, kTagged),
 
-      NATIVE_SLOTS_LIST(DEFINE_NATIVE_FIELD)
+      BOXED_NATIVE_SLOTS_LIST(DEFINE_BOXED_NATIVE_FIELD)
 
-#undef DEFINE_FIELD
+#undef DEFINE_BOXED_NATIVE_FIELD
+#define DEFINE_UNBOXED_NATIVE_FIELD(ClassName, UnderlyingType, FieldName,      \
+                                    representation, mutability)                \
+  Slot(Kind::k##ClassName##_##FieldName, FIELD_##mutability,                   \
+       GetUnboxedNativeSlotCid(kUnboxed##representation),                      \
+       compiler::target::ClassName::FieldName##_offset(),                      \
+       #ClassName "." #FieldName, nullptr,                                     \
+       CheckFit(kUnboxed##representation)),
+
+          UNBOXED_NATIVE_SLOTS_LIST(DEFINE_UNBOXED_NATIVE_FIELD)
+
+#undef DEFINE_UNBOXED_NATIVE_FIELD
 #undef FIELD_VAR
 #undef FIELD_FINAL
   };
@@ -146,7 +190,7 @@
   ASSERT(offset != Class::kNoTypeArguments);
   return SlotCache::Instance(thread).Canonicalize(Slot(
       Kind::kTypeArguments, IsImmutableBit::encode(true), kTypeArgumentsCid,
-      offset, ":type_arguments", /*static_type=*/nullptr));
+      offset, ":type_arguments", /*static_type=*/nullptr, kTagged));
 }
 
 const Slot& Slot::GetTypeArgumentsSlotFor(Thread* thread, const Class& cls) {
@@ -163,7 +207,7 @@
                IsNullableBit::encode(true),
            kDynamicCid,
            compiler::target::Context::variable_offset(variable.index().value()),
-           &variable.name(), &variable.type()));
+           &variable.name(), &variable.type(), kTagged));
 }
 
 const Slot& Slot::GetTypeArgumentsIndexSlot(Thread* thread, intptr_t index) {
@@ -171,7 +215,7 @@
       compiler::target::TypeArguments::type_at_offset(index);
   const Slot& slot =
       Slot(Kind::kTypeArgumentsIndex, IsImmutableBit::encode(true), kDynamicCid,
-           offset, ":argument", /*static_type=*/nullptr);
+           offset, ":argument", /*static_type=*/nullptr, kTagged);
   return SlotCache::Instance(thread).Canonicalize(slot);
 }
 
@@ -179,6 +223,7 @@
                       const ParsedFunction* parsed_function) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
+  Representation rep = kTagged;
   intptr_t nullable_cid = kDynamicCid;
   bool is_nullable = true;
 
@@ -221,16 +266,21 @@
   }
 
   if (field.is_non_nullable_integer()) {
+    ASSERT(FLAG_precompiled_mode);
     is_nullable = false;
+    if (FlowGraphCompiler::IsUnboxedField(field)) {
+      rep = kUnboxedInt64;
+    }
   }
 
-  const Slot& slot = SlotCache::Instance(thread).Canonicalize(Slot(
-      Kind::kDartField,
-      IsImmutableBit::encode((field.is_final() && !field.is_late()) ||
-                             field.is_const()) |
-          IsNullableBit::encode(is_nullable) |
-          IsGuardedBit::encode(used_guarded_state),
-      nullable_cid, compiler::target::Field::OffsetOf(field), &field, &type));
+  const Slot& slot = SlotCache::Instance(thread).Canonicalize(
+      Slot(Kind::kDartField,
+           IsImmutableBit::encode((field.is_final() && !field.is_late()) ||
+                                  field.is_const()) |
+               IsNullableBit::encode(is_nullable) |
+               IsGuardedBit::encode(used_guarded_state),
+           nullable_cid, compiler::target::Field::OffsetOf(field), &field,
+           &type, rep));
 
   // If properties of this slot were based on the guarded state make sure
   // to add the field to the list of guarded fields. Note that during background
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index f59bc7c..6b2bd68 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -29,6 +29,7 @@
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 
 #include "vm/compiler/backend/compile_type.h"
+#include "vm/compiler/backend/locations.h"
 #include "vm/thread.h"
 
 namespace dart {
@@ -52,7 +53,7 @@
 //   that) or like a non-final field.
 //
 // Note: native slots are expected to be non-nullable.
-#define NATIVE_SLOTS_LIST(V)                                                   \
+#define BOXED_NATIVE_SLOTS_LIST(V)                                             \
   V(Array, ArrayLayout, length, Smi, FINAL)                                    \
   V(Context, ContextLayout, parent, Context, FINAL)                            \
   V(Closure, ClosureLayout, instantiator_type_arguments, TypeArguments, FINAL) \
@@ -61,6 +62,9 @@
   V(Closure, ClosureLayout, function, Function, FINAL)                         \
   V(Closure, ClosureLayout, context, Context, FINAL)                           \
   V(Closure, ClosureLayout, hash, Context, VAR)                                \
+  V(Function, FunctionLayout, parameter_names, Array, FINAL)                   \
+  V(Function, FunctionLayout, parameter_types, Array, FINAL)                   \
+  V(Function, FunctionLayout, type_parameters, Array, FINAL)                   \
   V(GrowableObjectArray, GrowableObjectArrayLayout, length, Smi, VAR)          \
   V(GrowableObjectArray, GrowableObjectArrayLayout, data, Array, VAR)          \
   V(TypedDataBase, TypedDataBaseLayout, length, Smi, FINAL)                    \
@@ -81,6 +85,24 @@
   V(UnhandledException, UnhandledExceptionLayout, exception, Dynamic, FINAL)   \
   V(UnhandledException, UnhandledExceptionLayout, stacktrace, Dynamic, FINAL)
 
+// List of slots that correspond to unboxed fields of native objects in the
+// following format:
+//
+//     V(class_name, underlying_type, field_name, representation, FINAL|VAR)
+//
+// - class_name and field_name specify the name of the host class and the name
+//   of the field respectively;
+// - underlying_type: the Raw class which holds the field;
+// - representation specifies the representation of the bits stored within
+//   the unboxed field (minus the kUnboxed prefix);
+// - the last component specifies whether field behaves like a final field
+//   (i.e. initialized once at construction time and does not change after
+//   that) or like a non-final field.
+//
+// Note: As the underlying field is not boxed, these slots cannot be nullable.
+#define UNBOXED_NATIVE_SLOTS_LIST(V)                                           \
+  V(Function, FunctionLayout, packed_fields, Uint32, FINAL)
+
 // Slot is an abstraction that describes an readable (and possibly writeable)
 // location within an object.
 //
@@ -95,7 +117,8 @@
     // Native slots are identified by their kind - each native slot has its own.
 #define DECLARE_KIND(ClassName, UnderlyingType, FieldName, cid, mutability)    \
   k##ClassName##_##FieldName,
-    NATIVE_SLOTS_LIST(DECLARE_KIND)
+    BOXED_NATIVE_SLOTS_LIST(DECLARE_KIND)
+    UNBOXED_NATIVE_SLOTS_LIST(DECLARE_KIND)
 #undef DECLARE_KIND
 
     // A slot used to store type arguments.
@@ -146,7 +169,8 @@
     return GetNativeSlot(Kind::k##ClassName##_##FieldName);                    \
   }
 
-  NATIVE_SLOTS_LIST(DEFINE_GETTER)
+  BOXED_NATIVE_SLOTS_LIST(DEFINE_GETTER)
+  UNBOXED_NATIVE_SLOTS_LIST(DEFINE_GETTER)
 #undef DEFINE_GETTER
 
   Kind kind() const { return kind_; }
@@ -159,6 +183,12 @@
 
   intptr_t offset_in_bytes() const { return offset_in_bytes_; }
 
+  // Currently returns the representation of unboxed native fields and kTagged
+  // for most other types of fields. One special case: fields marked as
+  // containing non-nullable ints in AOT kernel, which have the kUnboxedInt64
+  // representation.
+  Representation representation() const { return representation_; }
+
   bool is_immutable() const { return IsImmutableBit::decode(flags_); }
 
   intptr_t nullable_cid() const { return cid_; }
@@ -200,11 +230,13 @@
        ClassIdTagType cid,
        intptr_t offset_in_bytes,
        const void* data,
-       const AbstractType* static_type)
+       const AbstractType* static_type,
+       Representation representation)
       : kind_(kind),
         flags_(bits),
         cid_(cid),
         offset_in_bytes_(offset_in_bytes),
+        representation_(representation),
         data_(data),
         static_type_(static_type) {}
 
@@ -214,7 +246,8 @@
              other.cid_,
              other.offset_in_bytes_,
              other.data_,
-             other.static_type_) {}
+             other.static_type_,
+             other.representation_) {}
 
   using IsImmutableBit = BitField<int8_t, bool, 0, 1>;
   using IsNullableBit = BitField<int8_t, bool, IsImmutableBit::kNextBit, 1>;
@@ -232,6 +265,7 @@
   const ClassIdTagType cid_;  // Concrete cid of a value or kDynamicCid.
 
   const intptr_t offset_in_bytes_;
+  const Representation representation_;
 
   // Kind dependent data:
   //   - name as a Dart String object for local variables;
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index f4a5ec7..5ed4c10 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -4,6 +4,7 @@
 
 #include "vm/compiler/frontend/base_flow_graph_builder.h"
 
+#include "vm/compiler/backend/range_analysis.h"  // For Range.
 #include "vm/compiler/ffi/call.h"
 #include "vm/compiler/frontend/flow_graph_builder.h"  // For InlineExitCollector.
 #include "vm/compiler/jit/compiler.h"  // For Compiler::IsBackgroundCompilation().
@@ -245,6 +246,15 @@
       Constant(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld))));
 }
 
+Fragment BaseFlowGraphBuilder::UnboxedIntConstant(
+    int64_t value,
+    Representation representation) {
+  const auto& obj = Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld));
+  auto const constant = new (Z) UnboxedConstantInstr(obj, representation);
+  Push(constant);
+  return Fragment(constant);
+}
+
 Fragment BaseFlowGraphBuilder::MemoryCopy(classid_t src_cid,
                                           classid_t dest_cid) {
   Value* length = Pop();
@@ -793,38 +803,19 @@
 
 Fragment BaseFlowGraphBuilder::SmiBinaryOp(Token::Kind kind,
                                            bool is_truncating) {
-  Value* right = Pop();
-  Value* left = Pop();
-  BinarySmiOpInstr* instr =
-      new (Z) BinarySmiOpInstr(kind, left, right, GetNextDeoptId());
-  if (is_truncating) {
-    instr->mark_truncating();
-  }
-  Push(instr);
-  return Fragment(instr);
+  return BinaryIntegerOp(kind, kTagged, is_truncating);
 }
 
 Fragment BaseFlowGraphBuilder::BinaryIntegerOp(Token::Kind kind,
                                                Representation representation,
                                                bool is_truncating) {
   ASSERT(representation == kUnboxedInt32 || representation == kUnboxedUint32 ||
-         representation == kUnboxedInt64);
+         representation == kUnboxedInt64 || representation == kTagged);
   Value* right = Pop();
   Value* left = Pop();
-  BinaryIntegerOpInstr* instr;
-  switch (representation) {
-    case kUnboxedInt32:
-      instr = new (Z) BinaryInt32OpInstr(kind, left, right, GetNextDeoptId());
-      break;
-    case kUnboxedUint32:
-      instr = new (Z) BinaryUint32OpInstr(kind, left, right, GetNextDeoptId());
-      break;
-    case kUnboxedInt64:
-      instr = new (Z) BinaryInt64OpInstr(kind, left, right, GetNextDeoptId());
-      break;
-    default:
-      UNREACHABLE();
-  }
+  BinaryIntegerOpInstr* instr = BinaryIntegerOpInstr::Make(
+      representation, kind, left, right, GetNextDeoptId());
+  ASSERT(instr != nullptr);
   if (is_truncating) {
     instr->mark_truncating();
   }
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.h b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
index 40b9d4f..095d6d6 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
@@ -155,7 +155,11 @@
         next_used_try_index_(0),
         stack_(NULL),
         exit_collector_(exit_collector),
-        inlining_unchecked_entry_(inlining_unchecked_entry) {}
+        inlining_unchecked_entry_(inlining_unchecked_entry),
+        saved_args_desc_array_(
+            has_saved_args_desc_array()
+                ? Array::ZoneHandle(zone_, function_.saved_args_desc())
+                : Object::null_array()) {}
 
   Fragment LoadField(const Field& field, bool calls_initializer);
   Fragment LoadNativeField(const Slot& native_field,
@@ -255,6 +259,7 @@
                          bool number_check = false);
   Fragment StrictCompare(Token::Kind kind, bool number_check = false);
   Fragment Goto(JoinEntryInstr* destination);
+  Fragment UnboxedIntConstant(int64_t value, Representation representation);
   Fragment IntConstant(int64_t value);
   Fragment Constant(const Object& value);
   Fragment NullConstant();
@@ -312,6 +317,9 @@
   void InlineBailout(const char* reason);
 
   Fragment LoadArgDescriptor() {
+    if (has_saved_args_desc_array()) {
+      return Constant(saved_args_desc_array());
+    }
     ASSERT(parsed_function_->has_arg_desc_var());
     return LoadLocal(parsed_function_->arg_desc_var());
   }
@@ -425,6 +433,18 @@
   // Sets raw parameter variables to inferred constant values.
   Fragment InitConstantParameters();
 
+  // Returns whether this function has a saved arguments descriptor array.
+  bool has_saved_args_desc_array() {
+    return function_.IsInvokeFieldDispatcher() ||
+           function_.IsNoSuchMethodDispatcher();
+  }
+
+  // Returns the saved arguments descriptor array for functions that have them.
+  const Array& saved_args_desc_array() {
+    ASSERT(has_saved_args_desc_array());
+    return saved_args_desc_array_;
+  }
+
  protected:
   intptr_t AllocateBlockId() { return ++last_used_block_id_; }
 
@@ -445,6 +465,7 @@
   InlineExitCollector* exit_collector_;
 
   const bool inlining_unchecked_entry_;
+  const Array& saved_args_desc_array_;
 
   friend class StreamingFlowGraphBuilder;
   friend class BytecodeFlowGraphBuilder;
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index d1e60cd..1ce2b7a 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -617,7 +617,10 @@
   copy_args_prologue = Fragment(copy_args_prologue.entry, prologue_entry);
 
   ASSERT(throw_no_such_method_ == nullptr);
-  throw_no_such_method_ = B->BuildThrowNoSuchMethod();
+  if (function().CanReceiveDynamicInvocation()) {
+    // We only pass a non-nullptr NSM block if argument shape checks are needed.
+    throw_no_such_method_ = B->BuildThrowNoSuchMethod();
+  }
 
   PrologueBuilder prologue_builder(parsed_function(), B->last_used_block_id_,
                                    B->IsCompiledForOsr(), B->IsInlining());
@@ -670,43 +673,45 @@
   const intptr_t expected_num_type_args = DecodeOperandA().value();
   LocalVariable* type_args_var = LocalVariableAt(DecodeOperandE().value());
 
-  if (throw_no_such_method_ == nullptr) {
+  const bool check_lengths = function().CanReceiveDynamicInvocation();
+
+  if (check_lengths && throw_no_such_method_ == nullptr) {
     throw_no_such_method_ = B->BuildThrowNoSuchMethod();
   }
 
   Fragment setup_type_args;
-  JoinEntryInstr* done = B->BuildJoinEntry();
 
   // Type args are always optional, so length can always be zero.
-  // If expect_type_args, a non-zero length must match the declaration length.
-  TargetEntryInstr *then, *fail;
-  setup_type_args += B->LoadArgDescriptor();
-  setup_type_args +=
-      B->LoadNativeField(Slot::ArgumentsDescriptor_type_args_len());
-
+  // If expect_type_args and lengths are being checked, a non-zero length must
+  // match the declaration length.
   if (expected_num_type_args != 0) {
-    JoinEntryInstr* join2 = B->BuildJoinEntry();
+    JoinEntryInstr* done = B->BuildJoinEntry();
 
+    TargetEntryInstr *then, *otherwise;
+    setup_type_args += B->LoadArgDescriptor();
+    setup_type_args +=
+        B->LoadNativeField(Slot::ArgumentsDescriptor_type_args_len());
     LocalVariable* len = B->MakeTemporary();
-
-    TargetEntryInstr* otherwise;
     setup_type_args += B->LoadLocal(len);
     setup_type_args += B->IntConstant(0);
     setup_type_args += B->BranchIfEqual(&then, &otherwise);
 
-    TargetEntryInstr* then2;
-    Fragment check_len(otherwise);
-    check_len += B->LoadLocal(len);
-    check_len += B->IntConstant(expected_num_type_args);
-    check_len += B->BranchIfEqual(&then2, &fail);
+    JoinEntryInstr* join2 = B->BuildJoinEntry();
 
-    Fragment null_type_args(then);
-    null_type_args += B->NullConstant();
-    null_type_args += B->StoreLocalRaw(TokenPosition::kNoSource, type_args_var);
-    null_type_args += B->Drop();
-    null_type_args += B->Goto(join2);
+    Fragment store_type_args(otherwise);
+    if (check_lengths) {
+      Fragment check_length;
+      check_length += B->LoadLocal(len);
+      check_length += B->IntConstant(expected_num_type_args);
+      TargetEntryInstr *then2, *fail;
+      check_length += B->BranchIfEqual(&then2, &fail);
+      check_length.current = then2;  // Continue in the non-error case.
 
-    Fragment store_type_args(then2);
+      Fragment(fail) + B->Goto(throw_no_such_method_);
+
+      store_type_args += check_length;
+    }
+
     store_type_args += B->LoadArgDescriptor();
     store_type_args += B->LoadNativeField(Slot::ArgumentsDescriptor_count());
     store_type_args += B->LoadFpRelativeSlot(
@@ -718,16 +723,27 @@
     store_type_args += B->Drop();
     store_type_args += B->Goto(join2);
 
+    Fragment null_type_args(then);
+    null_type_args += B->NullConstant();
+    null_type_args += B->StoreLocalRaw(TokenPosition::kNoSource, type_args_var);
+    null_type_args += B->Drop();
+    null_type_args += B->Goto(join2);
+
     Fragment(join2) + B->Drop() + B->Goto(done);
-    Fragment(fail) + B->Goto(throw_no_such_method_);
-  } else {
+
+    setup_type_args.current = done;
+  } else if (check_lengths) {
+    TargetEntryInstr *then, *fail;
+    setup_type_args += B->LoadArgDescriptor();
+    setup_type_args +=
+        B->LoadNativeField(Slot::ArgumentsDescriptor_type_args_len());
     setup_type_args += B->IntConstant(0);
     setup_type_args += B->BranchIfEqual(&then, &fail);
-    Fragment(then) + B->Goto(done);
+    setup_type_args.current = then;  // Continue in the non-error case.
+
     Fragment(fail) + B->Goto(throw_no_such_method_);
   }
 
-  setup_type_args = Fragment(setup_type_args.entry, done);
   ASSERT(IsStackEmpty());
 
   if (expected_num_type_args != 0) {
diff --git a/runtime/vm/compiler/frontend/bytecode_scope_builder.cc b/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
index 2a5e79f..c88a227 100644
--- a/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
@@ -64,6 +64,17 @@
     case FunctionLayout::kImplicitClosureFunction: {
       ASSERT(function.NumImplicitParameters() == 1);
 
+      const auto& parent = Function::Handle(Z, function.parent_function());
+      const auto& target =
+          Function::Handle(Z, function.ImplicitClosureTarget(Z));
+
+      // For BuildGraphOfNoSuchMethodForwarder, since closures no longer
+      // require arg_desc_var in all cases.
+      if (target.IsNull() ||
+          (parent.num_fixed_parameters() != target.num_fixed_parameters())) {
+        needs_expr_temp = true;
+      }
+
       LocalVariable* closure_parameter = MakeVariable(
           Symbols::ClosureParameter(), AbstractType::dynamic_type());
       closure_parameter->set_is_forced_stack();
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 2a05f82..905112c 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -9,6 +9,7 @@
 #include "vm/compiler/backend/il.h"
 #include "vm/compiler/backend/il_printer.h"
 #include "vm/compiler/backend/locations.h"
+#include "vm/compiler/backend/range_analysis.h"
 #include "vm/compiler/ffi/abi.h"
 #include "vm/compiler/ffi/marshaller.h"
 #include "vm/compiler/ffi/recognized_method.h"
@@ -1740,13 +1741,14 @@
 }
 
 BlockEntryInstr* FlowGraphBuilder::BuildPrologue(BlockEntryInstr* normal_entry,
-                                                 PrologueInfo* prologue_info) {
+                                                 PrologueInfo* prologue_info,
+                                                 JoinEntryInstr* nsm) {
   const bool compiling_for_osr = IsCompiledForOsr();
 
   kernel::PrologueBuilder prologue_builder(
       parsed_function_, last_used_block_id_, compiling_for_osr, IsInlining());
   BlockEntryInstr* instruction_cursor =
-      prologue_builder.BuildPrologue(normal_entry, prologue_info);
+      prologue_builder.BuildPrologue(normal_entry, prologue_info, nsm);
 
   last_used_block_id_ = prologue_builder.last_used_block_id();
 
@@ -1837,9 +1839,7 @@
   // parameters, even if they are all known to be passed at the call site
   // because the call site matches the arguments descriptor.  Use null for
   // the default values.
-  const Array& descriptor_array =
-      Array::ZoneHandle(Z, function.saved_args_desc());
-  ArgumentsDescriptor descriptor(descriptor_array);
+  ArgumentsDescriptor descriptor(saved_args_desc_array());
   ZoneGrowableArray<const Instance*>* default_values =
       new ZoneGrowableArray<const Instance*>(Z, descriptor.NamedCount());
   for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) {
@@ -1859,7 +1859,7 @@
   body += Constant(String::ZoneHandle(Z, function.name()));
 
   // Second, the arguments descriptor.
-  body += Constant(descriptor_array);
+  body += Constant(saved_args_desc_array());
 
   // Third, an array containing the original arguments.  Create it and fill
   // it in.
@@ -1928,6 +1928,343 @@
                            prologue_info);
 }
 
+Fragment FlowGraphBuilder::BuildDynamicCallVarsInit(LocalVariable* closure) {
+  auto const vars = parsed_function_->dynamic_closure_call_vars();
+  ASSERT(vars != nullptr);
+  ASSERT(has_saved_args_desc_array());
+  const ArgumentsDescriptor descriptor(saved_args_desc_array());
+  auto const rep = Slot::Function_packed_fields().representation();
+
+  // We extract all the packed fields here so code generation that puts unboxed
+  // integers on the expression stack even in unoptimized code is in one place.
+
+  Fragment init;
+  init += LoadLocal(closure);
+  init += LoadNativeField(Slot::Closure_function());
+  init += LoadNativeField(Slot::Function_packed_fields());
+  init +=
+      BuildExtractPackedFieldIntoSmi<Function::PackedNumFixedParameters>(rep);
+  init += StoreLocal(TokenPosition::kNoSource, vars->num_fixed_params);
+  // Not dropping as we'll use the value to get the max number of parameters.
+
+  init += LoadLocal(closure);
+  init += LoadNativeField(Slot::Closure_function());
+  init += LoadNativeField(Slot::Function_packed_fields());
+  init += BuildExtractPackedFieldIntoSmi<Function::PackedNumOptionalParameters>(
+      rep);
+  init += StoreLocal(TokenPosition::kNoSource, vars->num_opt_params);
+  init += SmiBinaryOp(Token::kADD);
+  init += StoreLocal(TokenPosition::kNoSource, vars->num_max_params);
+  init += Drop();
+
+  // Currently, we only need this initialized to either check provided optional
+  // names, if any, or to check for missing required parameters if null safe.
+  if (Isolate::Current()->null_safety() || descriptor.NamedCount() > 0) {
+    init += LoadLocal(closure);
+    init += LoadNativeField(Slot::Closure_function());
+    init += LoadNativeField(Slot::Function_parameter_names());
+    init += StoreLocal(TokenPosition::kNoSource, vars->parameter_names);
+    init += Drop();
+  }
+
+  init += LoadLocal(closure);
+  init += LoadNativeField(Slot::Closure_function());
+  init += LoadNativeField(Slot::Function_packed_fields());
+  init += BuildExtractPackedFieldIntoSmi<
+      Function::PackedHasNamedOptionalParameters>(rep);
+  init += IntConstant(0);
+  TargetEntryInstr *is_true, *is_false;
+  init += BranchIfEqual(&is_false, &is_true);
+
+  JoinEntryInstr* join = BuildJoinEntry();
+  init.current = join;
+
+  Fragment true_branch(is_true);
+  true_branch += Constant(Object::bool_true());
+  true_branch += StoreLocal(TokenPosition::kNoSource, vars->has_named_params);
+  true_branch += Drop();
+  true_branch += Goto(join);
+
+  Fragment false_branch(is_false);
+  false_branch += Constant(Object::bool_false());
+  false_branch += StoreLocal(TokenPosition::kNoSource, vars->has_named_params);
+  false_branch += Drop();
+  false_branch += Goto(join);
+
+  return init;
+}
+
+Fragment FlowGraphBuilder::BuildClosureCallHasRequiredNamedArgumentsCheck(
+    LocalVariable* closure,
+    JoinEntryInstr* nsm) {
+  auto const vars = parsed_function_->dynamic_closure_call_vars();
+  ASSERT(vars != nullptr);
+  ASSERT(has_saved_args_desc_array());
+  const ArgumentsDescriptor descriptor(saved_args_desc_array());
+
+  // Required named arguments only exist if null_safety is enabled.
+  if (!Isolate::Current()->null_safety()) return Fragment();
+
+  // Loop over the indexes of the named parameters of the function, checking
+  // whether the named parameter at that index is required. If it is, then
+  // check whether it matches any of the names in the ArgumentsDescriptor.
+  JoinEntryInstr* loop = BuildJoinEntry();
+
+  // We iterate from [0, num_named), not [num_fixed, num_named) because the
+  // flag mask and index is based off the named index, not the param index.
+  Fragment check_required;
+  check_required += IntConstant(0);
+  check_required +=
+      StoreLocal(TokenPosition::kNoSource, vars->current_param_index);
+  check_required += Drop();
+  check_required += Goto(loop);
+
+  Fragment loop_check(loop);
+  loop_check += LoadLocal(vars->current_param_index);
+  loop_check += LoadLocal(vars->num_opt_params);
+  loop_check += SmiRelationalOp(Token::kLT);
+  TargetEntryInstr *no_more, *more;
+  loop_check += BranchIfTrue(&more, &no_more);
+
+  JoinEntryInstr* done = BuildJoinEntry();
+  Fragment(no_more) + Goto(done);
+
+  Fragment loop_body(more);
+  // First, we calculate the index to dereference into the parameter names
+  // array and store it in :expr_temp.
+  loop_body += LoadLocal(vars->num_max_params);
+  loop_body += LoadLocal(vars->current_param_index);
+  loop_body += IntConstant(compiler::target::kNumParameterFlagsPerElementLog2);
+  loop_body += SmiBinaryOp(Token::kSHR);
+  loop_body += SmiBinaryOp(Token::kADD);
+  LocalVariable* temp = parsed_function_->expression_temp_var();
+  loop_body += StoreLocal(TokenPosition::kNoSource, temp);
+  // Now we check to see if it is within the bounds of the parameters names
+  // array. If not, we're done, as this and later indices cannot be required.
+  loop_body += LoadLocal(vars->parameter_names);
+  loop_body += LoadNativeField(Slot::Array_length());
+  loop_body += SmiRelationalOp(Token::kLT);
+  TargetEntryInstr *valid_index, *invalid_index;
+  loop_body += BranchIfTrue(&valid_index, &invalid_index);
+
+  Fragment(invalid_index) + Goto(done);
+
+  // Otherwise, we need to retrieve the value. If it's null, then this index
+  // and others that map to the same entry cannot be required (but later ones
+  // may be).
+  loop_body.current = valid_index;
+  loop_body += LoadLocal(vars->parameter_names);
+  loop_body += LoadLocal(temp);  // Index into parameter names array.
+  loop_body += LoadIndexed(compiler::target::kWordSize);
+  // Store the result so we can use it in the non-null branch. We can reuse
+  // :expr_temp as we don't need the names index once we've gotten the contents.
+  loop_body += StoreLocal(TokenPosition::kNoSource, temp);
+  TargetEntryInstr *null_smi, *flags_smi;
+  loop_body += BranchIfNull(&null_smi, &flags_smi);
+
+  // If it was null, then skip forward to the first named parameter index that
+  // would map to the next parameter names index, since no other indices that
+  // map to the same entry can be set either.
+  Fragment skip_ahead(null_smi);
+  skip_ahead += LoadLocal(vars->current_param_index);
+  skip_ahead += IntConstant(compiler::target::kNumParameterFlagsPerElement);
+  skip_ahead += SmiBinaryOp(Token::kADD, /*is_truncating=*/true);
+  skip_ahead += StoreLocal(TokenPosition::kNoSource, vars->current_param_index);
+  skip_ahead += Drop();
+  skip_ahead += Goto(loop);
+
+  // If not null, see if any of the flag bits are set for the given named
+  // parameter. If so, this named parameter is required.
+  loop_body.current = flags_smi;
+  loop_body += LoadLocal(temp);  // Flag bits loaded from parameter names array.
+  loop_body += LoadLocal(vars->current_param_index);
+  loop_body += IntConstant(compiler::target::kNumParameterFlagsPerElement - 1);
+  loop_body += SmiBinaryOp(Token::kBIT_AND);
+  loop_body += SmiBinaryOp(Token::kSHR);
+  loop_body += IntConstant(1);
+  loop_body += SmiBinaryOp(Token::kBIT_AND);
+  loop_body += IntConstant(0);
+  TargetEntryInstr *not_set, *set;
+  loop_body += BranchIfEqual(&not_set, &set);
+
+  // Make a join entry for the increment at the end of the loop, so we can jump
+  // to it if we match one of the names in the ArgumentsDescriptor.
+  JoinEntryInstr* incr_index = BuildJoinEntry();
+  Fragment(not_set) + Goto(incr_index);
+
+  Fragment check_names(set);
+  if (descriptor.NamedCount() > 0) {
+    // First load the name we need to check against into :expr_temp.
+    check_names += LoadLocal(vars->parameter_names);
+    check_names += LoadLocal(vars->current_param_index);
+    check_names += LoadLocal(vars->num_fixed_params);
+    check_names += SmiBinaryOp(Token::kADD, /*is_truncating=*/true);
+    check_names += LoadIndexed(compiler::target::kWordSize);
+    check_names += StoreLocal(TokenPosition::kNoSource, temp);
+    check_names += Drop();
+    // Now iterate over the names in the ArgumentsDescriptor and add a check
+    // against each that goes to t he next loop iteration if the name is found.
+    for (intptr_t i = 0; i < descriptor.NamedCount(); i++) {
+      const auto& name = String::ZoneHandle(Z, descriptor.NameAt(i));
+      check_names += LoadLocal(temp);
+      check_names += Constant(name);
+      TargetEntryInstr *str_equal, *str_neq;
+      check_names += BranchIfEqual(&str_equal, &str_neq);
+      check_names.current = str_neq;
+
+      Fragment(str_equal) + Goto(incr_index);
+    }
+  }
+  // None of the names in the arguments descriptor matched, so throw NSM.
+  check_names += Goto(nsm);
+
+  // Increment the counter if the current parameter wasn't required or was
+  // required but provided.
+  loop_body.current = incr_index;
+  loop_body += LoadLocal(vars->current_param_index);
+  loop_body += IntConstant(1);
+  loop_body += SmiBinaryOp(Token::kADD, /*is_truncating=*/true);
+  loop_body += StoreLocal(TokenPosition::kNoSource, vars->current_param_index);
+  loop_body += Drop();
+  loop_body += Goto(loop);
+
+  check_required.current = done;
+  return check_required;
+}
+
+Fragment FlowGraphBuilder::BuildClosureCallArgumentsValidCheck(
+    LocalVariable* closure,
+    JoinEntryInstr* nsm) {
+  auto const vars = parsed_function_->dynamic_closure_call_vars();
+  ASSERT(vars != nullptr);
+  ASSERT(has_saved_args_desc_array());
+  const ArgumentsDescriptor descriptor(saved_args_desc_array());
+
+  // Type argument length checking, including checking for delayed type
+  // arguments, is already done in the prologue builder.
+
+  Fragment check_entry;
+  check_entry += LoadLocal(vars->has_named_params);
+  TargetEntryInstr *has_named, *has_positional;
+  check_entry += BranchIfTrue(&has_named, &has_positional);
+  JoinEntryInstr* join_after_optional = BuildJoinEntry();
+  check_entry.current = join_after_optional;
+
+  if (descriptor.NamedCount() > 0) {
+    // No reason to continue checking, as this function doesn't take named args.
+    Fragment(has_positional) + Goto(nsm);
+  } else {
+    Fragment check_pos(has_positional);
+    check_pos += LoadLocal(vars->num_fixed_params);
+    check_pos += IntConstant(descriptor.PositionalCount());
+    check_pos += SmiRelationalOp(Token::kLTE);
+    TargetEntryInstr *enough, *too_few;
+    check_pos += BranchIfTrue(&enough, &too_few);
+    check_pos.current = enough;
+
+    Fragment(too_few) + Goto(nsm);
+
+    check_pos += IntConstant(descriptor.PositionalCount());
+    check_pos += LoadLocal(vars->num_max_params);
+    check_pos += SmiRelationalOp(Token::kLTE);
+    TargetEntryInstr *valid, *too_many;
+    check_pos += BranchIfTrue(&valid, &too_many);
+    check_pos.current = valid;
+
+    Fragment(too_many) + Goto(nsm);
+
+    check_pos += Goto(join_after_optional);
+  }
+
+  Fragment check_named(has_named);
+
+  TargetEntryInstr *same, *different;
+  check_named += LoadLocal(vars->num_fixed_params);
+  check_named += IntConstant(descriptor.PositionalCount());
+  check_named += BranchIfEqual(&same, &different);
+  check_named.current = same;
+
+  Fragment(different) + Goto(nsm);
+
+  if (descriptor.NamedCount() > 0) {
+    check_named += IntConstant(descriptor.NamedCount());
+    check_named += LoadLocal(vars->num_opt_params);
+    check_named += SmiRelationalOp(Token::kLTE);
+    TargetEntryInstr *valid, *too_many;
+    check_named += BranchIfTrue(&valid, &too_many);
+    check_named.current = valid;
+
+    Fragment(too_many) + Goto(nsm);
+  }
+
+  check_named += BuildClosureCallHasRequiredNamedArgumentsCheck(closure, nsm);
+  check_named += Goto(join_after_optional);
+
+  return check_entry;
+}
+
+Fragment FlowGraphBuilder::BuildClosureCallNamedArgumentCheck(
+    LocalVariable* closure,
+    intptr_t pos,
+    JoinEntryInstr* nsm) {
+  auto const vars = parsed_function_->dynamic_closure_call_vars();
+  ASSERT(vars != nullptr);
+  ASSERT(has_saved_args_desc_array());
+  const ArgumentsDescriptor descriptor(saved_args_desc_array());
+
+  // If this isn't a named argument, then don't build anything.
+  if (pos < descriptor.PositionalCount()) return Fragment();
+  const intptr_t named_pos = pos - descriptor.PositionalCount();
+  ASSERT(named_pos < descriptor.NamedCount());
+
+  // Loop over the indexes of the named parameters of the function, checking
+  // whether the named parameter at that index is required. If it is, then
+  // check whether it matches any of the names in the ArgumentsDescriptor.
+  JoinEntryInstr* loop = BuildJoinEntry();
+
+  // We iterate from [0, num_named), not [num_fixed, num_named) because the
+  // flag mask and index is based off the named index, not the param index.
+  Fragment check_arg_name;
+  check_arg_name += LoadLocal(vars->num_fixed_params);
+  check_arg_name +=
+      StoreLocal(TokenPosition::kNoSource, vars->current_param_index);
+  check_arg_name += Drop();
+  check_arg_name += Goto(loop);
+
+  Fragment loop_check(loop);
+  loop_check += LoadLocal(vars->current_param_index);
+  loop_check += LoadLocal(vars->num_max_params);
+  loop_check += SmiRelationalOp(Token::kLT);
+  TargetEntryInstr *no_more, *more;
+  loop_check += BranchIfTrue(&more, &no_more);
+
+  JoinEntryInstr* done = BuildJoinEntry();
+  // None of the parameter names matched.
+  Fragment(no_more) + Goto(nsm);
+
+  Fragment loop_body(more);
+  loop_body += LoadLocal(vars->parameter_names);
+  loop_body += LoadLocal(vars->current_param_index);
+  loop_body += LoadIndexed(compiler::target::kWordSize);
+  loop_body += Constant(String::ZoneHandle(Z, descriptor.NameAt(named_pos)));
+  TargetEntryInstr *str_equal, *str_neq;
+  loop_body += BranchIfEqual(&str_equal, &str_neq);
+
+  Fragment(str_equal) + Goto(done);
+
+  // Increment the index and jump back to the loop check.
+  loop_body.current = str_neq;
+  loop_body += LoadLocal(vars->current_param_index);
+  loop_body += IntConstant(1);
+  loop_body += SmiBinaryOp(Token::kADD, /*is_truncating=*/true);
+  loop_body += StoreLocal(TokenPosition::kNoSource, vars->current_param_index);
+  loop_body += Drop();
+  loop_body += Goto(loop);
+
+  check_arg_name.current = done;
+  return check_arg_name;
+}
+
 FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
     const Function& function) {
   // Find the name of the field we should dispatch to.
@@ -1952,15 +2289,24 @@
   const bool is_closure_call = (owner.raw() == closure_class.raw()) &&
                                field_name.Equals(Symbols::Call());
 
+  JoinEntryInstr* nsm = nullptr;
+  if (is_dynamic_call && is_closure_call) {
+    // Create a NSM block that can be shared with the prologue builder.
+    nsm = BuildThrowNoSuchMethod();
+    // The whole reason for making this invoke field dispatcher is that
+    // this closure call needs checking, so we shouldn't inline a call to an
+    // unchecked entry that can't tail call NSM.
+    InlineBailout(
+        "kernel::FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher");
+  }
+
   // Set default parameters & construct argument names array.
   //
   // The backend will expect an array of default values for all the named
   // parameters, even if they are all known to be passed at the call site
   // because the call site matches the arguments descriptor.  Use null for
   // the default values.
-  const Array& descriptor_array =
-      Array::ZoneHandle(Z, function.saved_args_desc());
-  ArgumentsDescriptor descriptor(descriptor_array);
+  const ArgumentsDescriptor descriptor(saved_args_desc_array());
   const Array& argument_names =
       Array::ZoneHandle(Z, Array::New(descriptor.NamedCount(), Heap::kOld));
   ZoneGrowableArray<const Instance*>* default_values =
@@ -1981,7 +2327,7 @@
 
   PrologueInfo prologue_info(-1, -1);
   BlockEntryInstr* instruction_cursor =
-      BuildPrologue(normal_entry, &prologue_info);
+      BuildPrologue(normal_entry, &prologue_info, nsm);
 
   Fragment body(instruction_cursor);
   body += CheckStackOverflowInPrologue(function.token_pos());
@@ -2000,6 +2346,15 @@
     body += LoadLocal(closure);
 
     if (is_dynamic_call) {
+      // We should have a throw NSM block from the prologue.
+      ASSERT(nsm != nullptr);
+      // Init the variables we'll be using for dynamic call checking.
+      body += BuildDynamicCallVarsInit(closure);
+      // Check that the shape of the arguments generally matches what the
+      // closure function expects. The only remaining non-type check after this
+      // is that the names for optional arguments are valid.
+      body += BuildClosureCallArgumentsValidCheck(closure, nsm);
+
       // TODO(dartbug.com/40813): Move checks that are currently compiled
       // in the closure body to here, using the dynamic versions of
       // AssertSubtype to typecheck the type arguments using the runtime types
@@ -2023,6 +2378,9 @@
       // in the closure body to here, using the dynamic versions of
       // AssertAssignable to typecheck the parameters using the runtime types
       // available in the closure object.
+      //
+      // For now, we check that any named arguments have valid names.
+      body += BuildClosureCallNamedArgumentCheck(closure, pos, nsm);
     }
   }
 
@@ -2035,9 +2393,11 @@
                         descriptor.Count(), argument_names);
   } else {
     const intptr_t kNumArgsChecked = 1;
-    body += InstanceCall(TokenPosition::kMinSource, Symbols::Call(),
-                         Token::kILLEGAL, descriptor.TypeArgsLen(),
-                         descriptor.Count(), argument_names, kNumArgsChecked);
+    body +=
+        InstanceCall(TokenPosition::kMinSource,
+                     is_dynamic_call ? Symbols::DynamicCall() : Symbols::Call(),
+                     Token::kILLEGAL, descriptor.TypeArgsLen(),
+                     descriptor.Count(), argument_names, kNumArgsChecked);
   }
 
   body += Return(TokenPosition::kNoSource);
@@ -2070,19 +2430,15 @@
     if (parsed_function_->has_arg_desc_var()) {
       body += LoadArgDescriptor();
       body += LoadNativeField(Slot::ArgumentsDescriptor_size());
-      body += LoadLocal(parsed_function_->current_context_var());
-      body += LoadNativeField(Slot::GetContextVariableSlotFor(
-          thread_, *parsed_function_->receiver_var()));
-      body += StoreFpRelativeSlot(
-          kWordSize * compiler::target::frame_layout.param_end_from_fp);
     } else {
-      body += LoadLocal(parsed_function_->current_context_var());
-      body += LoadNativeField(Slot::GetContextVariableSlotFor(
-          thread_, *parsed_function_->receiver_var()));
-      body += StoreFpRelativeSlot(
-          kWordSize * (compiler::target::frame_layout.param_end_from_fp +
-                       function.NumParameters()));
+      ASSERT(function.NumOptionalParameters() == 0);
+      body += IntConstant(function.NumParameters());
     }
+    body += LoadLocal(parsed_function_->current_context_var());
+    body += LoadNativeField(Slot::GetContextVariableSlotFor(
+        thread_, *parsed_function_->receiver_var()));
+    body += StoreFpRelativeSlot(
+        kWordSize * compiler::target::frame_layout.param_end_from_fp);
   }
 
   if (function.NeedsArgumentTypeChecks()) {
@@ -2419,17 +2775,7 @@
 FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction(
     const Function& function) {
   const Function& parent = Function::ZoneHandle(Z, function.parent_function());
-  const String& func_name = String::ZoneHandle(Z, parent.name());
-  const Class& owner = Class::ZoneHandle(Z, parent.Owner());
-  Function& target = Function::ZoneHandle(Z, owner.LookupFunction(func_name));
-
-  if (!target.IsNull() && (target.raw() != parent.raw())) {
-    DEBUG_ASSERT(Isolate::Current()->HasAttemptedReload());
-    if ((target.is_static() != parent.is_static()) ||
-        (target.kind() != parent.kind())) {
-      target = Function::null();
-    }
-  }
+  Function& target = Function::ZoneHandle(Z, function.ImplicitClosureTarget(Z));
 
   if (target.IsNull() ||
       (parent.num_fixed_parameters() != target.num_fixed_parameters())) {
@@ -2754,6 +3100,16 @@
                            prologue_info);
 }
 
+void FlowGraphBuilder::SetConstantRangeOfCurrentDefinition(
+    const Fragment& fragment,
+    int64_t min,
+    int64_t max) {
+  ASSERT(fragment.current->IsDefinition());
+  Range range(RangeBoundary::FromConstant(min),
+              RangeBoundary::FromConstant(max));
+  fragment.current->AsDefinition()->set_range(range);
+}
+
 Fragment FlowGraphBuilder::EnterHandleScope() {
   auto* instr = new (Z)
       EnterHandleScopeInstr(EnterHandleScopeInstr::Kind::kEnterHandleScope);
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 0aff448..19b0a0b 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -67,7 +67,8 @@
 
  private:
   BlockEntryInstr* BuildPrologue(BlockEntryInstr* normal_entry,
-                                 PrologueInfo* prologue_info);
+                                 PrologueInfo* prologue_info,
+                                 JoinEntryInstr* nsm = nullptr);
 
   // Return names of optional named parameters of [function].
   ArrayPtr GetOptionalParameterNames(const Function& function);
@@ -79,6 +80,33 @@
 
   FlowGraph* BuildGraphOfMethodExtractor(const Function& method);
   FlowGraph* BuildGraphOfNoSuchMethodDispatcher(const Function& function);
+
+  Fragment BuildDynamicCallVarsInit(LocalVariable* closure);
+
+  // The BuildClosureCall...Check methods differs from the checks built in the
+  // PrologueBuilder in that they are built for invoke field dispatchers,
+  // where the ArgumentsDescriptor is known at compile time but the specific
+  // closure function is retrieved at runtime.
+
+  // Builds checks that all required arguments are provided. Generates an empty
+  // fragment if null safety is not enabled.
+  Fragment BuildClosureCallHasRequiredNamedArgumentsCheck(
+      LocalVariable* closure,
+      JoinEntryInstr* nsm);
+
+  // Builds checks for checking the arguments of a call are valid for the
+  // function retrieved at runtime from the closure. Checks almost all the
+  // same cases as Function::AreArgumentsValid, leaving only name checking
+  // for optional named arguments to be checked during argument type checking.
+  Fragment BuildClosureCallArgumentsValidCheck(LocalVariable* closure,
+                                               JoinEntryInstr* nsm);
+
+  // Builds checks that the given named argument has a valid argument name.
+  // Returns the empty fragment for positional arguments.
+  Fragment BuildClosureCallNamedArgumentCheck(LocalVariable* closure,
+                                              intptr_t pos,
+                                              JoinEntryInstr* nsm);
+
   FlowGraph* BuildGraphOfInvokeFieldDispatcher(const Function& function);
   FlowGraph* BuildGraphOfFfiTrampoline(const Function& function);
   FlowGraph* BuildGraphOfFfiCallback(const Function& function);
@@ -352,6 +380,35 @@
   //
   FlowGraph* BuildGraphOfDynamicInvocationForwarder(const Function& function);
 
+  void SetConstantRangeOfCurrentDefinition(const Fragment& fragment,
+                                           int64_t min,
+                                           int64_t max);
+
+  // Extracts a packed field out of the unboxed value with representation [rep
+  // on the top of the stack. Picks a sequence that keeps unboxed values on the
+  // expression stack only as needed, switching to Smis as soon as possible.
+  template <typename T>
+  Fragment BuildExtractPackedFieldIntoSmi(Representation rep) {
+    Fragment instructions;
+    // Since kBIT_AND never throws or deoptimizes, we require that the result of
+    // masking the field in place fits into a Smi, so we can use Smi operations
+    // for the shift.
+    static_assert(T::mask_in_place() <= compiler::target::kSmiMax,
+                  "Cannot fit results of masking in place into a Smi");
+    instructions += UnboxedIntConstant(T::mask_in_place(), rep);
+    instructions += BinaryIntegerOp(Token::kBIT_AND, rep);
+    // Set the range of the definition that will be used as the value in the
+    // box so that ValueFitsSmi() can return true even in unoptimized code.
+    SetConstantRangeOfCurrentDefinition(instructions, 0, T::mask_in_place());
+    instructions += Box(rep);
+    if (T::shift() != 0) {
+      // Only add the shift operation if it's necessary.
+      instructions += IntConstant(T::shift());
+      instructions += SmiBinaryOp(Token::kSHR);
+    }
+    return instructions;
+  }
+
   TranslationHelper translation_helper_;
   Thread* thread_;
   Zone* zone_;
diff --git a/runtime/vm/compiler/frontend/prologue_builder.cc b/runtime/vm/compiler/frontend/prologue_builder.cc
index 6bf2aff..fc92e62 100644
--- a/runtime/vm/compiler/frontend/prologue_builder.cc
+++ b/runtime/vm/compiler/frontend/prologue_builder.cc
@@ -45,7 +45,8 @@
 }
 
 BlockEntryInstr* PrologueBuilder::BuildPrologue(BlockEntryInstr* entry,
-                                                PrologueInfo* prologue_info) {
+                                                PrologueInfo* prologue_info,
+                                                JoinEntryInstr* provided_nsm) {
   // We always have to build the graph, but we only link it sometimes.
   const bool link = !is_inlining_ && !compiling_for_osr_;
 
@@ -53,14 +54,18 @@
 
   const bool load_optional_arguments = function_.HasOptionalParameters();
   const bool expect_type_args = function_.IsGeneric();
-  const bool check_arguments = function_.CanReceiveDynamicInvocation();
+  const bool check_shapes = function_.CanReceiveDynamicInvocation();
 
   Fragment prologue = Fragment(entry);
-  JoinEntryInstr* nsm = NULL;
-  if (load_optional_arguments || check_arguments || expect_type_args) {
-    nsm = BuildThrowNoSuchMethod();
-  }
-  if (check_arguments) {
+
+  // We only check for bad argument shapes and throw NSM in functions that
+  // can receive dynamic invocation. Otherwise, the NSM block is never used
+  // and so there's no need to create it. The helper methods can only throw
+  // NSM in appropriate spots if one was created.
+  JoinEntryInstr* nsm = nullptr;
+  if (check_shapes) {
+    // If no block for throwing NSM was provided, create a new one.
+    nsm = provided_nsm != nullptr ? provided_nsm : BuildThrowNoSuchMethod();
     Fragment f = BuildTypeArgumentsLengthCheck(nsm, expect_type_args);
     if (link) prologue += f;
   }
@@ -68,7 +73,7 @@
     Fragment f = BuildOptionalParameterHandling(
         nsm, parsed_function_->expression_temp_var());
     if (link) prologue += f;
-  } else if (check_arguments) {
+  } else if (check_shapes) {
     Fragment f = BuildFixedParameterLengthChecks(nsm);
     if (link) prologue += f;
   }
@@ -102,6 +107,7 @@
 
 Fragment PrologueBuilder::BuildTypeArgumentsLengthCheck(JoinEntryInstr* nsm,
                                                         bool expect_type_args) {
+  ASSERT(nsm != nullptr);
   Fragment check_type_args;
   JoinEntryInstr* done = BuildJoinEntry();
 
@@ -144,6 +150,12 @@
 Fragment PrologueBuilder::BuildOptionalParameterHandling(
     JoinEntryInstr* nsm,
     LocalVariable* temp_var) {
+  // We only need to check the shape of the arguments (correct parameter count
+  // and correct names/provided required arguments) when the function can be
+  // invoked dynamically. The caller only provides a non-nullptr nsm block if
+  // dynamic invocation is possible.
+  const bool check_arguments_shape = nsm != nullptr;
+
   Fragment copy_args_prologue;
   const int num_fixed_params = function_.num_fixed_parameters();
   const int num_opt_pos_params = function_.NumOptionalPositionalParameters();
@@ -169,25 +181,27 @@
   copy_args_prologue += LoadNativeField(Slot::ArgumentsDescriptor_count());
   LocalVariable* count_var = MakeTemporary();
 
-  // Ensure the caller provided at least [min_num_pos_args] arguments.
-  copy_args_prologue += IntConstant(min_num_pos_args);
-  copy_args_prologue += LoadLocal(positional_count_var);
-  copy_args_prologue += SmiRelationalOp(Token::kLTE);
-  TargetEntryInstr *success1, *fail1;
-  copy_args_prologue += BranchIfTrue(&success1, &fail1);
-  copy_args_prologue = Fragment(copy_args_prologue.entry, success1);
+  if (check_arguments_shape) {
+    // Ensure the caller provided at least [min_num_pos_args] arguments.
+    copy_args_prologue += IntConstant(min_num_pos_args);
+    copy_args_prologue += LoadLocal(positional_count_var);
+    copy_args_prologue += SmiRelationalOp(Token::kLTE);
+    TargetEntryInstr *success1, *fail1;
+    copy_args_prologue += BranchIfTrue(&success1, &fail1);
+    copy_args_prologue = Fragment(copy_args_prologue.entry, success1);
 
-  // Ensure the caller provided at most [max_num_pos_args] arguments.
-  copy_args_prologue += LoadLocal(positional_count_var);
-  copy_args_prologue += IntConstant(max_num_pos_args);
-  copy_args_prologue += SmiRelationalOp(Token::kLTE);
-  TargetEntryInstr *success2, *fail2;
-  copy_args_prologue += BranchIfTrue(&success2, &fail2);
-  copy_args_prologue = Fragment(copy_args_prologue.entry, success2);
+    // Ensure the caller provided at most [max_num_pos_args] arguments.
+    copy_args_prologue += LoadLocal(positional_count_var);
+    copy_args_prologue += IntConstant(max_num_pos_args);
+    copy_args_prologue += SmiRelationalOp(Token::kLTE);
+    TargetEntryInstr *success2, *fail2;
+    copy_args_prologue += BranchIfTrue(&success2, &fail2);
+    copy_args_prologue = Fragment(copy_args_prologue.entry, success2);
 
-  // Link up the argument check failing code.
-  Fragment(fail1) + Goto(nsm);
-  Fragment(fail2) + Goto(nsm);
+    // Link up the argument check failing code.
+    Fragment(fail1) + Goto(nsm);
+    Fragment(fail2) + Goto(nsm);
+  }
 
   copy_args_prologue += LoadLocal(count_var);
   copy_args_prologue += IntConstant(min_num_pos_args);
@@ -279,16 +293,17 @@
     copy_args_prologue += Goto(next_missing /* join good/not_good flows */);
     copy_args_prologue.current = next_missing;
 
-    // If there are more arguments from the caller we haven't processed, go
-    // NSM.
-    TargetEntryInstr *done, *unknown_named_arg_passed;
-    copy_args_prologue += LoadLocal(positional_count_var);
-    copy_args_prologue += LoadLocal(count_var);
-    copy_args_prologue += BranchIfEqual(&done, &unknown_named_arg_passed);
-    copy_args_prologue.current = done;
-    {
-      Fragment f(unknown_named_arg_passed);
-      f += Goto(nsm);
+    if (check_arguments_shape) {
+      // Check for unprocessed arguments and throw NSM if there are any.
+      TargetEntryInstr *done, *unknown_named_arg_passed;
+      copy_args_prologue += LoadLocal(positional_count_var);
+      copy_args_prologue += LoadLocal(count_var);
+      copy_args_prologue += BranchIfEqual(&done, &unknown_named_arg_passed);
+      copy_args_prologue.current = done;
+      {
+        Fragment f(unknown_named_arg_passed);
+        f += Goto(nsm);
+      }
     }
   } else {
     ASSERT(num_opt_named_params > 0);
@@ -318,36 +333,12 @@
       copy_args_prologue += SmiBinaryOp(Token::kMUL, /* truncate= */ true);
       LocalVariable* tuple_diff = MakeTemporary();
 
-      // name = arg_desc[names_offset + arg_desc_name_index + nameOffset]
-      copy_args_prologue += LoadArgDescriptor();
-      copy_args_prologue +=
-          IntConstant((first_name_offset +
-                       compiler::target::ArgumentsDescriptor::name_offset()) /
-                      compiler::target::kWordSize);
-      copy_args_prologue += LoadLocal(tuple_diff);
-      copy_args_prologue += SmiBinaryOp(Token::kADD, /* truncate= */ true);
-      copy_args_prologue +=
-          LoadIndexed(/* index_scale = */ compiler::target::kWordSize);
-
-      // first name in sorted list of all names
-      const String& param_name = String::ZoneHandle(
-          Z, function_.ParameterNameAt(opt_param_position[i]));
-      ASSERT(param_name.IsSymbol());
-      copy_args_prologue += Constant(param_name);
-
-      // Compare the two names: Note that the ArgumentDescriptor array always
-      // terminates with a "null" name (i.e. kNullCid), which will prevent us
-      // from running out-of-bounds.
-      TargetEntryInstr *supplied, *missing;
-      copy_args_prologue += BranchIfStrictEqual(&supplied, &missing);
-
-      // Join good/not_good.
-      JoinEntryInstr* join = BuildJoinEntry();
-
       // Let's load position from arg descriptor (to see which parameter is the
       // name) and move kEntrySize forward in ArgDescriptopr names array.
-      Fragment good(supplied);
-
+      //
+      // Later we'll either add this fragment directly to the copy_args_prologue
+      // if no check is needed or add an appropriate check.
+      Fragment good;
       {
         // fp[target::frame_layout.param_end_from_fp + (count_var - pos)]
         good += LoadLocal(count_var);
@@ -380,41 +371,82 @@
         good += StoreLocalRaw(TokenPosition::kNoSource,
                               optional_count_vars_processed);
         good += Drop();
-
-        good += Goto(join);
       }
 
-      // We had no match. If the param is required, throw a NoSuchMethod error.
-      // Otherwise just load the default constant.
-      Fragment not_good(missing);
-      if (null_safety && function_.IsRequiredAt(opt_param_position[i])) {
-        not_good += Goto(nsm);
+      const bool required =
+          null_safety && function_.IsRequiredAt(opt_param_position[i]);
+
+      // If this function cannot be invoked dynamically and this is a required
+      // named argument, then we can just add this fragment directly without
+      // checking the name to ensure it was provided.
+      if (required && !check_arguments_shape) {
+        copy_args_prologue += good;
       } else {
-        not_good += Constant(
-            DefaultParameterValueAt(opt_param_position[i] - num_fixed_params));
+        // name = arg_desc[names_offset + arg_desc_name_index + nameOffset]
+        copy_args_prologue += LoadArgDescriptor();
+        copy_args_prologue +=
+            IntConstant((first_name_offset +
+                         compiler::target::ArgumentsDescriptor::name_offset()) /
+                        compiler::target::kWordSize);
+        copy_args_prologue += LoadLocal(tuple_diff);
+        copy_args_prologue += SmiBinaryOp(Token::kADD, /* truncate= */ true);
+        copy_args_prologue +=
+            LoadIndexed(/* index_scale = */ compiler::target::kWordSize);
 
-        // Copy down with default value.
-        not_good += StoreLocalRaw(TokenPosition::kNoSource,
-                                  ParameterVariable(opt_param_position[i]));
-        not_good += Drop();
-        not_good += Goto(join);
+        // first name in sorted list of all names
+        const String& param_name = String::ZoneHandle(
+            Z, function_.ParameterNameAt(opt_param_position[i]));
+        ASSERT(param_name.IsSymbol());
+        copy_args_prologue += Constant(param_name);
+
+        // Compare the two names: Note that the ArgumentDescriptor array always
+        // terminates with a "null" name (i.e. kNullCid), which will prevent us
+        // from running out-of-bounds.
+        TargetEntryInstr *supplied, *missing;
+        copy_args_prologue += BranchIfStrictEqual(&supplied, &missing);
+
+        // Join good/not_good.
+        JoinEntryInstr* join = BuildJoinEntry();
+
+        // Put good in the flowgraph as a separate basic block.
+        good.Prepend(supplied);
+        good += Goto(join);
+
+        // We had no match. If the param is required, throw a NoSuchMethod
+        // error. Otherwise just load the default constant.
+        Fragment not_good(missing);
+        if (required) {
+          ASSERT(nsm != nullptr);
+          not_good += Goto(nsm);
+        } else {
+          not_good += Constant(DefaultParameterValueAt(opt_param_position[i] -
+                                                       num_fixed_params));
+
+          // Copy down with default value.
+          not_good += StoreLocalRaw(TokenPosition::kNoSource,
+                                    ParameterVariable(opt_param_position[i]));
+          not_good += Drop();
+          not_good += Goto(join);
+        }
+
+        copy_args_prologue.current = join;
       }
 
-      copy_args_prologue.current = join;
       copy_args_prologue += Drop();  // tuple_diff
     }
 
-    // If there are more arguments from the caller we haven't processed, go
-    // NSM.
-    TargetEntryInstr *done, *unknown_named_arg_passed;
-    copy_args_prologue += LoadLocal(optional_count_var);
-    copy_args_prologue += LoadLocal(optional_count_vars_processed);
-    copy_args_prologue += BranchIfEqual(&done, &unknown_named_arg_passed);
-    copy_args_prologue.current = done;
+    if (check_arguments_shape) {
+      // Check for unprocessed arguments and throw NSM if there are any.
+      TargetEntryInstr *done, *unknown_named_arg_passed;
+      copy_args_prologue += LoadLocal(optional_count_var);
+      copy_args_prologue += LoadLocal(optional_count_vars_processed);
+      copy_args_prologue += BranchIfEqual(&done, &unknown_named_arg_passed);
+      copy_args_prologue.current = done;
 
-    {
-      Fragment f(unknown_named_arg_passed);
-      f += Goto(nsm);
+      {
+        Fragment f(unknown_named_arg_passed);
+        f += Goto(nsm);
+      }
     }
   }
 
@@ -466,6 +498,12 @@
 }
 
 Fragment PrologueBuilder::BuildTypeArgumentsHandling(JoinEntryInstr* nsm) {
+  // We only need to check the shape of the arguments (correct parameter count
+  // and correct names/provided required arguments) when the function can be
+  // invoked dynamically. The caller only provides a non-nullptr nsm block if
+  // dynamic invocation is possible.
+  const bool check_argument_shapes = nsm != nullptr;
+
   LocalVariable* type_args_var = parsed_function_->RawTypeArgumentsVariable();
   ASSERT(type_args_var != nullptr);
 
@@ -488,7 +526,9 @@
 
   handling += TestTypeArgsLen(store_null, store_type_args, 0);
 
-  if (parsed_function_->function().IsClosureFunction()) {
+  const auto& function = parsed_function_->function();
+  if (function.IsClosureFunction() ||
+      function.IsDynamicClosureCallDispatcher(thread_)) {
     LocalVariable* closure = parsed_function_->ParameterVariable(0);
 
     // Currently, delayed type arguments can only be introduced through type
@@ -504,7 +544,12 @@
 
     handling += TestDelayedTypeArgs(
         closure,
-        /*present=*/TestTypeArgsLen(use_delayed_type_args, Goto(nsm), 0),
+        /*present=*/
+        // No need to check the type arguments length if this function cannot
+        // be invoked dynamically, and thus we are not checking argument shapes.
+        check_argument_shapes
+            ? TestTypeArgsLen(use_delayed_type_args, Goto(nsm), 0)
+            : use_delayed_type_args,
         /*absent=*/Fragment());
   }
 
diff --git a/runtime/vm/compiler/frontend/prologue_builder.h b/runtime/vm/compiler/frontend/prologue_builder.h
index cef094c..74b93fb 100644
--- a/runtime/vm/compiler/frontend/prologue_builder.h
+++ b/runtime/vm/compiler/frontend/prologue_builder.h
@@ -47,7 +47,8 @@
         is_inlining_(is_inlining) {}
 
   BlockEntryInstr* BuildPrologue(BlockEntryInstr* entry,
-                                 PrologueInfo* prologue_info);
+                                 PrologueInfo* prologue_info,
+                                 JoinEntryInstr* nsm = nullptr);
 
   Fragment BuildOptionalParameterHandling(JoinEntryInstr* nsm,
                                           LocalVariable* temp_var);
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 72d7ead..b91b32a 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -30,7 +30,12 @@
   //
   // Though for some kinds of methods (e.g. ffi trampolines called from native
   // code) we do have to perform type checks for all parameters.
-  return !method.CanReceiveDynamicInvocation();
+  //
+  // TODO(dartbug.com/40813): Remove the closure case when argument checks have
+  // been fully moved out of closures.
+  return !method.CanReceiveDynamicInvocation() &&
+         !(method.IsClosureFunction() &&
+           Function::ClosureBodiesContainNonCovariantChecks());
 }
 
 ScopeBuilder::ScopeBuilder(ParsedFunction* parsed_function)
@@ -118,10 +123,6 @@
     scope_->AddVariable(parsed_function_->arg_desc_var());
   }
 
-  if (parsed_function_->function().IsFfiTrampoline()) {
-    needs_expr_temp_ = true;
-  }
-
   LocalVariable* context_var = parsed_function_->current_context_var();
   context_var->set_is_forced_stack();
   scope_->AddVariable(context_var);
@@ -136,8 +137,20 @@
           function.kernel_offset());
 
   switch (function.kind()) {
+    case FunctionLayout::kImplicitClosureFunction: {
+      const auto& parent = Function::Handle(Z, function.parent_function());
+      const auto& target =
+          Function::Handle(Z, function.ImplicitClosureTarget(Z));
+
+      // For BuildGraphOfNoSuchMethodForwarder, since closures no longer
+      // require arg_desc_var in all cases.
+      if (target.IsNull() ||
+          (parent.num_fixed_parameters() != target.num_fixed_parameters())) {
+        needs_expr_temp_ = true;
+      }
+      FALL_THROUGH;
+    }
     case FunctionLayout::kClosureFunction:
-    case FunctionLayout::kImplicitClosureFunction:
     case FunctionLayout::kRegularFunction:
     case FunctionLayout::kGetterFunction:
     case FunctionLayout::kSetterFunction:
@@ -405,21 +418,10 @@
       parsed_function_->set_receiver_var(variable);
       break;
     }
-    case FunctionLayout::kNoSuchMethodDispatcher:
-    case FunctionLayout::kInvokeFieldDispatcher:
     case FunctionLayout::kFfiTrampoline: {
-      for (intptr_t i = 0; i < function.NumParameters(); ++i) {
-        LocalVariable* variable = MakeVariable(
-            TokenPosition::kNoSource, TokenPosition::kNoSource,
-            String::ZoneHandle(Z, function.ParameterNameAt(i)),
-            AbstractType::ZoneHandle(Z, function.IsFfiTrampoline()
-                                            ? function.ParameterTypeAt(i)
-                                            : Object::dynamic_type().raw()));
-        scope_->InsertParameterAt(i, variable);
-      }
+      needs_expr_temp_ = true;
       // Callbacks and calls with handles need try/catch variables.
-      if (function.IsFfiTrampoline() &&
-          (function.FfiCallbackTarget() != Function::null() ||
+      if ((function.FfiCallbackTarget() != Function::null() ||
            function.FfiCSignatureContainsHandles())) {
         current_function_async_marker_ = FunctionNodeHelper::kSync;
         ++depth_.try_;
@@ -430,6 +432,29 @@
         FinalizeCatchVariables();
         --depth_.catch_;
       }
+      FALL_THROUGH;
+    }
+    case FunctionLayout::kInvokeFieldDispatcher: {
+      if (function.IsDynamicClosureCallDispatcher()) {
+        auto const vars = parsed_function_->EnsureDynamicClosureCallVars();
+        ASSERT(vars != nullptr);
+#define ADD_VAR(Name, _, __) scope_->AddVariable(vars->Name);
+        FOR_EACH_DYNAMIC_CLOSURE_CALL_VARIABLE(ADD_VAR);
+#undef ADD_VAR
+        needs_expr_temp_ = true;
+      }
+      FALL_THROUGH;
+    }
+    case FunctionLayout::kNoSuchMethodDispatcher: {
+      for (intptr_t i = 0; i < function.NumParameters(); ++i) {
+        LocalVariable* variable = MakeVariable(
+            TokenPosition::kNoSource, TokenPosition::kNoSource,
+            String::ZoneHandle(Z, function.ParameterNameAt(i)),
+            AbstractType::ZoneHandle(Z, function.IsFfiTrampoline()
+                                            ? function.ParameterTypeAt(i)
+                                            : Object::dynamic_type().raw()));
+        scope_->InsertParameterAt(i, variable);
+      }
       break;
     }
     case FunctionLayout::kSignatureFunction:
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index 1a028a0..572f0a0 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -268,20 +268,19 @@
 #if defined(TARGET_ARCH_IS_32_BIT)
 typedef int32_t word;
 typedef uint32_t uword;
-static constexpr int kWordSize = 4;
 static constexpr int kWordSizeLog2 = 2;
 #elif defined(TARGET_ARCH_IS_64_BIT)
 typedef int64_t word;
 typedef uint64_t uword;
-static constexpr int kWordSize = 8;
 static constexpr int kWordSizeLog2 = 3;
 #else
 #error "Unsupported architecture"
 #endif
+static constexpr int kWordSize = 1 << kWordSizeLog2;
+static_assert(kWordSize == sizeof(word), "kWordSize should match sizeof(word)");
 
-static constexpr word kBitsPerWord = 8 * kWordSize;
-static_assert((1 << kWordSizeLog2) == kWordSize,
-              "kWordSizeLog2 should match kWordSize");
+static constexpr word kBitsPerWordLog2 = kWordSizeLog2 + kBitsPerByteLog2;
+static constexpr word kBitsPerWord = 1 << kBitsPerWordLog2;
 
 using ObjectAlignment = dart::ObjectAlignment<kWordSize, kWordSizeLog2>;
 
@@ -289,6 +288,7 @@
 constexpr word kWordMin = -(static_cast<uword>(1) << (kBitsPerWord - 1));
 constexpr uword kUwordMax = static_cast<word>(-1);
 
+// The number of bits in the _magnitude_ of a Smi, not counting the sign bit.
 constexpr int kSmiBits = kBitsPerWord - 2;
 constexpr word kSmiMax = (static_cast<uword>(1) << kSmiBits) - 1;
 constexpr word kSmiMin = -(static_cast<uword>(1) << kSmiBits);
@@ -299,9 +299,19 @@
 extern const word kOldPageMask;
 
 static constexpr intptr_t kObjectAlignment = ObjectAlignment::kObjectAlignment;
-static constexpr intptr_t kNumParameterFlagsPerElement = kBitsPerWord / 2;
+// Parameter flags are stored in Smis. In particular, there is one flag (the
+// required flag), but we want ensure that the number of bits stored per Smi is
+// a power of two so we can simply uses shift to convert the parameter index to
+// calculate both the parameter flag index in the parameter names array to get
+// the packed flags and which bit in the packed flags to check.
+static constexpr intptr_t kNumParameterFlagsPerElementLog2 =
+    kBitsPerWordLog2 - 1;
+static constexpr intptr_t kNumParameterFlagsPerElement =
+    1 << kNumParameterFlagsPerElementLog2;
+// Thus, in the untagged Smi value, only the lowest kNumParameterFlagsPerElement
+// bits are used for flags, with the other bits currently unused.
 static_assert(kNumParameterFlagsPerElement <= kSmiBits,
-              "kNumParameterFlagsPerElement should fit inside a Smi");
+              "kNumParameterFlagsPerElement should fit in a Smi");
 
 inline intptr_t RoundedAllocationSize(intptr_t size) {
   return Utils::RoundUp(size, kObjectAlignment);
@@ -466,6 +476,10 @@
  public:
   static word code_offset();
   static word entry_point_offset(CodeEntryKind kind = CodeEntryKind::kNormal);
+  static word packed_fields_offset();
+  static word parameter_names_offset();
+  static word parameter_types_offset();
+  static word type_parameters_offset();
   static word usage_counter_offset();
   static word InstanceSize();
   static word NextFieldOffset();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index d222e0f..63f65ca 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -122,6 +122,14 @@
 static constexpr dart::compiler::target::word Function_code_offset = 44;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
+static constexpr dart::compiler::target::word Function_packed_fields_offset =
+    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;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -198,9 +206,9 @@
 static constexpr dart::compiler::target::word
     Thread_AllocateArray_entry_point_offset = 376;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    716;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     720;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    724;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
@@ -225,7 +233,7 @@
     Thread_allocate_object_slow_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 200;
-static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 752;
+static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 756;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     96;
 static constexpr dart::compiler::target::word
@@ -238,7 +246,7 @@
     Thread_call_to_runtime_entry_point_offset = 272;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 148;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 760;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 764;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 48;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -256,7 +264,7 @@
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 252;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    736;
+    740;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 256;
 static constexpr dart::compiler::target::word
@@ -276,7 +284,7 @@
 static constexpr dart::compiler::target::word
     Thread_float_zerow_address_offset = 372;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    724;
+    728;
 static constexpr dart::compiler::target::word
     Thread_interpret_call_entry_point_offset = 340;
 static constexpr dart::compiler::target::word
@@ -284,7 +292,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 140;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    748;
+    752;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     68;
@@ -323,11 +331,11 @@
 static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
 static constexpr dart::compiler::target::word
     Thread_predefined_symbols_address_offset = 344;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 728;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 732;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 732;
+    Thread_saved_shadow_call_stack_offset = 736;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    740;
+    744;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 244;
 static constexpr dart::compiler::target::word
@@ -360,7 +368,7 @@
     Thread_write_barrier_entry_point_offset = 264;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     40;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 744;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 748;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -402,7 +410,7 @@
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        684, 688, 692, 696, 700, -1, 704, -1, 708, 712, -1, -1, -1, -1, -1, -1};
+        688, 692, 696, 700, 704, -1, 708, -1, 712, 716, -1, -1, -1, -1, -1, -1};
 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;
@@ -616,6 +624,14 @@
 static constexpr dart::compiler::target::word Function_code_offset = 88;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
+static constexpr dart::compiler::target::word Function_packed_fields_offset =
+    124;
+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;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -693,9 +709,9 @@
 static constexpr dart::compiler::target::word
     Thread_AllocateArray_entry_point_offset = 736;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    1440;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1448;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    1456;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
@@ -721,7 +737,7 @@
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 384;
 static constexpr dart::compiler::target::word Thread_api_top_scope_offset =
-    1512;
+    1520;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     192;
 static constexpr dart::compiler::target::word
@@ -734,7 +750,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 280;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1528;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1536;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -752,7 +768,7 @@
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 488;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    1480;
+    1488;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 496;
 static constexpr dart::compiler::target::word
@@ -772,7 +788,7 @@
 static constexpr dart::compiler::target::word
     Thread_float_zerow_address_offset = 728;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    1456;
+    1464;
 static constexpr dart::compiler::target::word
     Thread_interpret_call_entry_point_offset = 664;
 static constexpr dart::compiler::target::word
@@ -780,7 +796,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 264;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    1504;
+    1512;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     136;
@@ -819,11 +835,11 @@
 static constexpr dart::compiler::target::word Thread_object_null_offset = 208;
 static constexpr dart::compiler::target::word
     Thread_predefined_symbols_address_offset = 672;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1464;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1472;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 1472;
+    Thread_saved_shadow_call_stack_offset = 1480;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    1488;
+    1496;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 472;
 static constexpr dart::compiler::target::word
@@ -857,7 +873,7 @@
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     80;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
-    1496;
+    1504;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -900,8 +916,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1352, 1360, 1368, 1376, -1,   -1,   1384, 1392,
-        1400, 1408, 1416, -1,   1424, 1432, -1,   -1};
+        1360, 1368, 1376, 1384, -1,   -1,   1392, 1400,
+        1408, 1416, 1424, -1,   1432, 1440, -1,   -1};
 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;
@@ -1114,6 +1130,14 @@
 static constexpr dart::compiler::target::word Function_code_offset = 44;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
+static constexpr dart::compiler::target::word Function_packed_fields_offset =
+    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;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -1190,9 +1214,9 @@
 static constexpr dart::compiler::target::word
     Thread_AllocateArray_entry_point_offset = 376;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    684;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     688;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    692;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
@@ -1217,7 +1241,7 @@
     Thread_allocate_object_slow_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 200;
-static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 720;
+static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 724;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     96;
 static constexpr dart::compiler::target::word
@@ -1230,7 +1254,7 @@
     Thread_call_to_runtime_entry_point_offset = 272;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 148;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 728;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 732;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 48;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -1248,7 +1272,7 @@
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 252;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    704;
+    708;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 256;
 static constexpr dart::compiler::target::word
@@ -1268,7 +1292,7 @@
 static constexpr dart::compiler::target::word
     Thread_float_zerow_address_offset = 372;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    692;
+    696;
 static constexpr dart::compiler::target::word
     Thread_interpret_call_entry_point_offset = 340;
 static constexpr dart::compiler::target::word
@@ -1276,7 +1300,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 140;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    716;
+    720;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     68;
@@ -1315,11 +1339,11 @@
 static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
 static constexpr dart::compiler::target::word
     Thread_predefined_symbols_address_offset = 344;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 696;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 700;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 700;
+    Thread_saved_shadow_call_stack_offset = 704;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    708;
+    712;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 244;
 static constexpr dart::compiler::target::word
@@ -1352,7 +1376,7 @@
     Thread_write_barrier_entry_point_offset = 264;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     40;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 712;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 716;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -1605,6 +1629,14 @@
 static constexpr dart::compiler::target::word Function_code_offset = 88;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
+static constexpr dart::compiler::target::word Function_packed_fields_offset =
+    124;
+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;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -1682,9 +1714,9 @@
 static constexpr dart::compiler::target::word
     Thread_AllocateArray_entry_point_offset = 736;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    1512;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1520;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    1528;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
@@ -1710,7 +1742,7 @@
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 384;
 static constexpr dart::compiler::target::word Thread_api_top_scope_offset =
-    1584;
+    1592;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     192;
 static constexpr dart::compiler::target::word
@@ -1723,7 +1755,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 280;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1600;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1608;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -1741,7 +1773,7 @@
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 488;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    1552;
+    1560;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 496;
 static constexpr dart::compiler::target::word
@@ -1761,7 +1793,7 @@
 static constexpr dart::compiler::target::word
     Thread_float_zerow_address_offset = 728;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    1528;
+    1536;
 static constexpr dart::compiler::target::word
     Thread_interpret_call_entry_point_offset = 664;
 static constexpr dart::compiler::target::word
@@ -1769,7 +1801,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 264;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    1576;
+    1584;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     136;
@@ -1808,11 +1840,11 @@
 static constexpr dart::compiler::target::word Thread_object_null_offset = 208;
 static constexpr dart::compiler::target::word
     Thread_predefined_symbols_address_offset = 672;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1536;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1544;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 1544;
+    Thread_saved_shadow_call_stack_offset = 1552;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    1560;
+    1568;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 472;
 static constexpr dart::compiler::target::word
@@ -1846,7 +1878,7 @@
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     80;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
-    1568;
+    1576;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -1889,9 +1921,9 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432,
-        1440, 1448, 1456, 1464, -1,   -1,   -1,   -1,   1472, 1480, -1,
-        -1,   1488, 1496, 1504, -1,   -1,   -1,   -1,   -1,   -1};
+        1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432, 1440,
+        1448, 1456, 1464, 1472, -1,   -1,   -1,   -1,   1480, 1488, -1,
+        -1,   1496, 1504, 1512, -1,   -1,   -1,   -1,   -1,   -1};
 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;
@@ -2104,6 +2136,14 @@
 static constexpr dart::compiler::target::word Function_code_offset = 44;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
+static constexpr dart::compiler::target::word Function_packed_fields_offset =
+    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;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -2179,9 +2219,9 @@
 static constexpr dart::compiler::target::word
     Thread_AllocateArray_entry_point_offset = 376;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    716;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     720;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    724;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
@@ -2206,7 +2246,7 @@
     Thread_allocate_object_slow_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 200;
-static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 752;
+static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 756;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     96;
 static constexpr dart::compiler::target::word
@@ -2219,7 +2259,7 @@
     Thread_call_to_runtime_entry_point_offset = 272;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 148;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 760;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 764;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 48;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -2237,7 +2277,7 @@
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 252;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    736;
+    740;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 256;
 static constexpr dart::compiler::target::word
@@ -2257,7 +2297,7 @@
 static constexpr dart::compiler::target::word
     Thread_float_zerow_address_offset = 372;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    724;
+    728;
 static constexpr dart::compiler::target::word
     Thread_interpret_call_entry_point_offset = 340;
 static constexpr dart::compiler::target::word
@@ -2265,7 +2305,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 140;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    748;
+    752;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     68;
@@ -2304,11 +2344,11 @@
 static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
 static constexpr dart::compiler::target::word
     Thread_predefined_symbols_address_offset = 344;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 728;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 732;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 732;
+    Thread_saved_shadow_call_stack_offset = 736;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    740;
+    744;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 244;
 static constexpr dart::compiler::target::word
@@ -2341,7 +2381,7 @@
     Thread_write_barrier_entry_point_offset = 264;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     40;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 744;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 748;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -2380,7 +2420,7 @@
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        684, 688, 692, 696, 700, -1, 704, -1, 708, 712, -1, -1, -1, -1, -1, -1};
+        688, 692, 696, 700, 704, -1, 708, -1, 712, 716, -1, -1, -1, -1, -1, -1};
 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;
@@ -2592,6 +2632,14 @@
 static constexpr dart::compiler::target::word Function_code_offset = 88;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
+static constexpr dart::compiler::target::word Function_packed_fields_offset =
+    124;
+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;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -2668,9 +2716,9 @@
 static constexpr dart::compiler::target::word
     Thread_AllocateArray_entry_point_offset = 736;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    1440;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1448;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    1456;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
@@ -2696,7 +2744,7 @@
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 384;
 static constexpr dart::compiler::target::word Thread_api_top_scope_offset =
-    1512;
+    1520;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     192;
 static constexpr dart::compiler::target::word
@@ -2709,7 +2757,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 280;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1528;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1536;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -2727,7 +2775,7 @@
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 488;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    1480;
+    1488;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 496;
 static constexpr dart::compiler::target::word
@@ -2747,7 +2795,7 @@
 static constexpr dart::compiler::target::word
     Thread_float_zerow_address_offset = 728;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    1456;
+    1464;
 static constexpr dart::compiler::target::word
     Thread_interpret_call_entry_point_offset = 664;
 static constexpr dart::compiler::target::word
@@ -2755,7 +2803,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 264;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    1504;
+    1512;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     136;
@@ -2794,11 +2842,11 @@
 static constexpr dart::compiler::target::word Thread_object_null_offset = 208;
 static constexpr dart::compiler::target::word
     Thread_predefined_symbols_address_offset = 672;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1464;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1472;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 1472;
+    Thread_saved_shadow_call_stack_offset = 1480;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    1488;
+    1496;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 472;
 static constexpr dart::compiler::target::word
@@ -2832,7 +2880,7 @@
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     80;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
-    1496;
+    1504;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -2872,8 +2920,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1352, 1360, 1368, 1376, -1,   -1,   1384, 1392,
-        1400, 1408, 1416, -1,   1424, 1432, -1,   -1};
+        1360, 1368, 1376, 1384, -1,   -1,   1392, 1400,
+        1408, 1416, 1424, -1,   1432, 1440, -1,   -1};
 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;
@@ -3084,6 +3132,14 @@
 static constexpr dart::compiler::target::word Function_code_offset = 44;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
+static constexpr dart::compiler::target::word Function_packed_fields_offset =
+    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;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -3159,9 +3215,9 @@
 static constexpr dart::compiler::target::word
     Thread_AllocateArray_entry_point_offset = 376;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    684;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     688;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    692;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
@@ -3186,7 +3242,7 @@
     Thread_allocate_object_slow_entry_point_offset = 292;
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 200;
-static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 720;
+static constexpr dart::compiler::target::word Thread_api_top_scope_offset = 724;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     96;
 static constexpr dart::compiler::target::word
@@ -3199,7 +3255,7 @@
     Thread_call_to_runtime_entry_point_offset = 272;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 148;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 728;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 732;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 48;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -3217,7 +3273,7 @@
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 252;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    704;
+    708;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 256;
 static constexpr dart::compiler::target::word
@@ -3237,7 +3293,7 @@
 static constexpr dart::compiler::target::word
     Thread_float_zerow_address_offset = 372;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    692;
+    696;
 static constexpr dart::compiler::target::word
     Thread_interpret_call_entry_point_offset = 340;
 static constexpr dart::compiler::target::word
@@ -3245,7 +3301,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 140;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    716;
+    720;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     68;
@@ -3284,11 +3340,11 @@
 static constexpr dart::compiler::target::word Thread_object_null_offset = 112;
 static constexpr dart::compiler::target::word
     Thread_predefined_symbols_address_offset = 344;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 696;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 700;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 700;
+    Thread_saved_shadow_call_stack_offset = 704;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    708;
+    712;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 244;
 static constexpr dart::compiler::target::word
@@ -3321,7 +3377,7 @@
     Thread_write_barrier_entry_point_offset = 264;
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     40;
-static constexpr dart::compiler::target::word Thread_callback_code_offset = 712;
+static constexpr dart::compiler::target::word Thread_callback_code_offset = 716;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 12;
 static constexpr dart::compiler::target::word Type_arguments_offset = 16;
@@ -3569,6 +3625,14 @@
 static constexpr dart::compiler::target::word Function_code_offset = 88;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
+static constexpr dart::compiler::target::word Function_packed_fields_offset =
+    124;
+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;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -3645,9 +3709,9 @@
 static constexpr dart::compiler::target::word
     Thread_AllocateArray_entry_point_offset = 736;
 static constexpr dart::compiler::target::word Thread_active_exception_offset =
-    1512;
-static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
     1520;
+static constexpr dart::compiler::target::word Thread_active_stacktrace_offset =
+    1528;
 static constexpr dart::compiler::target::word
     Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
@@ -3673,7 +3737,7 @@
 static constexpr dart::compiler::target::word
     Thread_allocate_object_slow_stub_offset = 384;
 static constexpr dart::compiler::target::word Thread_api_top_scope_offset =
-    1584;
+    1592;
 static constexpr dart::compiler::target::word Thread_async_stack_trace_offset =
     192;
 static constexpr dart::compiler::target::word
@@ -3686,7 +3750,7 @@
     Thread_call_to_runtime_entry_point_offset = 528;
 static constexpr dart::compiler::target::word
     Thread_call_to_runtime_stub_offset = 280;
-static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1600;
+static constexpr dart::compiler::target::word Thread_dart_stream_offset = 1608;
 static constexpr dart::compiler::target::word
     Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word Thread_optimize_entry_offset =
@@ -3704,7 +3768,7 @@
 static constexpr dart::compiler::target::word
     Thread_enter_safepoint_stub_offset = 488;
 static constexpr dart::compiler::target::word Thread_execution_state_offset =
-    1552;
+    1560;
 static constexpr dart::compiler::target::word
     Thread_exit_safepoint_stub_offset = 496;
 static constexpr dart::compiler::target::word
@@ -3724,7 +3788,7 @@
 static constexpr dart::compiler::target::word
     Thread_float_zerow_address_offset = 728;
 static constexpr dart::compiler::target::word Thread_global_object_pool_offset =
-    1528;
+    1536;
 static constexpr dart::compiler::target::word
     Thread_interpret_call_entry_point_offset = 664;
 static constexpr dart::compiler::target::word
@@ -3732,7 +3796,7 @@
 static constexpr dart::compiler::target::word
     Thread_invoke_dart_code_stub_offset = 264;
 static constexpr dart::compiler::target::word Thread_exit_through_ffi_offset =
-    1576;
+    1584;
 static constexpr dart::compiler::target::word Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word Thread_field_table_values_offset =
     136;
@@ -3771,11 +3835,11 @@
 static constexpr dart::compiler::target::word Thread_object_null_offset = 208;
 static constexpr dart::compiler::target::word
     Thread_predefined_symbols_address_offset = 672;
-static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1536;
+static constexpr dart::compiler::target::word Thread_resume_pc_offset = 1544;
 static constexpr dart::compiler::target::word
-    Thread_saved_shadow_call_stack_offset = 1544;
+    Thread_saved_shadow_call_stack_offset = 1552;
 static constexpr dart::compiler::target::word Thread_safepoint_state_offset =
-    1560;
+    1568;
 static constexpr dart::compiler::target::word
     Thread_slow_type_test_stub_offset = 472;
 static constexpr dart::compiler::target::word
@@ -3809,7 +3873,7 @@
 static constexpr dart::compiler::target::word Thread_write_barrier_mask_offset =
     80;
 static constexpr dart::compiler::target::word Thread_callback_code_offset =
-    1568;
+    1576;
 static constexpr dart::compiler::target::word TimelineStream_enabled_offset =
     16;
 static constexpr dart::compiler::target::word TwoByteString_data_offset = 16;
@@ -3849,9 +3913,9 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     Thread_write_barrier_wrappers_thread_offset[] = {
-        1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432,
-        1440, 1448, 1456, 1464, -1,   -1,   -1,   -1,   1472, 1480, -1,
-        -1,   1488, 1496, 1504, -1,   -1,   -1,   -1,   -1,   -1};
+        1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432, 1440,
+        1448, 1456, 1464, 1472, -1,   -1,   -1,   -1,   1480, 1488, -1,
+        -1,   1496, 1504, 1512, -1,   -1,   -1,   -1,   -1,   -1};
 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;
@@ -4070,6 +4134,14 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
 static constexpr dart::compiler::target::word
+    AOT_Function_packed_fields_offset = 52;
+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;
+static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_data_offset = 12;
@@ -4162,9 +4234,9 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_AllocateArray_entry_point_offset = 376;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 716;
+    AOT_Thread_active_exception_offset = 720;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 720;
+    AOT_Thread_active_stacktrace_offset = 724;
 static constexpr dart::compiler::target::word
     AOT_Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
@@ -4190,7 +4262,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 200;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    752;
+    756;
 static constexpr dart::compiler::target::word
     AOT_Thread_async_stack_trace_offset = 96;
 static constexpr dart::compiler::target::word
@@ -4205,7 +4277,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 148;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    760;
+    764;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 48;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -4224,7 +4296,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_enter_safepoint_stub_offset = 252;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 736;
+    AOT_Thread_execution_state_offset = 740;
 static constexpr dart::compiler::target::word
     AOT_Thread_exit_safepoint_stub_offset = 256;
 static constexpr dart::compiler::target::word
@@ -4244,7 +4316,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_float_zerow_address_offset = 372;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 724;
+    AOT_Thread_global_object_pool_offset = 728;
 static constexpr dart::compiler::target::word
     AOT_Thread_interpret_call_entry_point_offset = 340;
 static constexpr dart::compiler::target::word
@@ -4252,7 +4324,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 140;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 748;
+    AOT_Thread_exit_through_ffi_offset = 752;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 68;
@@ -4292,11 +4364,11 @@
     112;
 static constexpr dart::compiler::target::word
     AOT_Thread_predefined_symbols_address_offset = 344;
-static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 728;
+static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 732;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 732;
+    AOT_Thread_saved_shadow_call_stack_offset = 736;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 740;
+    AOT_Thread_safepoint_state_offset = 744;
 static constexpr dart::compiler::target::word
     AOT_Thread_slow_type_test_stub_offset = 244;
 static constexpr dart::compiler::target::word
@@ -4332,7 +4404,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_mask_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    744;
+    748;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -4381,7 +4453,7 @@
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        684, 688, 692, 696, 700, -1, 704, -1, 708, 712, -1, -1, -1, -1, -1, -1};
+        688, 692, 696, 700, 704, -1, 708, -1, 712, 716, -1, -1, -1, -1, -1, -1};
 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;
@@ -4616,6 +4688,14 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word
+    AOT_Function_packed_fields_offset = 100;
+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;
+static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_data_offset = 24;
@@ -4708,9 +4788,9 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_AllocateArray_entry_point_offset = 736;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 1440;
+    AOT_Thread_active_exception_offset = 1448;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 1448;
+    AOT_Thread_active_stacktrace_offset = 1456;
 static constexpr dart::compiler::target::word
     AOT_Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
@@ -4736,7 +4816,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 384;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    1512;
+    1520;
 static constexpr dart::compiler::target::word
     AOT_Thread_async_stack_trace_offset = 192;
 static constexpr dart::compiler::target::word
@@ -4751,7 +4831,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1528;
+    1536;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -4770,7 +4850,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_enter_safepoint_stub_offset = 488;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 1480;
+    AOT_Thread_execution_state_offset = 1488;
 static constexpr dart::compiler::target::word
     AOT_Thread_exit_safepoint_stub_offset = 496;
 static constexpr dart::compiler::target::word
@@ -4790,7 +4870,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_float_zerow_address_offset = 728;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 1456;
+    AOT_Thread_global_object_pool_offset = 1464;
 static constexpr dart::compiler::target::word
     AOT_Thread_interpret_call_entry_point_offset = 664;
 static constexpr dart::compiler::target::word
@@ -4798,7 +4878,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 264;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 1504;
+    AOT_Thread_exit_through_ffi_offset = 1512;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 136;
@@ -4839,11 +4919,11 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_predefined_symbols_address_offset = 672;
 static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset =
-    1464;
+    1472;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 1472;
+    AOT_Thread_saved_shadow_call_stack_offset = 1480;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 1488;
+    AOT_Thread_safepoint_state_offset = 1496;
 static constexpr dart::compiler::target::word
     AOT_Thread_slow_type_test_stub_offset = 472;
 static constexpr dart::compiler::target::word
@@ -4879,7 +4959,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_mask_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    1496;
+    1504;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -4928,8 +5008,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        1352, 1360, 1368, 1376, -1,   -1,   1384, 1392,
-        1400, 1408, 1416, -1,   1424, 1432, -1,   -1};
+        1360, 1368, 1376, 1384, -1,   -1,   1392, 1400,
+        1408, 1416, 1424, -1,   1432, 1440, -1,   -1};
 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;
@@ -5168,6 +5248,14 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word
+    AOT_Function_packed_fields_offset = 100;
+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;
+static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_data_offset = 24;
@@ -5260,9 +5348,9 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_AllocateArray_entry_point_offset = 736;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 1512;
+    AOT_Thread_active_exception_offset = 1520;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 1520;
+    AOT_Thread_active_stacktrace_offset = 1528;
 static constexpr dart::compiler::target::word
     AOT_Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
@@ -5288,7 +5376,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 384;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    1584;
+    1592;
 static constexpr dart::compiler::target::word
     AOT_Thread_async_stack_trace_offset = 192;
 static constexpr dart::compiler::target::word
@@ -5303,7 +5391,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1600;
+    1608;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -5322,7 +5410,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_enter_safepoint_stub_offset = 488;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 1552;
+    AOT_Thread_execution_state_offset = 1560;
 static constexpr dart::compiler::target::word
     AOT_Thread_exit_safepoint_stub_offset = 496;
 static constexpr dart::compiler::target::word
@@ -5342,7 +5430,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_float_zerow_address_offset = 728;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 1528;
+    AOT_Thread_global_object_pool_offset = 1536;
 static constexpr dart::compiler::target::word
     AOT_Thread_interpret_call_entry_point_offset = 664;
 static constexpr dart::compiler::target::word
@@ -5350,7 +5438,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 264;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 1576;
+    AOT_Thread_exit_through_ffi_offset = 1584;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 136;
@@ -5391,11 +5479,11 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_predefined_symbols_address_offset = 672;
 static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset =
-    1536;
+    1544;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 1544;
+    AOT_Thread_saved_shadow_call_stack_offset = 1552;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 1560;
+    AOT_Thread_safepoint_state_offset = 1568;
 static constexpr dart::compiler::target::word
     AOT_Thread_slow_type_test_stub_offset = 472;
 static constexpr dart::compiler::target::word
@@ -5431,7 +5519,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_mask_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    1568;
+    1576;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -5480,9 +5568,9 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432,
-        1440, 1448, 1456, 1464, -1,   -1,   -1,   -1,   1472, 1480, -1,
-        -1,   1488, 1496, 1504, -1,   -1,   -1,   -1,   -1,   -1};
+        1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432, 1440,
+        1448, 1456, 1464, 1472, -1,   -1,   -1,   -1,   1480, 1488, -1,
+        -1,   1496, 1504, 1512, -1,   -1,   -1,   -1,   -1,   -1};
 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;
@@ -5717,6 +5805,14 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
 static constexpr dart::compiler::target::word
+    AOT_Function_packed_fields_offset = 52;
+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;
+static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_data_offset = 12;
@@ -5807,9 +5903,9 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_AllocateArray_entry_point_offset = 376;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 716;
+    AOT_Thread_active_exception_offset = 720;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 720;
+    AOT_Thread_active_stacktrace_offset = 724;
 static constexpr dart::compiler::target::word
     AOT_Thread_array_write_barrier_code_offset = 128;
 static constexpr dart::compiler::target::word
@@ -5835,7 +5931,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 200;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    752;
+    756;
 static constexpr dart::compiler::target::word
     AOT_Thread_async_stack_trace_offset = 96;
 static constexpr dart::compiler::target::word
@@ -5850,7 +5946,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 148;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    760;
+    764;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 48;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -5869,7 +5965,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_enter_safepoint_stub_offset = 252;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 736;
+    AOT_Thread_execution_state_offset = 740;
 static constexpr dart::compiler::target::word
     AOT_Thread_exit_safepoint_stub_offset = 256;
 static constexpr dart::compiler::target::word
@@ -5889,7 +5985,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_float_zerow_address_offset = 372;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 724;
+    AOT_Thread_global_object_pool_offset = 728;
 static constexpr dart::compiler::target::word
     AOT_Thread_interpret_call_entry_point_offset = 340;
 static constexpr dart::compiler::target::word
@@ -5897,7 +5993,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 140;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 748;
+    AOT_Thread_exit_through_ffi_offset = 752;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 68;
@@ -5937,11 +6033,11 @@
     112;
 static constexpr dart::compiler::target::word
     AOT_Thread_predefined_symbols_address_offset = 344;
-static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 728;
+static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset = 732;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 732;
+    AOT_Thread_saved_shadow_call_stack_offset = 736;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 740;
+    AOT_Thread_safepoint_state_offset = 744;
 static constexpr dart::compiler::target::word
     AOT_Thread_slow_type_test_stub_offset = 244;
 static constexpr dart::compiler::target::word
@@ -5977,7 +6073,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_mask_offset = 40;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    744;
+    748;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 8;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -6023,7 +6119,7 @@
     4, 12, 8, 16};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        684, 688, 692, 696, 700, -1, 704, -1, 708, 712, -1, -1, -1, -1, -1, -1};
+        688, 692, 696, 700, 704, -1, 708, -1, 712, 716, -1, -1, -1, -1, -1, -1};
 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;
@@ -6256,6 +6352,14 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word
+    AOT_Function_packed_fields_offset = 100;
+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;
+static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_data_offset = 24;
@@ -6346,9 +6450,9 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_AllocateArray_entry_point_offset = 736;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 1440;
+    AOT_Thread_active_exception_offset = 1448;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 1448;
+    AOT_Thread_active_stacktrace_offset = 1456;
 static constexpr dart::compiler::target::word
     AOT_Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
@@ -6374,7 +6478,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 384;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    1512;
+    1520;
 static constexpr dart::compiler::target::word
     AOT_Thread_async_stack_trace_offset = 192;
 static constexpr dart::compiler::target::word
@@ -6389,7 +6493,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1528;
+    1536;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -6408,7 +6512,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_enter_safepoint_stub_offset = 488;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 1480;
+    AOT_Thread_execution_state_offset = 1488;
 static constexpr dart::compiler::target::word
     AOT_Thread_exit_safepoint_stub_offset = 496;
 static constexpr dart::compiler::target::word
@@ -6428,7 +6532,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_float_zerow_address_offset = 728;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 1456;
+    AOT_Thread_global_object_pool_offset = 1464;
 static constexpr dart::compiler::target::word
     AOT_Thread_interpret_call_entry_point_offset = 664;
 static constexpr dart::compiler::target::word
@@ -6436,7 +6540,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 264;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 1504;
+    AOT_Thread_exit_through_ffi_offset = 1512;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 136;
@@ -6477,11 +6581,11 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_predefined_symbols_address_offset = 672;
 static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset =
-    1464;
+    1472;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 1472;
+    AOT_Thread_saved_shadow_call_stack_offset = 1480;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 1488;
+    AOT_Thread_safepoint_state_offset = 1496;
 static constexpr dart::compiler::target::word
     AOT_Thread_slow_type_test_stub_offset = 472;
 static constexpr dart::compiler::target::word
@@ -6517,7 +6621,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_mask_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    1496;
+    1504;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -6563,8 +6667,8 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        1352, 1360, 1368, 1376, -1,   -1,   1384, 1392,
-        1400, 1408, 1416, -1,   1424, 1432, -1,   -1};
+        1360, 1368, 1376, 1384, -1,   -1,   1392, 1400,
+        1408, 1416, 1424, -1,   1432, 1440, -1,   -1};
 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;
@@ -6801,6 +6905,14 @@
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
 static constexpr dart::compiler::target::word
+    AOT_Function_packed_fields_offset = 100;
+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;
+static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
     AOT_GrowableObjectArray_data_offset = 24;
@@ -6891,9 +7003,9 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_AllocateArray_entry_point_offset = 736;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_exception_offset = 1512;
+    AOT_Thread_active_exception_offset = 1520;
 static constexpr dart::compiler::target::word
-    AOT_Thread_active_stacktrace_offset = 1520;
+    AOT_Thread_active_stacktrace_offset = 1528;
 static constexpr dart::compiler::target::word
     AOT_Thread_array_write_barrier_code_offset = 240;
 static constexpr dart::compiler::target::word
@@ -6919,7 +7031,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_allocate_object_slow_stub_offset = 384;
 static constexpr dart::compiler::target::word AOT_Thread_api_top_scope_offset =
-    1584;
+    1592;
 static constexpr dart::compiler::target::word
     AOT_Thread_async_stack_trace_offset = 192;
 static constexpr dart::compiler::target::word
@@ -6934,7 +7046,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_call_to_runtime_stub_offset = 280;
 static constexpr dart::compiler::target::word AOT_Thread_dart_stream_offset =
-    1600;
+    1608;
 static constexpr dart::compiler::target::word
     AOT_Thread_dispatch_table_array_offset = 96;
 static constexpr dart::compiler::target::word AOT_Thread_optimize_entry_offset =
@@ -6953,7 +7065,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_enter_safepoint_stub_offset = 488;
 static constexpr dart::compiler::target::word
-    AOT_Thread_execution_state_offset = 1552;
+    AOT_Thread_execution_state_offset = 1560;
 static constexpr dart::compiler::target::word
     AOT_Thread_exit_safepoint_stub_offset = 496;
 static constexpr dart::compiler::target::word
@@ -6973,7 +7085,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_float_zerow_address_offset = 728;
 static constexpr dart::compiler::target::word
-    AOT_Thread_global_object_pool_offset = 1528;
+    AOT_Thread_global_object_pool_offset = 1536;
 static constexpr dart::compiler::target::word
     AOT_Thread_interpret_call_entry_point_offset = 664;
 static constexpr dart::compiler::target::word
@@ -6981,7 +7093,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_invoke_dart_code_stub_offset = 264;
 static constexpr dart::compiler::target::word
-    AOT_Thread_exit_through_ffi_offset = 1576;
+    AOT_Thread_exit_through_ffi_offset = 1584;
 static constexpr dart::compiler::target::word AOT_Thread_isolate_offset = 88;
 static constexpr dart::compiler::target::word
     AOT_Thread_field_table_values_offset = 136;
@@ -7022,11 +7134,11 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_predefined_symbols_address_offset = 672;
 static constexpr dart::compiler::target::word AOT_Thread_resume_pc_offset =
-    1536;
+    1544;
 static constexpr dart::compiler::target::word
-    AOT_Thread_saved_shadow_call_stack_offset = 1544;
+    AOT_Thread_saved_shadow_call_stack_offset = 1552;
 static constexpr dart::compiler::target::word
-    AOT_Thread_safepoint_state_offset = 1560;
+    AOT_Thread_safepoint_state_offset = 1568;
 static constexpr dart::compiler::target::word
     AOT_Thread_slow_type_test_stub_offset = 472;
 static constexpr dart::compiler::target::word
@@ -7062,7 +7174,7 @@
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_mask_offset = 80;
 static constexpr dart::compiler::target::word AOT_Thread_callback_code_offset =
-    1568;
+    1576;
 static constexpr dart::compiler::target::word
     AOT_TimelineStream_enabled_offset = 16;
 static constexpr dart::compiler::target::word AOT_TwoByteString_data_offset =
@@ -7108,9 +7220,9 @@
     8, 24, 16, 32};
 static constexpr dart::compiler::target::word
     AOT_Thread_write_barrier_wrappers_thread_offset[] = {
-        1352, 1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432,
-        1440, 1448, 1456, 1464, -1,   -1,   -1,   -1,   1472, 1480, -1,
-        -1,   1488, 1496, 1504, -1,   -1,   -1,   -1,   -1,   -1};
+        1360, 1368, 1376, 1384, 1392, 1400, 1408, 1416, 1424, 1432, 1440,
+        1448, 1456, 1464, 1472, -1,   -1,   -1,   -1,   1480, 1488, -1,
+        -1,   1496, 1504, 1512, -1,   -1,   -1,   -1,   -1,   -1};
 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;
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 67b3283..b477334 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -94,6 +94,10 @@
   FIELD(Function, code_offset)                                                 \
   RANGE(Function, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal,   \
         CodeEntryKind::kUnchecked, [](CodeEntryKind value) { return true; })   \
+  FIELD(Function, packed_fields_offset)                                        \
+  FIELD(Function, parameter_names_offset)                                      \
+  FIELD(Function, parameter_types_offset)                                      \
+  FIELD(Function, type_parameters_offset)                                      \
   FIELD(FutureOr, type_arguments_offset)                                       \
   FIELD(GrowableObjectArray, data_offset)                                      \
   FIELD(GrowableObjectArray, length_offset)                                    \
diff --git a/runtime/vm/compiler/write_barrier_elimination.cc b/runtime/vm/compiler/write_barrier_elimination.cc
index 9ffa022..4d1e453 100644
--- a/runtime/vm/compiler/write_barrier_elimination.cc
+++ b/runtime/vm/compiler/write_barrier_elimination.cc
@@ -335,7 +335,8 @@
            std::is_base_of<ContextLayout, underlying_type>::value ||           \
            std::is_base_of<UnhandledExceptionLayout, underlying_type>::value;
 
-      NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT)
+      BOXED_NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT)
+      UNBOXED_NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT)
 #undef FOR_EACH_NATIVE_SLOT
 
     default:
diff --git a/runtime/vm/interpreter.cc b/runtime/vm/interpreter.cc
index 5b16c67c..97b58f5 100644
--- a/runtime/vm/interpreter.cc
+++ b/runtime/vm/interpreter.cc
@@ -1712,6 +1712,7 @@
     const intptr_t arg_count = InterpreterHelpers::ArgDescArgCount(argdesc_);
     const intptr_t pos_count = InterpreterHelpers::ArgDescPosCount(argdesc_);
     if ((arg_count != num_fixed_params) || (pos_count != num_fixed_params)) {
+      SP[1] = FrameFunction(FP);
       goto NoSuchMethodFromPrologue;
     }
 
@@ -1729,6 +1730,7 @@
     if (CopyParameters(thread, &pc, &FP, &SP, rA, rB, rC)) {
       DISPATCH();
     } else {
+      SP[1] = FrameFunction(FP);
       goto NoSuchMethodFromPrologue;
     }
   }
@@ -1792,6 +1794,7 @@
     const intptr_t type_args_len =
         InterpreterHelpers::ArgDescTypeArgsLen(argdesc_);
     if ((type_args_len != declared_type_args_len) && (type_args_len != 0)) {
+      SP[1] = FrameFunction(FP);
       goto NoSuchMethodFromPrologue;
     }
     if (type_args_len > 0) {
@@ -3451,6 +3454,8 @@
 
     FunctionPtr function = FrameFunction(FP);
     ASSERT(Function::kind(function) == FunctionLayout::kInvokeFieldDispatcher);
+    const bool is_dynamic_call =
+        Function::IsDynamicInvocationForwarderName(function->ptr()->name_);
 
     BUMP_USAGE_COUNTER_ON_ENTRY(function);
 
@@ -3462,9 +3467,31 @@
 
     ClosurePtr receiver =
         Closure::RawCast(FrameArguments(FP, argc)[receiver_idx]);
-    function = receiver->ptr()->function_;
+    SP[1] = receiver->ptr()->function_;
 
-    SP[1] = function;
+    if (is_dynamic_call) {
+      {
+        SP[2] = null_value;
+        SP[3] = receiver;
+        SP[4] = argdesc_;
+        Exit(thread, FP, SP + 5, pc);
+        if (!InvokeRuntime(thread, this, DRT_ClosureArgumentsValid,
+                           NativeArguments(thread, 2, SP + 3, SP + 2))) {
+          HANDLE_EXCEPTION;
+        }
+        receiver = Closure::RawCast(SP[3]);
+        argdesc_ = Array::RawCast(SP[4]);
+      }
+
+      if (SP[2] != Bool::True().raw()) {
+        goto NoSuchMethodFromPrologue;
+      }
+
+      // TODO(dartbug.com/40813): Move other checks that are currently
+      // compiled in the closure body to here as they are also moved to
+      // FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher.
+    }
+
     goto TailCallSP1;
   }
 
@@ -3509,12 +3536,31 @@
 
     // If the field value is a closure, no need to resolve 'call' function.
     if (InterpreterHelpers::GetClassId(receiver) == kClosureCid) {
+      SP[1] = Closure::RawCast(receiver)->ptr()->function_;
+
       if (is_dynamic_call) {
-        // TODO(dartbug.com/40813): Move checks that are currently compiled
-        // in the closure body to here as they are also moved to
+        {
+          SP[2] = null_value;
+          SP[3] = receiver;
+          SP[4] = argdesc_;
+          Exit(thread, FP, SP + 5, pc);
+          if (!InvokeRuntime(thread, this, DRT_ClosureArgumentsValid,
+                             NativeArguments(thread, 2, SP + 3, SP + 2))) {
+            HANDLE_EXCEPTION;
+          }
+          receiver = SP[3];
+          argdesc_ = Array::RawCast(SP[4]);
+        }
+
+        if (SP[2] != Bool::True().raw()) {
+          goto NoSuchMethodFromPrologue;
+        }
+
+        // TODO(dartbug.com/40813): Move other checks that are currently
+        // compiled in the closure body to here as they are also moved to
         // FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher.
       }
-      SP[1] = Closure::RawCast(receiver)->ptr()->function_;
+
       goto TailCallSP1;
     }
 
@@ -3605,6 +3651,7 @@
       rC = KernelBytecode::DecodeC(pc2);
       pc2 = KernelBytecode::Next(pc2);
       if (!CopyParameters(thread, &pc2, &FP, &SP, rA, rB, rC)) {
+        SP[1] = function;
         goto NoSuchMethodFromPrologue;
       }
     }
@@ -3688,6 +3735,7 @@
     BYTECODE(VMInternal_NoSuchMethodDispatcher, 0);
     FunctionPtr function = FrameFunction(FP);
     ASSERT(Function::kind(function) == FunctionLayout::kNoSuchMethodDispatcher);
+    SP[1] = function;
     goto NoSuchMethodFromPrologue;
   }
 
@@ -3766,10 +3814,11 @@
     }
   }
 
-  // Helper used to handle noSuchMethod on closures.
+  // Helper used to handle noSuchMethod on closures. The function should be
+  // placed into SP[1] before jumping here, similar to TailCallSP1.
   {
   NoSuchMethodFromPrologue:
-    FunctionPtr function = FrameFunction(FP);
+    FunctionPtr function = Function::RawCast(SP[1]);
 
     const intptr_t type_args_len =
         InterpreterHelpers::ArgDescTypeArgsLen(argdesc_);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 20c9883..25c9549 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7438,6 +7438,7 @@
 
 intptr_t Function::GetRequiredFlagIndex(intptr_t index,
                                         intptr_t* flag_mask) const {
+  ASSERT(flag_mask != nullptr);
   ASSERT(index >= num_fixed_parameters());
   index -= num_fixed_parameters();
   *flag_mask = 1 << (static_cast<uintptr_t>(index) %
@@ -8036,10 +8037,16 @@
     if (function_type_args.raw() == Object::empty_type_arguments().raw()) {
       // There are no delayed type arguments, so set back to null.
       function_type_args = TypeArguments::null();
+    } else {
+      // We should never end up here when the receiver is a closure with delayed
+      // type arguments unless this dynamically called closure function was
+      // retrieved directly from the closure instead of going through
+      // DartEntry::ResolveCallable, which appropriately checks for this case.
+      ASSERT(args_desc.TypeArgsLen() == 0);
     }
   }
 
-  if (function_type_args.IsNull() && args_desc.TypeArgsLen() > 0) {
+  if (args_desc.TypeArgsLen() > 0) {
     function_type_args ^= args.At(0);
   }
 
@@ -8796,6 +8803,15 @@
 #endif
 }
 
+bool Function::IsDynamicClosureCallDispatcher(Thread* thread) const {
+  if (!IsInvokeFieldDispatcher()) return false;
+  if (thread->isolate()->object_store()->closure_class() != Owner()) {
+    return false;
+  }
+  const auto& handle = String::Handle(thread->zone(), name());
+  return handle.Equals(Symbols::DynamicCall());
+}
+
 FunctionPtr Function::ImplicitClosureFunction() const {
   // Return the existing implicit closure function if any.
   if (implicit_closure_function() != Function::null()) {
@@ -9013,6 +9029,23 @@
                       Object::null_type_arguments(), *this, context);
 }
 
+FunctionPtr Function::ImplicitClosureTarget(Zone* zone) const {
+  const auto& parent = Function::Handle(zone, parent_function());
+  const auto& func_name = String::Handle(zone, parent.name());
+  const auto& owner = Class::Handle(zone, parent.Owner());
+  auto& target = Function::Handle(zone, owner.LookupFunction(func_name));
+
+  if (!target.IsNull() && (target.raw() != parent.raw())) {
+    DEBUG_ASSERT(Isolate::Current()->HasAttemptedReload());
+    if ((target.is_static() != parent.is_static()) ||
+        (target.kind() != parent.kind())) {
+      target = Function::null();
+    }
+  }
+
+  return target.raw();
+}
+
 intptr_t Function::ComputeClosureHash() const {
   ASSERT(IsClosureFunction());
   const Class& cls = Class::Handle(Owner());
@@ -24159,8 +24192,9 @@
 }
 
 intptr_t Closure::NumTypeParameters(Thread* thread) const {
-  if (delayed_type_arguments() != Object::null_type_arguments().raw() &&
-      delayed_type_arguments() != Object::empty_type_arguments().raw()) {
+  // Only check for empty here, as the null TAV is used to mean that the
+  // closed-over delayed type parameters were all of dynamic type.
+  if (delayed_type_arguments() != Object::empty_type_arguments().raw()) {
     return 0;
   } else {
     const auto& closure_function = Function::Handle(thread->zone(), function());
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 28b6ca2..60a78a7 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2595,6 +2595,9 @@
   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_);
+  }
 
   // Parameter names are valid for all valid parameter indices, and are not
   // limited to named optional parameters. If there are parameter flags (eg
@@ -2605,6 +2608,9 @@
   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;
+  static intptr_t parameter_names_offset() {
+    return OFFSET_OF(FunctionLayout, parameter_names_);
+  }
 
   // The required flags are stored at the end of the parameter_names. The flags
   // are packed into SMIs, but omitted if they're 0.
@@ -2626,6 +2632,9 @@
     return raw_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());
@@ -2779,6 +2788,20 @@
     return kind() == FunctionLayout::kInvokeFieldDispatcher;
   }
 
+  bool IsDynamicInvokeFieldDispatcher() const {
+    return IsInvokeFieldDispatcher() &&
+           IsDynamicInvocationForwarderName(name());
+  }
+
+  // Performs all the checks that don't require the current thread first, to
+  // avoid retrieving it unless they all pass. If you have a handle on the
+  // current thread, call the version that takes one instead.
+  bool IsDynamicClosureCallDispatcher() const {
+    if (!IsDynamicInvokeFieldDispatcher()) return false;
+    return IsDynamicClosureCallDispatcher(Thread::Current());
+  }
+  bool IsDynamicClosureCallDispatcher(Thread* thread) const;
+
   bool IsDynamicInvocationForwarder() const {
     return kind() == FunctionLayout::kDynamicInvocationForwarder;
   }
@@ -2807,6 +2830,10 @@
 
   InstancePtr ImplicitInstanceClosure(const Instance& receiver) const;
 
+  // Returns the target of the implicit closure or null if the target is now
+  // invalid (e.g., mismatched argument shapes after a reload).
+  FunctionPtr ImplicitClosureTarget(Zone* zone) const;
+
   intptr_t ComputeClosureHash() const;
 
   // Redirection information for a redirecting factory.
@@ -2849,8 +2876,7 @@
   // Whether this function can receive an invocation where the number and names
   // of arguments have not been checked.
   bool CanReceiveDynamicInvocation() const {
-    return (IsClosureFunction() && ClosureBodiesContainNonCovariantChecks()) ||
-           IsFfiTrampoline();
+    return IsFfiTrampoline() || IsDynamicClosureCallDispatcher();
   }
 
   bool HasThisParameter() const {
@@ -2959,22 +2985,28 @@
 
   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;
+  using PackedNumFixedParameters = FunctionLayout::PackedNumFixedParameters;
+  using PackedNumOptionalParameters =
+      FunctionLayout::PackedNumOptionalParameters;
 
   bool HasOptionalParameters() const {
-    return FunctionLayout::PackedNumOptionalParameters::decode(
-               raw_ptr()->packed_fields_) > 0;
+    return PackedNumOptionalParameters::decode(raw_ptr()->packed_fields_) > 0;
   }
   bool HasOptionalNamedParameters() const {
     return HasOptionalParameters() &&
-           FunctionLayout::PackedHasNamedOptionalParameters::decode(
-               raw_ptr()->packed_fields_);
+           PackedHasNamedOptionalParameters::decode(raw_ptr()->packed_fields_);
   }
   bool HasOptionalPositionalParameters() const {
     return HasOptionalParameters() && !HasOptionalNamedParameters();
   }
   intptr_t NumOptionalParameters() const {
-    return FunctionLayout::PackedNumOptionalParameters::decode(
-        raw_ptr()->packed_fields_);
+    return PackedNumOptionalParameters::decode(raw_ptr()->packed_fields_);
   }
   void SetNumOptionalParameters(intptr_t num_optional_parameters,
                                 bool are_optional_positional) const;
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 7e66350..d3e0e47 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -59,6 +59,7 @@
       expression_temp_var_(NULL),
       entry_points_temp_var_(NULL),
       finally_return_temp_var_(NULL),
+      dynamic_closure_call_vars_(nullptr),
       guarded_fields_(new ZoneGrowableArray<const Field*>()),
       default_parameter_values_(NULL),
       raw_type_arguments_var_(NULL),
@@ -78,8 +79,7 @@
 
   const bool load_optional_arguments = function.HasOptionalParameters();
 
-  const bool check_arguments =
-      function_.IsClosureFunction() || function.IsFfiTrampoline();
+  const bool check_arguments = function.CanReceiveDynamicInvocation();
 
   const bool need_argument_descriptor =
       load_optional_arguments || check_arguments || reify_generic_argument;
@@ -339,6 +339,25 @@
   return generic_covariant_impl_parameters_->Contains(i);
 }
 
+ParsedFunction::DynamicClosureCallVars*
+ParsedFunction::EnsureDynamicClosureCallVars() {
+  ASSERT(function().IsDynamicClosureCallDispatcher(thread()));
+  if (dynamic_closure_call_vars_ != nullptr) return dynamic_closure_call_vars_;
+  dynamic_closure_call_vars_ = new (zone()) DynamicClosureCallVars();
+
+  const auto& type_Array = Type::ZoneHandle(zone(), Type::ArrayType());
+  const auto& type_Bool = Type::ZoneHandle(zone(), Type::BoolType());
+  const auto& type_Smi = Type::ZoneHandle(zone(), Type::SmiType());
+#define INIT_FIELD(Name, TypeName, Symbol)                                     \
+  dynamic_closure_call_vars_->Name = new (zone())                              \
+      LocalVariable(function().token_pos(), function().token_pos(),            \
+                    Symbols::DynamicCall##Symbol##Var(), type_##TypeName);
+  FOR_EACH_DYNAMIC_CLOSURE_CALL_VARIABLE(INIT_FIELD);
+#undef INIT_FIELD
+
+  return dynamic_closure_call_vars_;
+}
+
 }  // namespace dart
 
 #endif  // DART_PRECOMPILED_RUNTIME
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index f574ea6..6ea6d2a 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -243,6 +243,26 @@
   // method.
   bool IsGenericCovariantImplParameter(intptr_t i) const;
 
+  // Variables needed for the InvokeFieldDispatcher for dynamic closure calls.
+  struct DynamicClosureCallVars : ZoneAllocated {
+#define FOR_EACH_DYNAMIC_CLOSURE_CALL_VARIABLE(V)                              \
+  V(current_param_index, Smi, CurrentParamIndex)                               \
+  V(has_named_params, Bool, HasNamed)                                          \
+  V(num_fixed_params, Smi, NumFixed)                                           \
+  V(num_opt_params, Smi, NumOpt)                                               \
+  V(num_max_params, Smi, MaxParams)                                            \
+  V(parameter_names, Array, ParameterNames)
+
+#define DEFINE_FIELD(Name, _, __) LocalVariable* Name = nullptr;
+    FOR_EACH_DYNAMIC_CLOSURE_CALL_VARIABLE(DEFINE_FIELD)
+#undef DEFINE_FIELD
+  };
+
+  DynamicClosureCallVars* dynamic_closure_call_vars() const {
+    return dynamic_closure_call_vars_;
+  }
+  DynamicClosureCallVars* EnsureDynamicClosureCallVars();
+
  private:
   Thread* thread_;
   const Function& function_;
@@ -257,6 +277,7 @@
   LocalVariable* expression_temp_var_;
   LocalVariable* entry_points_temp_var_;
   LocalVariable* finally_return_temp_var_;
+  DynamicClosureCallVars* dynamic_closure_call_vars_;
   ZoneGrowableArray<const Field*>* guarded_fields_;
   ZoneGrowableArray<const Instance*>* default_parameter_values_;
 
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index d76ec2f..499dba8 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -988,8 +988,8 @@
     uint64_t bitmap_;
   };
 
-  static constexpr intptr_t kMaxFixedParametersBits = 15;
-  static constexpr intptr_t kMaxOptionalParametersBits = 14;
+  static constexpr intptr_t kMaxFixedParametersBits = 14;
+  static constexpr intptr_t kMaxOptionalParametersBits = 13;
 
  private:
   friend class Class;
@@ -1063,6 +1063,10 @@
   static_assert(PackedNumOptionalParameters::kNextBit <=
                     kBitsPerWord * sizeof(decltype(packed_fields_)),
                 "FunctionLayout::packed_fields_ bitfields don't align.");
+  static_assert(PackedNumOptionalParameters::kNextBit <=
+                    compiler::target::kSmiBits,
+                "In-place mask for number of optional parameters cannot fit in "
+                "a Smi on the target architecture");
 
 #define JIT_FUNCTION_COUNTERS(F)                                               \
   F(intptr_t, int32_t, usage_counter)                                          \
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 4b7e6ad..0d7ffce 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -551,6 +551,28 @@
   arguments.SetReturn(result);
 }
 
+// Check that arguments are valid for the given closure.
+// Arg0: function
+// Arg1: arguments descriptor
+// Return value: whether the arguments are valid
+DEFINE_RUNTIME_ENTRY(ClosureArgumentsValid, 2) {
+  ASSERT(FLAG_enable_interpreter);
+  const auto& closure = Closure::CheckedHandle(zone, arguments.ArgAt(0));
+  const auto& descriptor = Array::CheckedHandle(zone, arguments.ArgAt(1));
+
+  const auto& function = Function::Handle(zone, closure.function());
+  const ArgumentsDescriptor args_desc(descriptor);
+  if (!function.AreValidArguments(args_desc, nullptr)) {
+    arguments.SetReturn(Bool::False());
+  } else if (!closure.IsGeneric(thread) && args_desc.TypeArgsLen() > 0) {
+    // The arguments may be valid for the closure function itself, but if the
+    // closure has delayed type arguments, no type arguments should be provided.
+    arguments.SetReturn(Bool::False());
+  } else {
+    arguments.SetReturn(Bool::True());
+  }
+}
+
 // Resolve 'call' function of receiver.
 // Arg0: receiver (not a closure).
 // Arg1: arguments descriptor
diff --git a/runtime/vm/runtime_entry_list.h b/runtime/vm/runtime_entry_list.h
index 8945038..c514b573 100644
--- a/runtime/vm/runtime_entry_list.h
+++ b/runtime/vm/runtime_entry_list.h
@@ -16,6 +16,7 @@
   V(SingleStepHandler)                                                         \
   V(CloneContext)                                                              \
   V(GetFieldForDispatch)                                                       \
+  V(ClosureArgumentsValid)                                                     \
   V(ResolveCallFunction)                                                       \
   V(FixCallersTarget)                                                          \
   V(FixCallersTargetMonomorphic)                                               \
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 529f4fa..9010987 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -108,6 +108,12 @@
   V(Double, "double")                                                          \
   V(Dynamic, "dynamic")                                                        \
   V(DynamicCall, "dyn:call")                                                   \
+  V(DynamicCallCurrentParamIndexVar, ":dyn_call_current_param_index")          \
+  V(DynamicCallHasNamedVar, ":dyn_call_has_named")                             \
+  V(DynamicCallMaxParamsVar, ":dyn_call_max_params")                           \
+  V(DynamicCallNumFixedVar, ":dyn_call_num_fixed")                             \
+  V(DynamicCallNumOptVar, ":dyn_call_num_opt")                                 \
+  V(DynamicCallParameterNamesVar, ":dyn_call_parameter_names")                 \
   V(DynamicPrefix, "dyn:")                                                     \
   V(EntryPointsTemp, ":entry_points_temp")                                     \
   V(EqualOperator, "==")                                                       \
diff --git a/tests/language/nnbd/required_named_parameters/missing_required_argument_dynamic_test.dart b/tests/language/nnbd/required_named_parameters/missing_required_argument_dynamic_test.dart
new file mode 100644
index 0000000..8857a6b
--- /dev/null
+++ b/tests/language/nnbd/required_named_parameters/missing_required_argument_dynamic_test.dart
@@ -0,0 +1,239 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Requirements=nnbd-strong
+
+import 'package:expect/expect.dart';
+
+// Test that it is an error if a named parameter that is part of a required
+// group is not bound to an argument at a call site.
+typedef String F({required String x});
+
+class A {
+  A() {}
+  int m1({required int a}) => 1;
+
+  F m2() => ({required String x}) => 'm2: $x';
+
+  // Check a mix of required and optional.
+  int m3(
+          {required int p1,
+          int p2 = 2,
+          int p3 = 3,
+          int p4 = 4,
+          int p5 = 5,
+          required int p6,
+          int p7 = 7,
+          required int p8,
+          int p9 = 9,
+          int p10 = 10}) =>
+      p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10;
+
+  // Check a case where at least one of the VM required flag packed entries
+  // should be represented by the null Smi. (Need at least 32 optional
+  // parameters on 64-bit architectures for this.)
+  int m4(
+          {int p1 = 1,
+          int p2 = 2,
+          int p3 = 3,
+          int p4 = 4,
+          int p5 = 5,
+          int p6 = 6,
+          int p7 = 7,
+          int p8 = 8,
+          int p9 = 9,
+          int p10 = 10,
+          int p11 = 11,
+          int p12 = 12,
+          int p13 = 13,
+          int p14 = 14,
+          int p15 = 15,
+          int p16 = 16,
+          int p17 = 17,
+          int p18 = 18,
+          int p19 = 19,
+          int p20 = 20,
+          int p21 = 21,
+          int p22 = 22,
+          int p23 = 23,
+          int p24 = 24,
+          int p25 = 25,
+          int p26 = 26,
+          int p27 = 27,
+          int p28 = 28,
+          int p29 = 29,
+          int p30 = 30,
+          int p31 = 31,
+          int p32 = 32,
+          int p33 = 33,
+          int p34 = 34,
+          int p35 = 35,
+          required int p36}) =>
+      p1 +
+      p2 +
+      p3 +
+      p4 +
+      p5 +
+      p6 +
+      p7 +
+      p8 +
+      p9 +
+      p10 +
+      p11 +
+      p12 +
+      p13 +
+      p14 +
+      p15 +
+      p16 +
+      p17 +
+      p18 +
+      p19 +
+      p20 +
+      p21 +
+      p22 +
+      p23 +
+      p24 +
+      p25 +
+      p26 +
+      p27 +
+      p28 +
+      p29 +
+      p30 +
+      p31 +
+      p32 +
+      p33 +
+      p34 +
+      p35 +
+      p36;
+}
+
+int f({required int a}) => 2;
+
+String Function({required int a}) g() => ({required int a}) => 'g';
+
+// Check a mix of required and optional.
+int h(
+        {required int p1,
+        int p2 = 2,
+        int p3 = 3,
+        int p4 = 4,
+        int p5 = 5,
+        int p6 = 6,
+        int p7 = 7,
+        required int p8,
+        int p9 = 9,
+        required int p10}) =>
+    p1 + p2 - p3 + p4 - p5 + p6 - p7 + p8 - p9 + p10;
+
+// Check a case where at least one of the VM required flag packed entries
+// should be represented by the null Smi. (Need at least 32 optional
+// parameters on 64-bit architectures for this.)
+int i(
+        {int p1 = 1,
+        int p2 = 2,
+        int p3 = 3,
+        int p4 = 4,
+        int p5 = 5,
+        int p6 = 6,
+        int p7 = 7,
+        int p8 = 8,
+        int p9 = 9,
+        int p10 = 10,
+        int p11 = 11,
+        int p12 = 12,
+        int p13 = 13,
+        int p14 = 14,
+        int p15 = 15,
+        int p16 = 16,
+        int p17 = 17,
+        int p18 = 18,
+        int p19 = 19,
+        int p20 = 20,
+        int p21 = 21,
+        int p22 = 22,
+        int p23 = 23,
+        int p24 = 24,
+        int p25 = 25,
+        int p26 = 26,
+        int p27 = 27,
+        int p28 = 28,
+        int p29 = 29,
+        int p30 = 30,
+        int p31 = 31,
+        int p32 = 32,
+        int p33 = 33,
+        required int p34,
+        int p35 = 35,
+        int p36 = 36}) =>
+    p1 +
+    p2 -
+    p3 +
+    p4 -
+    p5 +
+    p6 -
+    p7 +
+    p8 -
+    p9 +
+    p10 -
+    p11 +
+    p12 -
+    p13 +
+    p14 -
+    p15 +
+    p16 -
+    p17 +
+    p18 -
+    p19 +
+    p20 -
+    p21 +
+    p22 -
+    p23 +
+    p24 -
+    p25 +
+    p26 -
+    p27 +
+    p28 -
+    p29 +
+    p30 -
+    p31 +
+    p32 -
+    p33 +
+    p34 -
+    p35 +
+    p36;
+
+main() {
+  A a = A();
+  dynamic b = a as dynamic;
+  Expect.equals(1, (a.m1 as dynamic)(a: 5));
+  Expect.throwsNoSuchMethodError(() => (a.m1 as dynamic)());
+  Expect.equals(1, b.m1(a: 5));
+  Expect.throwsNoSuchMethodError(() => b.m1());
+  Expect.equals(2, (f as dynamic)(a: 3));
+  Expect.throwsNoSuchMethodError(() => (f as dynamic)());
+
+  Expect.equals('g', (g() as dynamic)(a: 4));
+  Expect.throwsNoSuchMethodError(() => (g() as dynamic)());
+  Expect.equals('g', (g as dynamic)()(a: 4));
+  Expect.throwsNoSuchMethodError(() => (g as dynamic)()());
+  Expect.equals('m2: check', (a.m2() as dynamic)(x: 'check'));
+  Expect.throwsNoSuchMethodError(() => (a.m2() as dynamic)());
+  Expect.equals('m2: check', b.m2()(x: 'check'));
+  Expect.throwsNoSuchMethodError(() => b.m2()());
+
+  Expect.equals(7, (h as dynamic)(p1: 1, p8: 8, p10: 10));
+  Expect.throwsNoSuchMethodError(() => (h as dynamic)(p1: 1, p6: 6, p10: 10));
+  Expect.equals(55, (a.m3 as dynamic)(p1: 1, p6: 6, p8: 8));
+  Expect.throwsNoSuchMethodError(
+      () => (a.m3 as dynamic)(p1: 1, p8: 8, p10: 10));
+  Expect.equals(55, b.m3(p1: 1, p6: 6, p8: 8));
+  Expect.throwsNoSuchMethodError(() => b.m3(p1: 1, p8: 8, p10: 10));
+
+  Expect.equals(20, (i as dynamic)(p34: 34));
+  Expect.throwsNoSuchMethodError(() => (i as dynamic)(p36: 36));
+  Expect.equals(666, (a.m4 as dynamic)(p36: 36));
+  Expect.throwsNoSuchMethodError(() => (a.m4 as dynamic)(p34: 34));
+  Expect.equals(666, b.m4(p36: 36));
+  Expect.throwsNoSuchMethodError(() => b.m4(p34: 34));
+}