Version 2.14.0-132.0.dev

Merge commit '269828ed34b7f2b3406941d5c438a853fe01864f' into 'dev'
diff --git a/DEPS b/DEPS
index c6d7fe8..4c1a614 100644
--- a/DEPS
+++ b/DEPS
@@ -45,7 +45,7 @@
   # hashes. It requires access to the dart-build-access group, which EngProd
   # has.
   "co19_rev": "055b5c984613ec1b8ef76516db3ea99fee63acb9",
-  "co19_2_rev": "f7f583366396cb1457e58c9bfb6d6e53dc21d741",
+  "co19_2_rev": "1c2e425f461bfae7de6db7014fc44a58fc72b4a8",
 
   # The internal benchmarks to use. See go/dart-benchmarks-internal
   "benchmarks_internal_rev": "076df10d9b77af337f2d8029725787155eb1cd52",
diff --git a/pkg/dartdev/lib/src/templates/server_shelf.dart b/pkg/dartdev/lib/src/templates/server_shelf.dart
index fcd674f..97794bb 100644
--- a/pkg/dartdev/lib/src/templates/server_shelf.dart
+++ b/pkg/dartdev/lib/src/templates/server_shelf.dart
@@ -149,22 +149,22 @@
 
 # Resolve app dependencies.
 WORKDIR /app
-COPY pubspec.* .
+COPY pubspec.* ./
 RUN dart pub get
 
 # Copy app source code (except anything in .dockerignore) and AOT compile app.
 COPY . .
-RUN dart compile exe bin/server.dart -o /server
+RUN dart compile exe bin/server.dart -o bin/server
 
 # Build minimal serving image from AOT-compiled `/server`
 # and the pre-built AOT-runtime in the `/runtime/` directory of the base image.
 FROM scratch
 COPY --from=build /runtime/ /
-COPY --from=build /server /bin/
+COPY --from=build /app/bin/server /app/bin/
 
 # Start server.
 EXPOSE 8080
-CMD ["/bin/server"]
+CMD ["/app/bin/server"]
 ''';
 
 final String _dockerignore = r'''
diff --git a/runtime/platform/assert.h b/runtime/platform/assert.h
index c4155d0..bdf73c5 100644
--- a/runtime/platform/assert.h
+++ b/runtime/platform/assert.h
@@ -339,7 +339,15 @@
 
 #define EXPECT_NULLPTR(ptr) dart::Expect(__FILE__, __LINE__).Null((ptr))
 
-#define FAIL(error) dart::Expect(__FILE__, __LINE__).Fail("%s", error)
+#if defined(_MSC_VER)
+#define FAIL(format, ...)                                                      \
+  dart::Expect(__FILE__, __LINE__).Fail(format, __VA_ARGS__);
+#else
+#define FAIL(format, ...)                                                      \
+  dart::Expect(__FILE__, __LINE__).Fail(format, ##__VA_ARGS__);
+#endif
+
+// Leaving old non-varargs versions to avoid having to rewrite all uses.
 
 #define FAIL1(format, p1) dart::Expect(__FILE__, __LINE__).Fail(format, (p1))
 
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index dd57f81..ece6a7e 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1109,14 +1109,13 @@
       Function& func = Function::Handle(d->zone());
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         func ^= refs.At(i);
-        ASSERT(func.ptr()->untag()->code()->IsCode());
-        if (!Code::IsUnknownDartCode(func.ptr()->untag()->code())) {
-          uword entry_point =
-              func.ptr()->untag()->code()->untag()->entry_point_;
+        auto const code = func.ptr()->untag()->code();
+        ASSERT(code->IsCode());
+        if (!Code::IsUnknownDartCode(code)) {
+          uword entry_point = code->untag()->entry_point_;
           ASSERT(entry_point != 0);
           func.ptr()->untag()->entry_point_ = entry_point;
-          uword unchecked_entry_point =
-              func.ptr()->untag()->code()->untag()->unchecked_entry_point_;
+          uword unchecked_entry_point = code->untag()->unchecked_entry_point_;
           ASSERT(unchecked_entry_point != 0);
           func.ptr()->untag()->unchecked_entry_point_ = unchecked_entry_point;
         }
@@ -1222,7 +1221,7 @@
             static_cast<ContextScopePtr>(d->ReadRef());
       }
       data->untag()->parent_function_ = static_cast<FunctionPtr>(d->ReadRef());
-      data->untag()->closure_ = static_cast<InstancePtr>(d->ReadRef());
+      data->untag()->closure_ = static_cast<ClosurePtr>(d->ReadRef());
       data->untag()->default_type_arguments_kind_ =
           static_cast<ClosureData::DefaultTypeArgumentsKind>(d->ReadUnsigned());
     }
@@ -4464,8 +4463,29 @@
                                      Closure::InstanceSize(),
                                      primary && is_canonical());
       ReadFromTo(closure);
+#if defined(DART_PRECOMPILED_RUNTIME)
+      closure->untag()->entry_point_ = 0;
+#endif
     }
   }
+
+  void PostLoad(Deserializer* d, const Array& refs, bool primary) {
+#if defined(DART_PRECOMPILED_RUNTIME)
+    // We only cache the entry point in bare instructions mode (as we need
+    // to load the function anyway otherwise).
+    if (d->kind() == Snapshot::kFullAOT && FLAG_use_bare_instructions) {
+      auto& closure = Closure::Handle(d->zone());
+      auto& func = Function::Handle(d->zone());
+      for (intptr_t i = start_index_; i < stop_index_; i++) {
+        closure ^= refs.At(i);
+        func = closure.function();
+        uword entry_point = func.entry_point();
+        ASSERT(entry_point != 0);
+        closure.ptr()->untag()->entry_point_ = entry_point;
+      }
+    }
+#endif
+  }
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -6121,6 +6141,20 @@
         uword unchecked_entry_point = code->untag()->unchecked_entry_point_;
         ASSERT(unchecked_entry_point != 0);
         func->untag()->unchecked_entry_point_ = unchecked_entry_point;
+#if defined(DART_PRECOMPILED_RUNTIME)
+        if (FLAG_use_bare_instructions &&
+            func->untag()->data()->IsHeapObject() &&
+            func->untag()->data()->IsClosureData()) {
+          // For closure functions in bare instructions mode, also update the
+          // cache inside the static implicit closure object, if any.
+          auto data = static_cast<ClosureDataPtr>(func->untag()->data());
+          if (data->untag()->closure() != Closure::null()) {
+            // Closure functions only have one entry point.
+            ASSERT_EQUAL(entry_point, unchecked_entry_point);
+            data->untag()->closure()->untag()->entry_point_ = entry_point;
+          }
+        }
+#endif
       }
       if (!FLAG_use_bare_instructions) {
         code->untag()->object_pool_ = static_cast<ObjectPoolPtr>(d->ReadRef());
@@ -7064,48 +7098,57 @@
 
   GrowableArray<SerializationCluster*> clusters;
   // The order that PostLoad runs matters for some classes because of
-  // assumptions during canonicalization of some classes about what is already
-  // canonical. Explicitly place these clusters first, then add the rest
-  // ordered by class id.
-#define ADD_NEXT(cid)                                                          \
+  // assumptions during canonicalization, read filling, or post-load filling of
+  // some classes about what has already been read and/or canonicalized.
+  // Explicitly add these clusters first, then add the rest ordered by class id.
+#define ADD_CANONICAL_NEXT(cid)                                                \
   if (auto const cluster = canonical_clusters_by_cid_[cid]) {                  \
     clusters.Add(cluster);                                                     \
     canonical_clusters_by_cid_[cid] = nullptr;                                 \
   }
-  ADD_NEXT(kOneByteStringCid)
-  ADD_NEXT(kTwoByteStringCid)
-  ADD_NEXT(kMintCid)
-  ADD_NEXT(kDoubleCid)
-  ADD_NEXT(kTypeParameterCid)
-  ADD_NEXT(kTypeCid)
-  ADD_NEXT(kTypeArgumentsCid)
-  ADD_NEXT(kClosureCid)
-#undef ADD_NEXT
+#define ADD_NON_CANONICAL_NEXT(cid)                                            \
+  if (auto const cluster = clusters_by_cid_[cid]) {                            \
+    clusters.Add(cluster);                                                     \
+    clusters_by_cid_[cid] = nullptr;                                           \
+  }
+  ADD_CANONICAL_NEXT(kOneByteStringCid)
+  ADD_CANONICAL_NEXT(kTwoByteStringCid)
+  ADD_CANONICAL_NEXT(kStringCid)
+  ADD_CANONICAL_NEXT(kMintCid)
+  ADD_CANONICAL_NEXT(kDoubleCid)
+  ADD_CANONICAL_NEXT(kTypeParameterCid)
+  ADD_CANONICAL_NEXT(kTypeCid)
+  ADD_CANONICAL_NEXT(kTypeArgumentsCid)
+  // Code cluster should be deserialized before Function as
+  // FunctionDeserializationCluster::ReadFill uses instructions table
+  // which is filled in CodeDeserializationCluster::ReadFill.
+  ADD_NON_CANONICAL_NEXT(kCodeCid)
+  // The function cluster should be deserialized before any closures, as
+  // PostLoad for closures caches the entry point found in the function.
+  ADD_NON_CANONICAL_NEXT(kFunctionCid)
+  ADD_CANONICAL_NEXT(kClosureCid)
+#undef ADD_CANONICAL_NEXT
+#undef ADD_NON_CANONICAL_NEXT
   const intptr_t out_of_order_clusters = clusters.length();
   for (intptr_t cid = 0; cid < num_cids_; cid++) {
     if (auto const cluster = canonical_clusters_by_cid_[cid]) {
       clusters.Add(cluster);
     }
   }
-  // Put these back so they'll show up in PrintSnapshotSizes.
-  for (intptr_t i = 0; i < out_of_order_clusters; i++) {
-    auto const cluster = clusters.At(i);
-    canonical_clusters_by_cid_[cluster->cid()] = cluster;
-  }
-  // Code cluster should be deserialized before Function as
-  // FunctionDeserializationCluster::ReadFill uses instructions table
-  // which is filled in CodeDeserializationCluster::ReadFill.
-  if (auto const cluster = clusters_by_cid_[kCodeCid]) {
-    clusters.Add(cluster);
-    clusters_by_cid_[kCodeCid] = nullptr;
-  }
   for (intptr_t cid = 0; cid < num_cids_; cid++) {
     if (auto const cluster = clusters_by_cid_[cid]) {
       clusters.Add(clusters_by_cid_[cid]);
     }
   }
-  // Put this back so it'll show up in PrintSnapshotSizes if present.
-  clusters_by_cid_[kCodeCid] = code_cluster_;
+  // Put back any taken out temporarily to avoid re-adding them during the loop.
+  for (intptr_t i = 0; i < out_of_order_clusters; i++) {
+    const auto& cluster = clusters.At(i);
+    const intptr_t cid = cluster->cid();
+    auto const cid_clusters =
+        cluster->is_canonical() ? canonical_clusters_by_cid_ : clusters_by_cid_;
+    ASSERT(cid_clusters[cid] == nullptr);
+    cid_clusters[cid] = cluster;
+  }
 
   instructions_table_len_ = PrepareInstructions();
 
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index ce21bc8..12baaef 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -3973,14 +3973,12 @@
                    intptr_t type_args_len,
                    const Array& argument_names,
                    const InstructionSource& source,
-                   intptr_t deopt_id,
-                   Code::EntryKind entry_kind = Code::EntryKind::kNormal)
+                   intptr_t deopt_id)
       : TemplateDartCall(deopt_id,
                          type_args_len,
                          argument_names,
                          inputs,
-                         source),
-        entry_kind_(entry_kind) {}
+                         source) {}
 
   DECLARE_INSTRUCTION(ClosureCall)
 
@@ -3989,13 +3987,9 @@
 
   virtual bool HasUnknownSideEffects() const { return true; }
 
-  Code::EntryKind entry_kind() const { return entry_kind_; }
-
   PRINT_OPERANDS_TO_SUPPORT
 
  private:
-  const Code::EntryKind entry_kind_;
-
   DISALLOW_COPY_AND_ASSIGN(ClosureCallInstr);
 };
 
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 61558c5..cb66118 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -597,17 +597,21 @@
       Array::ZoneHandle(Z, GetArgumentsDescriptor());
   __ LoadObject(R4, arguments_descriptor);
 
-  // R4: Arguments descriptor.
-  // R0: Function.
   ASSERT(locs()->in(0).reg() == R0);
-  if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+    // R0: Closure with a cached entry point.
+    __ ldr(R2, compiler::FieldAddress(
+                   R0, compiler::target::Closure::entry_point_offset()));
+  } else {
+    // R0: Function.
     __ ldr(CODE_REG, compiler::FieldAddress(
                          R0, compiler::target::Function::code_offset()));
+    // Closure functions only have one entry point.
+    __ ldr(R2, compiler::FieldAddress(
+                   R0, compiler::target::Function::entry_point_offset()));
   }
-  __ ldr(R2,
-         compiler::FieldAddress(
-             R0, compiler::target::Function::entry_point_offset(entry_kind())));
 
+  // R4: Arguments descriptor array.
   // R2: instructions entry point.
   if (!FLAG_precompiled_mode) {
     // R9: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index da3b618..b4accd0 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -522,17 +522,22 @@
       Array::ZoneHandle(Z, GetArgumentsDescriptor());
   __ LoadObject(R4, arguments_descriptor);
 
-  // R4: Arguments descriptor.
-  // R0: Function.
   ASSERT(locs()->in(0).reg() == R0);
-  if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+    // R0: Closure with a cached entry point.
+    __ LoadFieldFromOffset(R2, R0,
+                           compiler::target::Closure::entry_point_offset());
+  } else {
+    // R0: Function.
     __ LoadCompressedFieldFromOffset(CODE_REG, R0,
                                      compiler::target::Function::code_offset());
+    // Closure functions only have one entry point.
+    __ LoadFieldFromOffset(R2, R0,
+                           compiler::target::Function::entry_point_offset());
   }
-  __ LoadFieldFromOffset(
-      R2, R0, compiler::target::Function::entry_point_offset(entry_kind()));
 
-  // R2: instructions.
+  // R4: Arguments descriptor array.
+  // R2: instructions entry point.
   if (!FLAG_precompiled_mode) {
     // R5: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
     __ LoadImmediate(R5, 0);
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index 4ba570f..ca703b3 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -6593,8 +6593,7 @@
 
   // EBX: Code (compiled code or lazy compile stub).
   ASSERT(locs()->in(0).reg() == EAX);
-  __ movl(EBX, compiler::FieldAddress(
-                   EAX, Function::entry_point_offset(entry_kind())));
+  __ movl(EBX, compiler::FieldAddress(EAX, Function::entry_point_offset()));
 
   // EAX: Function.
   // EDX: Arguments descriptor array.
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index 2dcf90c..02c1790 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -475,16 +475,17 @@
 }
 
 void ClosureCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
-  f->AddString(" function=");
+  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+    f->AddString(" closure=");
+  } else {
+    f->AddString(" function=");
+  }
   InputAt(InputCount() - 1)->PrintTo(f);
   f->Printf("<%" Pd ">", type_args_len());
   for (intptr_t i = 0; i < ArgumentCount(); ++i) {
     f->AddString(", ");
     ArgumentValueAt(i)->PrintTo(f);
   }
-  if (entry_kind() == Code::EntryKind::kUnchecked) {
-    f->AddString(" using unchecked entrypoint");
-  }
 }
 
 void InstanceCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
diff --git a/runtime/vm/compiler/backend/il_test.cc b/runtime/vm/compiler/backend/il_test.cc
index 3f70e07..48654fb 100644
--- a/runtime/vm/compiler/backend/il_test.cc
+++ b/runtime/vm/compiler/backend/il_test.cc
@@ -169,7 +169,7 @@
                             /*expected_stores=*/{"g"});
   RunInitializingStoresTest(root_library, "f3", CompilerPass::kJIT,
                             /*expected_stores=*/
-                            {"Closure.function"});
+                            {"Closure.function", "Closure.entry_point"});
 
   // Note that in JIT mode we lower context allocation in a way that hinders
   // removal of initializing moves so there would be some redundant stores of
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 0ca20ae..72e489e 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -6881,20 +6881,23 @@
       Array::ZoneHandle(Z, GetArgumentsDescriptor());
   __ LoadObject(R10, arguments_descriptor);
 
-  // Function in RAX.
   ASSERT(locs()->in(0).reg() == RAX);
-  if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+    // RAX: Closure with cached entry point.
+    __ movq(RCX, compiler::FieldAddress(
+                     RAX, compiler::target::Closure::entry_point_offset()));
+  } else {
+    // RAX: Function.
     __ LoadCompressed(
         CODE_REG,
         compiler::FieldAddress(RAX, compiler::target::Function::code_offset()));
+    // Closure functions only have one entry point.
+    __ movq(RCX, compiler::FieldAddress(
+                     RAX, compiler::target::Function::entry_point_offset()));
   }
-  __ movq(
-      RCX,
-      compiler::FieldAddress(
-          RAX, compiler::target::Function::entry_point_offset(entry_kind())));
 
-  // RAX: Function.
   // R10: Arguments descriptor array.
+  // RCX: instructions entry point.
   if (!FLAG_precompiled_mode) {
     // RBX: Smi 0 (no IC data; the lazy-compile stub expects a GC-safe value).
     __ xorq(RBX, RBX);
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 62172d2..5c8dcc8 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -1051,7 +1051,7 @@
                        call_data->call->AsPolymorphicInstanceCall()) {
           entry_kind = instr->entry_kind();
         } else if (ClosureCallInstr* instr = call_data->call->AsClosureCall()) {
-          entry_kind = instr->entry_kind();
+          // Closure functions only have one entry point.
         }
         kernel::FlowGraphBuilder builder(
             parsed_function, ic_data_array, /* not building var desc */ NULL,
diff --git a/runtime/vm/compiler/backend/locations.h b/runtime/vm/compiler/backend/locations.h
index a8ea373..ad2dc86 100644
--- a/runtime/vm/compiler/backend/locations.h
+++ b/runtime/vm/compiler/backend/locations.h
@@ -81,6 +81,16 @@
   static compiler::OperandSize OperandSize(Representation rep);
 };
 
+// The representation for word-sized unboxed fields.
+static constexpr Representation kUnboxedWord =
+    compiler::target::kWordSize == 4 ? kUnboxedInt32 : kUnboxedInt64;
+// The representation for unsigned word-sized unboxed fields.
+//
+// Note: kUnboxedUword is identical to kUnboxedWord until range analysis can
+// handle unsigned 64-bit ranges. This means that range analysis will give
+// signed results for unboxed uword field values.
+static constexpr Representation kUnboxedUword = kUnboxedWord;
+
 // 'UnboxedFfiIntPtr' should be able to hold a pointer of the target word-size.
 // On a 32-bit platform, it's an unsigned 32-bit int because it should be
 // zero-extended to 64-bits, not sign-extended (pointers are inherently
@@ -92,8 +102,7 @@
 
 // The representation which can be used for native pointers. We use signed 32/64
 // bit representation to be able to do arithmetic on pointers.
-static constexpr Representation kUnboxedIntPtr =
-    compiler::target::kWordSize == 4 ? kUnboxedInt32 : kUnboxedInt64;
+static constexpr Representation kUnboxedIntPtr = kUnboxedWord;
 
 // Location objects are used to connect register allocator and code generator.
 // Instruction templates used by code generator have a corresponding
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index c1019e5..a1daab1 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -110,6 +110,15 @@
   V(UnhandledException, UntaggedUnhandledException, exception, Dynamic, FINAL) \
   V(UnhandledException, UntaggedUnhandledException, stacktrace, Dynamic, FINAL)
 
+// Only define AOT-only unboxed native slots when in the precompiler. See
+// UNBOXED_NATIVE_SLOTS_LIST for the format.
+#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
+#define AOT_ONLY_UNBOXED_NATIVE_SLOTS_LIST(V)                                  \
+  V(Closure, UntaggedClosure, entry_point, Uword, FINAL)
+#else
+#define AOT_ONLY_UNBOXED_NATIVE_SLOTS_LIST(V)
+#endif
+
 // List of slots that correspond to unboxed fields of native objects in the
 // following format:
 //
@@ -125,9 +134,14 @@
 //   that) or like a non-final field.
 //
 // Note: As the underlying field is unboxed, these slots cannot be nullable.
+//
+// Note: Currently LoadFieldInstr::IsImmutableLengthLoad() assumes that no
+// unboxed slots represent length loads.
 #define UNBOXED_NATIVE_SLOTS_LIST(V)                                           \
+  AOT_ONLY_UNBOXED_NATIVE_SLOTS_LIST(V)                                        \
   V(ClosureData, UntaggedClosureData, default_type_arguments_kind, Uint8,      \
     FINAL)                                                                     \
+  V(Function, UntaggedFunction, entry_point, Uword, FINAL)                     \
   V(Function, UntaggedFunction, kind_tag, Uint32, FINAL)                       \
   V(Function, UntaggedFunction, packed_fields, Uint32, FINAL)                  \
   V(FunctionType, UntaggedFunctionType, packed_fields, Uint32, FINAL)          \
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index acfc656..52416d7 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -1106,7 +1106,7 @@
     return Drop();
   }
   auto& closure = Closure::ZoneHandle(Z, Closure::Cast(options).ptr());
-  LocalVariable* entry_point_num = MakeTemporary();
+  LocalVariable* entry_point_num = MakeTemporary("entry_point_num");
 
   auto& function_name = String::ZoneHandle(
       Z, String::New(function.ToLibNamePrefixedQualifiedCString(), Heap::kOld));
@@ -1123,27 +1123,30 @@
   call_hook += Constant(closure);
   call_hook += Constant(function_name);
   call_hook += LoadLocal(entry_point_num);
-  call_hook += Constant(Function::ZoneHandle(Z, closure.function()));
+  if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
+    call_hook += Constant(closure);
+  } else {
+    call_hook += Constant(Function::ZoneHandle(Z, closure.function()));
+  }
   call_hook += ClosureCall(TokenPosition::kNoSource,
                            /*type_args_len=*/0, /*argument_count=*/3,
                            /*argument_names=*/Array::ZoneHandle(Z));
-  call_hook += Drop();  // result of closure call
-  call_hook += Drop();  // entrypoint number
+  call_hook += Drop();                           // result of closure call
+  call_hook += DropTemporary(&entry_point_num);  // entrypoint number
   return call_hook;
 }
 
 Fragment BaseFlowGraphBuilder::ClosureCall(TokenPosition position,
                                            intptr_t type_args_len,
                                            intptr_t argument_count,
-                                           const Array& argument_names,
-                                           bool is_statically_checked) {
-  const intptr_t total_count = argument_count + (type_args_len > 0 ? 1 : 0) + 1;
+                                           const Array& argument_names) {
+  const intptr_t total_count =
+      (type_args_len > 0 ? 1 : 0) + argument_count +
+      /*closure (bare instructions) or function (otherwise)*/ 1;
   InputsArray* arguments = GetArguments(total_count);
-  ClosureCallInstr* call = new (Z)
-      ClosureCallInstr(arguments, type_args_len, argument_names,
-                       InstructionSource(position), GetNextDeoptId(),
-                       is_statically_checked ? Code::EntryKind::kUnchecked
-                                             : Code::EntryKind::kNormal);
+  ClosureCallInstr* call =
+      new (Z) ClosureCallInstr(arguments, type_args_len, argument_names,
+                               InstructionSource(position), GetNextDeoptId());
   Push(call);
   return Fragment(call);
 }
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.h b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
index e3948fc..b2d1cfe 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
@@ -402,13 +402,13 @@
   Fragment BuildEntryPointsIntrospection();
 
   // Builds closure call with given number of arguments. Target closure
-  // function is taken from top of the stack.
+  // (in bare instructions mode) or closure function (otherwise) is taken from
+  // top of the stack.
   // PushArgument instructions should be already added for arguments.
   Fragment ClosureCall(TokenPosition position,
                        intptr_t type_args_len,
                        intptr_t argument_count,
-                       const Array& argument_names,
-                       bool use_unchecked_entry = false);
+                       const Array& argument_names);
 
   // Builds StringInterpolate instruction, an equivalent of
   // _StringBase._interpolate call.
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 93d9ad5..1ff1ed3 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -3215,14 +3215,15 @@
   if (is_unchecked_closure_call) {
     // Lookup the function in the closure.
     instructions += LoadLocal(receiver_temp);
-    instructions += LoadNativeField(Slot::Closure_function());
+    if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+      instructions += LoadNativeField(Slot::Closure_function());
+    }
     if (parsed_function()->function().is_debuggable()) {
       ASSERT(!parsed_function()->function().is_native());
       instructions += DebugStepCheck(position);
     }
     instructions +=
-        B->ClosureCall(position, type_args_len, argument_count, argument_names,
-                       /*use_unchecked_entry=*/true);
+        B->ClosureCall(position, type_args_len, argument_count, argument_names);
   } else if (!direct_call_target->IsNull()) {
     // Even if TFA infers a concrete receiver type, the static type of the
     // call-site may still be dynamic and we need to call the dynamic invocation
@@ -3303,14 +3304,15 @@
 
   // Lookup the function in the closure.
   instructions += LoadLocal(variable);
-  instructions += LoadNativeField(Slot::Closure_function());
+  if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+    instructions += LoadNativeField(Slot::Closure_function());
+  }
   if (parsed_function()->function().is_debuggable()) {
     ASSERT(!parsed_function()->function().is_native());
     instructions += DebugStepCheck(position);
   }
   instructions +=
-      B->ClosureCall(position, type_args_len, argument_count, argument_names,
-                     /*use_unchecked_entry=*/true);
+      B->ClosureCall(position, type_args_len, argument_count, argument_names);
   return instructions;
 }
 
@@ -3365,14 +3367,15 @@
                               /*clear_temp=*/false);
     // Lookup the function in the closure.
     instructions += LoadLocal(receiver_temp);
-    instructions += LoadNativeField(Slot::Closure_function());
+    if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+      instructions += LoadNativeField(Slot::Closure_function());
+    }
     if (parsed_function()->function().is_debuggable()) {
       ASSERT(!parsed_function()->function().is_native());
       instructions += DebugStepCheck(position);
     }
     instructions +=
-        B->ClosureCall(position, type_args_len, argument_count, argument_names,
-                       /*use_unchecked_entry=*/true);
+        B->ClosureCall(position, type_args_len, argument_count, argument_names);
   } else {
     instructions += InstanceCall(
         position, Symbols::DynamicCall(), Token::kILLEGAL, type_args_len,
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 583a636..a12040d 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2974,10 +2974,11 @@
   }
 
   if (is_closure_call) {
-    // Lookup the function in the closure.
     body += LoadLocal(closure);
-    body += LoadNativeField(Slot::Closure_function());
-
+    if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
+      // Lookup the function in the closure.
+      body += LoadNativeField(Slot::Closure_function());
+    }
     body += ClosureCall(TokenPosition::kNoSource, descriptor.TypeArgsLen(),
                         descriptor.Count(), *argument_names);
   } else {
diff --git a/runtime/vm/compiler/offsets_extractor.cc b/runtime/vm/compiler/offsets_extractor.cc
index 4c11893..454457d 100644
--- a/runtime/vm/compiler/offsets_extractor.cc
+++ b/runtime/vm/compiler/offsets_extractor.cc
@@ -96,6 +96,10 @@
                "_" #Name " = "                                                 \
             << Class::Name << ";\n";
 
+    AOT_OFFSETS_LIST(PRINT_FIELD_OFFSET, PRINT_ARRAY_LAYOUT, PRINT_SIZEOF,
+                     PRINT_ARRAY_SIZEOF, PRINT_PAYLOAD_SIZEOF, PRINT_RANGE,
+                     PRINT_CONSTANT)
+
 #else  // defined(DART_PRECOMPILED_RUNTIME)
 
 #define PRINT_FIELD_OFFSET(Class, Name)                                        \
diff --git a/runtime/vm/compiler/runtime_api.cc b/runtime/vm/compiler/runtime_api.cc
index 48b7da7..8aa7359 100644
--- a/runtime/vm/compiler/runtime_api.cc
+++ b/runtime/vm/compiler/runtime_api.cc
@@ -613,7 +613,8 @@
 #define DEFINE_JIT_FIELD(clazz, name)                                          \
   word clazz::name() {                                                         \
     if (FLAG_precompiled_mode) {                                               \
-      FATAL1("Use JIT-only field %s in precompiled mode", #clazz "::" #name);  \
+      FATAL("Use of JIT-only field %s in precompiled mode",                    \
+            #clazz "::" #name);                                                \
     }                                                                          \
     return clazz##_##name;                                                     \
   }
@@ -621,8 +622,8 @@
 #define DEFINE_JIT_ARRAY(clazz, name)                                          \
   word clazz::name(intptr_t index) {                                           \
     if (FLAG_precompiled_mode) {                                               \
-      FATAL1("Use of JIT-only array %s in precompiled mode",                   \
-             #clazz "::" #name);                                               \
+      FATAL("Use of JIT-only array %s in precompiled mode",                    \
+            #clazz "::" #name);                                                \
     }                                                                          \
     return clazz##_elements_start_offset + index * clazz##_element_size;       \
   }
@@ -630,8 +631,8 @@
 #define DEFINE_JIT_SIZEOF(clazz, name, what)                                   \
   word clazz::name() {                                                         \
     if (FLAG_precompiled_mode) {                                               \
-      FATAL1("Use of JIT-only sizeof %s in precompiled mode",                  \
-             #clazz "::" #name);                                               \
+      FATAL("Use of JIT-only sizeof %s in precompiled mode",                   \
+            #clazz "::" #name);                                                \
     }                                                                          \
     return clazz##_##name;                                                     \
   }
@@ -639,8 +640,8 @@
 #define DEFINE_JIT_RANGE(Class, Getter, Type, First, Last, Filter)             \
   word Class::Getter(Type index) {                                             \
     if (FLAG_precompiled_mode) {                                               \
-      FATAL1("Use of JIT-only range %s in precompiled mode",                   \
-             #Class "::" #Getter);                                             \
+      FATAL("Use of JIT-only range %s in precompiled mode",                    \
+            #Class "::" #Getter);                                              \
     }                                                                          \
     return Class##_##Getter[static_cast<intptr_t>(index) -                     \
                             static_cast<intptr_t>(First)];                     \
@@ -659,6 +660,68 @@
 #undef DEFINE_JIT_SIZEOF
 #undef DEFINE_JIT_RANGE
 
+#if defined(DART_PRECOMPILER)
+// The following could check FLAG_precompiled_mode for more safety, but that
+// causes problems for defining things like native Slots, where the definition
+// cannot be based on a runtime flag. Instead, we limit the visibility of these
+// definitions using DART_PRECOMPILER.
+
+#define DEFINE_AOT_FIELD(clazz, name)                                          \
+  word clazz::name() { return AOT_##clazz##_##name; }
+
+#define DEFINE_AOT_ARRAY(clazz, name)                                          \
+  word clazz::name(intptr_t index) {                                           \
+    return AOT_##clazz##_elements_start_offset +                               \
+           index * AOT_##clazz##_element_size;                                 \
+  }
+
+#define DEFINE_AOT_SIZEOF(clazz, name, what)                                   \
+  word clazz::name() { return AOT_##clazz##_##name; }
+
+#define DEFINE_AOT_RANGE(Class, Getter, Type, First, Last, Filter)             \
+  word Class::Getter(Type index) {                                             \
+    return AOT_##Class##_##Getter[static_cast<intptr_t>(index) -               \
+                                  static_cast<intptr_t>(First)];               \
+  }
+#else
+#define DEFINE_AOT_FIELD(clazz, name)                                          \
+  word clazz::name() {                                                         \
+    FATAL("Use of AOT-only field %s outside of the precompiler",               \
+          #clazz "::" #name);                                                  \
+  }
+
+#define DEFINE_AOT_ARRAY(clazz, name)                                          \
+  word clazz::name(intptr_t index) {                                           \
+    FATAL("Use of AOT-only array %s outside of the precompiler",               \
+          #clazz "::" #name);                                                  \
+  }
+
+#define DEFINE_AOT_SIZEOF(clazz, name, what)                                   \
+  word clazz::name() {                                                         \
+    FATAL("Use of AOT-only sizeof %s outside of the precompiler",              \
+          #clazz "::" #name);                                                  \
+  }
+
+#define DEFINE_AOT_RANGE(Class, Getter, Type, First, Last, Filter)             \
+  word Class::Getter(Type index) {                                             \
+    FATAL("Use of AOT-only range %s outside of the precompiler",               \
+          #Class "::" #Getter);                                                \
+  }
+#endif  // defined(DART_PRECOMPILER)
+
+AOT_OFFSETS_LIST(DEFINE_AOT_FIELD,
+                 DEFINE_AOT_ARRAY,
+                 DEFINE_AOT_SIZEOF,
+                 DEFINE_ARRAY_SIZEOF,
+                 DEFINE_PAYLOAD_SIZEOF,
+                 DEFINE_AOT_RANGE,
+                 DEFINE_CONSTANT)
+
+#undef DEFINE_AOT_FIELD
+#undef DEFINE_AOT_ARRAY
+#undef DEFINE_AOT_SIZEOF
+#undef DEFINE_AOT_RANGE
+
 #define DEFINE_FIELD(clazz, name)                                              \
   word clazz::name() {                                                         \
     return FLAG_precompiled_mode ? AOT_##clazz##_##name : clazz##_##name;      \
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index e389c80..491e59f 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -1301,6 +1301,7 @@
  public:
   static word context_offset();
   static word delayed_type_arguments_offset();
+  static word entry_point_offset();
   static word function_offset();
   static word function_type_arguments_offset();
   static word instantiator_type_arguments_offset();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index bdd8b3c..91374ad 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -6494,6 +6494,8 @@
 #if !defined(PRODUCT)
 
 #if defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    28;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     12;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 4;
@@ -7000,7 +7002,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 92;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 28;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 20;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 8;
 static constexpr dart::compiler::target::word
@@ -7095,6 +7097,8 @@
 #endif  // defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
 
 #if defined(TARGET_ARCH_X64) && !defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    56;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     24;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 8;
@@ -7605,7 +7609,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 160;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 64;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -7703,6 +7707,8 @@
 #endif  // defined(TARGET_ARCH_IA32) && !defined(DART_COMPRESSED_POINTERS)
 
 #if defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    56;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     24;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 8;
@@ -8214,7 +8220,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 160;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 64;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -8309,6 +8315,8 @@
 #endif  // defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
 
 #if defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    56;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     24;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 8;
@@ -8819,7 +8827,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 96;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 64;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -8914,6 +8922,8 @@
 #endif  // defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
 
 #if defined(TARGET_ARCH_ARM64) && defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    56;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     24;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 8;
@@ -9425,7 +9435,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 96;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 64;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -9522,6 +9532,8 @@
 #else  // !defined(PRODUCT)
 
 #if defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    28;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     12;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 4;
@@ -10021,7 +10033,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 8;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 80;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 28;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 32;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 20;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 8;
 static constexpr dart::compiler::target::word
@@ -10116,6 +10128,8 @@
 #endif  // defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
 
 #if defined(TARGET_ARCH_X64) && !defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    56;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     24;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 8;
@@ -10619,7 +10633,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 136;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 64;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -10717,6 +10731,8 @@
 #endif  // defined(TARGET_ARCH_IA32) && !defined(DART_COMPRESSED_POINTERS)
 
 #if defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    56;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     24;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 8;
@@ -11221,7 +11237,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 136;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 64;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 40;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -11316,6 +11332,8 @@
 #endif  // defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
 
 #if defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    56;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     24;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 8;
@@ -11819,7 +11837,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 88;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 64;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
@@ -11914,6 +11932,8 @@
 #endif  // defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
 
 #if defined(TARGET_ARCH_ARM64) && defined(DART_COMPRESSED_POINTERS)
+static constexpr dart::compiler::target::word AOT_Closure_entry_point_offset =
+    56;
 static constexpr dart::compiler::target::word AOT_Array_elements_start_offset =
     24;
 static constexpr dart::compiler::target::word AOT_Array_element_size = 8;
@@ -12418,7 +12438,7 @@
 static constexpr dart::compiler::target::word AOT_Bool_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Capability_InstanceSize = 16;
 static constexpr dart::compiler::target::word AOT_Class_InstanceSize = 88;
-static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 56;
+static constexpr dart::compiler::target::word AOT_Closure_InstanceSize = 64;
 static constexpr dart::compiler::target::word AOT_ClosureData_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_CodeSourceMap_HeaderSize = 16;
 static constexpr dart::compiler::target::word
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 0af1b9e..fe34979 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -37,6 +37,7 @@
 //
 // COMMON_OFFSETS_LIST is for declarations that are valid in all contexts.
 // JIT_OFFSETS_LIST is for declarations that are only valid in JIT mode.
+// AOT_OFFSETS_LIST is for declarations that are only valid in AOT mode.
 // A declaration that is not valid in product mode can be wrapped with
 // NOT_IN_PRODUCT().
 //
@@ -409,4 +410,8 @@
   FIELD(Function, usage_counter_offset)                                        \
   FIELD(ICData, receivers_static_type_offset)
 
+#define AOT_OFFSETS_LIST(FIELD, ARRAY, SIZEOF, ARRAY_SIZEOF, PAYLOAD_SIZEOF,   \
+                         RANGE, CONSTANT)                                      \
+  FIELD(Closure, entry_point_offset)
+
 #endif  // RUNTIME_VM_COMPILER_RUNTIME_OFFSETS_LIST_H_
diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc
index 4dbf99c..7e42bc2 100644
--- a/runtime/vm/compiler/stub_code_compiler.cc
+++ b/runtime/vm/compiler/stub_code_compiler.cc
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "vm/compiler/runtime_api.h"
+#include "vm/flags.h"
 #include "vm/globals.h"
 
 // For `StubCodeCompiler::GenerateAllocateUnhandledExceptionStub`
@@ -804,6 +805,24 @@
     __ StoreToSlotNoBarrier(AllocateClosureABI::kScratchReg,
                             AllocateClosureABI::kResultReg,
                             Slot::Closure_hash());
+#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
+    if (FLAG_precompiled_mode) {
+      // Set the closure entry point in precompiled mode, either to the function
+      // entry point in bare instructions mode or to 0 otherwise (to catch
+      // misuse). This overwrites the scratch register, but there are no more
+      // boxed fields.
+      if (FLAG_use_bare_instructions) {
+        __ LoadFromSlot(AllocateClosureABI::kScratchReg,
+                        AllocateClosureABI::kFunctionReg,
+                        Slot::Function_entry_point());
+      } else {
+        __ LoadImmediate(AllocateClosureABI::kScratchReg, 0);
+      }
+      __ StoreToSlotNoBarrier(AllocateClosureABI::kScratchReg,
+                              AllocateClosureABI::kResultReg,
+                              Slot::Closure_entry_point());
+    }
+#endif
 
     // AllocateClosureABI::kResultReg: new object.
     __ Ret();
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index cf63124..4a634d4 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -160,6 +160,10 @@
       CHECK_FIELD, CHECK_ARRAY, CHECK_SIZEOF, CHECK_ARRAY_SIZEOF,
       CHECK_PAYLOAD_SIZEOF, CHECK_RANGE, CHECK_CONSTANT))
 
+  ONLY_IN_PRECOMPILED(AOT_OFFSETS_LIST(CHECK_FIELD, CHECK_ARRAY, CHECK_SIZEOF,
+                                       CHECK_ARRAY_SIZEOF, CHECK_PAYLOAD_SIZEOF,
+                                       CHECK_RANGE, CHECK_CONSTANT))
+
   if (!ok) {
     FATAL(
         "CheckOffsets failed. Try updating offsets by running "
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index da706c5..0834a41 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -7266,16 +7266,16 @@
   UNREACHABLE();
 }
 
-InstancePtr Function::implicit_static_closure() const {
+ClosurePtr Function::implicit_static_closure() const {
   if (IsImplicitStaticClosureFunction()) {
     const Object& obj = Object::Handle(untag()->data());
     ASSERT(!obj.IsNull());
     return ClosureData::Cast(obj).implicit_static_closure();
   }
-  return Instance::null();
+  return Closure::null();
 }
 
-void Function::set_implicit_static_closure(const Instance& closure) const {
+void Function::set_implicit_static_closure(const Closure& closure) const {
   if (IsImplicitStaticClosureFunction()) {
     const Object& obj = Object::Handle(untag()->data());
     ASSERT(!obj.IsNull());
@@ -9277,30 +9277,30 @@
   }
 }
 
-InstancePtr Function::ImplicitStaticClosure() const {
+ClosurePtr Function::ImplicitStaticClosure() const {
   ASSERT(IsImplicitStaticClosureFunction());
-  if (implicit_static_closure() != Instance::null()) {
+  if (implicit_static_closure() != Closure::null()) {
     return implicit_static_closure();
   }
 
   auto thread = Thread::Current();
   SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
 
-  if (implicit_static_closure() != Instance::null()) {
+  if (implicit_static_closure() != Closure::null()) {
     return implicit_static_closure();
   }
 
   Zone* zone = thread->zone();
   const auto& null_context = Context::Handle(zone);
   const auto& closure =
-      Instance::Handle(zone, Closure::New(Object::null_type_arguments(),
-                                          Object::null_type_arguments(), *this,
-                                          null_context, Heap::kOld));
+      Closure::Handle(zone, Closure::New(Object::null_type_arguments(),
+                                         Object::null_type_arguments(), *this,
+                                         null_context, Heap::kOld));
   set_implicit_static_closure(closure);
   return implicit_static_closure();
 }
 
-InstancePtr Function::ImplicitInstanceClosure(const Instance& receiver) const {
+ClosurePtr Function::ImplicitInstanceClosure(const Instance& receiver) const {
   ASSERT(IsImplicitClosureFunction());
   Zone* zone = Thread::Current()->zone();
   const Context& context = Context::Handle(zone, Context::New(1));
@@ -10267,9 +10267,9 @@
   untag()->set_context_scope(value.ptr());
 }
 
-void ClosureData::set_implicit_static_closure(const Instance& closure) const {
+void ClosureData::set_implicit_static_closure(const Closure& closure) const {
   ASSERT(!closure.IsNull());
-  ASSERT(untag()->closure() == Instance::null());
+  ASSERT(untag()->closure() == Closure::null());
   untag()->set_closure<std::memory_order_release>(closure.ptr());
 }
 
@@ -24985,6 +24985,10 @@
     result.untag()->set_delayed_type_arguments(delayed_type_arguments.ptr());
     result.untag()->set_function(function.ptr());
     result.untag()->set_context(context.ptr());
+#if defined(DART_PRECOMPILED_RUNTIME)
+    result.set_entry_point(FLAG_use_bare_instructions ? function.entry_point()
+                                                      : 0);
+#endif
   }
   return result.ptr();
 }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index e3189da..4766260 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2836,9 +2836,9 @@
 
   // Return the closure implicitly created for this function.
   // If none exists yet, create one and remember it.
-  InstancePtr ImplicitStaticClosure() const;
+  ClosurePtr ImplicitStaticClosure() const;
 
-  InstancePtr ImplicitInstanceClosure(const Instance& receiver) const;
+  ClosurePtr 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).
@@ -3771,8 +3771,8 @@
   void set_parent_function(const Function& value) const;
   FunctionPtr implicit_closure_function() const;
   void set_implicit_closure_function(const Function& value) const;
-  InstancePtr implicit_static_closure() const;
-  void set_implicit_static_closure(const Instance& closure) const;
+  ClosurePtr implicit_static_closure() const;
+  void set_implicit_static_closure(const Closure& closure) const;
   ScriptPtr eval_script() const;
   void set_eval_script(const Script& value) const;
   void set_num_optional_parameters(intptr_t value) const;  // Encoded value.
@@ -3823,10 +3823,10 @@
   void set_parent_function(const Function& value) const;
 #endif
 
-  InstancePtr implicit_static_closure() const {
+  ClosurePtr implicit_static_closure() const {
     return untag()->closure<std::memory_order_acquire>();
   }
-  void set_implicit_static_closure(const Instance& closure) const;
+  void set_implicit_static_closure(const Closure& closure) const;
 
   DefaultTypeArgumentsKind default_type_arguments_kind() const;
   void set_default_type_arguments_kind(DefaultTypeArgumentsKind value) const;
@@ -10937,6 +10937,16 @@
 
 class Closure : public Instance {
  public:
+#if defined(DART_PRECOMPILED_RUNTIME)
+  uword entry_point() const { return untag()->entry_point_; }
+  void set_entry_point(uword entry_point) const {
+    StoreNonPointer(&untag()->entry_point_, entry_point);
+  }
+  static intptr_t entry_point_offset() {
+    return OFFSET_OF(UntaggedClosure, entry_point_);
+  }
+#endif
+
   TypeArgumentsPtr instantiator_type_arguments() const {
     return untag()->instantiator_type_arguments();
   }
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index e075887..2f404f5 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -497,8 +497,8 @@
   Function& old_func = Function::Handle();
   String& selector = String::Handle();
   Function& new_func = Function::Handle();
-  Instance& old_closure = Instance::Handle();
-  Instance& new_closure = Instance::Handle();
+  Closure& old_closure = Closure::Handle();
+  Closure& new_closure = Closure::Handle();
   for (intptr_t i = 0; i < funcs.Length(); i++) {
     old_func ^= funcs.At(i);
     if (old_func.is_static() && old_func.HasImplicitClosureFunction()) {
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index ac28bb9..acff79d 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1408,7 +1408,7 @@
   COMPRESSED_POINTER_FIELD(FunctionPtr, parent_function)
 #endif
   // Closure object for static implicit closures.
-  COMPRESSED_POINTER_FIELD(InstancePtr, closure)
+  COMPRESSED_POINTER_FIELD(ClosurePtr, closure)
   VISIT_TO(closure)
 
   enum class DefaultTypeArgumentsKind : uint8_t {
@@ -1434,6 +1434,7 @@
   DefaultTypeArgumentsKind default_type_arguments_kind_;
 
   friend class Function;
+  friend class UnitDeserializationRoots;
 };
 
 class UntaggedFfiTrampolineData : public UntaggedObject {
@@ -2720,6 +2721,12 @@
   POINTER_FIELD(SmiPtr, hash)
   VISIT_TO(hash)
 
+  // We have an extra word in the object due to alignment rounding, so use it in
+  // bare instructions mode to cache the entry point from the closure function
+  // to avoid an extra redirection on call. Closure functions only have
+  // one entry point, as dynamic calls use dynamic closure call dispatchers.
+  ONLY_IN_PRECOMPILED(uword entry_point_);
+
   ObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
 
   // Note that instantiator_type_arguments_, function_type_arguments_ and
@@ -2744,6 +2751,8 @@
   // Object::empty_type_arguments(), the types in this vector will be passed as
   // type arguments to the closure when invoked. In this case there may not be
   // any type arguments passed directly (or NSM will be invoked instead).
+
+  friend class UnitDeserializationRoots;
 };
 
 class UntaggedNumber : public UntaggedInstance {
diff --git a/tools/VERSION b/tools/VERSION
index ecfba87..b1dbbe1 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 131
+PRERELEASE 132
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/utils/application_snapshot.gni b/utils/application_snapshot.gni
index 7ecdf28..51d2b147 100644
--- a/utils/application_snapshot.gni
+++ b/utils/application_snapshot.gni
@@ -145,7 +145,7 @@
     dfe = "$_dart_root/pkg/vm/bin/kernel_service.dart"
 
     abs_depfile = rebase_path(depfile)
-    abs_output = rebase_path(output, root_build_dir)
+    abs_output = rebase_path(output)
 
     vm_args = [
                 "--deterministic",