[vm/kernel] Use GC-tracked ExternalTypedData/TypedDataView for kernel buffers

Until now we often leaked kernel buffers (e.g. hot reload buffers) because various
objects were referencing ExternalTypedData objects pointing into the middle of
c-allocated memory. This made it impossible for the GC to determine when the last
reference is gone.

This CL ensures that the actual buffers are *always* made available via
ExternalTypedData and any inner pointers into it are created via TypedDataViews.

The embedder guarantees to the free kernel buffers it has provided to:
    - Dart_CreateIsolateFromKernel
    - Dart_LoadScriptFromKernel
    - Dart_LoadLibraryFromKernel
    - Dart_SetDartLibrarySourcesKernel
on isolate shutdown.

All other kernel buffers will get a finalizer attached, which ensures the
kernel buffers get freed by the GC once they are no longer referenced:
    - Kernel blobs for expression evaluation
    - Kernel blobs for Hot-Reload
    - Kernel blobs for cc tests

Fixes https://github.com/dart-lang/sdk/issues/33973
Fixes https://github.com/dart-lang/sdk/issues/36857
Issue https://github.com/dart-lang/sdk/issues/37030

Change-Id: I1cc410c94c0f4b229413e793728a261afcb10aaf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/103130
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index f144ed4..8da776e 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -2841,8 +2841,8 @@
  * of an application is needed and the VM is 'use dart front end' mode.
  * The dart front end typically compiles all the scripts, imports and part
  * files into one intermediate file hence we don't use the source/import or
- * script tags. The return value should be an error or a TypedData containing
- * the kernel bytes.
+ * script tags. The return value should be an error or an external TypedData
+ * containing the kernel bytes.
  *
  * Dart_kImportExtensionTag
  *
diff --git a/runtime/vm/base64.cc b/runtime/vm/base64.cc
index 60e919d..b27cf74 100644
--- a/runtime/vm/base64.cc
+++ b/runtime/vm/base64.cc
@@ -35,7 +35,7 @@
 
 static const char PAD = '=';
 
-uint8_t* DecodeBase64(Zone* zone, const char* str, intptr_t* out_decoded_len) {
+uint8_t* DecodeBase64(const char* str, intptr_t* out_decoded_len) {
   intptr_t len = strlen(str);
   if (len == 0 || (len % 4 != 0)) {
     return nullptr;
@@ -48,7 +48,7 @@
     if (current_code_unit == PAD) pad_length++;
   }
   intptr_t decoded_en = ((len * 6) >> 3) - pad_length;
-  uint8_t* bytes = zone->Alloc<uint8_t>(decoded_en);
+  uint8_t* bytes = new uint8_t[decoded_en];
 
   for (int i = 0, o = 0; o < decoded_en;) {
     // Accumulate 4 valid 6 bit Base 64 characters into an int.
diff --git a/runtime/vm/base64.h b/runtime/vm/base64.h
index 575b61b..d2a80f3 100644
--- a/runtime/vm/base64.h
+++ b/runtime/vm/base64.h
@@ -5,11 +5,12 @@
 #ifndef RUNTIME_VM_BASE64_H_
 #define RUNTIME_VM_BASE64_H_
 
-#include "vm/zone.h"
+#include "platform/globals.h"
 
 namespace dart {
 
-uint8_t* DecodeBase64(Zone* zone, const char* str, intptr_t* out_decoded_len);
+// If non-null, the returned buffer has to be freed via delete[].
+uint8_t* DecodeBase64(const char* str, intptr_t* out_decoded_len);
 
 }  // namespace dart
 
diff --git a/runtime/vm/base64_test.cc b/runtime/vm/base64_test.cc
index 406a431..8bb8423 100644
--- a/runtime/vm/base64_test.cc
+++ b/runtime/vm/base64_test.cc
@@ -11,22 +11,21 @@
 
 TEST_CASE(Base64Decode) {
   intptr_t decoded_len;
-  uint8_t* decoded_bytes =
-      DecodeBase64(thread->zone(), "SGVsbG8sIHdvcmxkIQo=", &decoded_len);
+  uint8_t* decoded_bytes = DecodeBase64("SGVsbG8sIHdvcmxkIQo=", &decoded_len);
   const char expected_bytes[] = "Hello, world!\n";
   intptr_t expected_len = strlen(expected_bytes);
   EXPECT(!memcmp(expected_bytes, decoded_bytes, expected_len));
   EXPECT_EQ(expected_len, decoded_len);
+  delete[] decoded_bytes;
 }
 
 TEST_CASE(Base64DecodeMalformed) {
   intptr_t decoded_len;
-  EXPECT(DecodeBase64(thread->zone(), "SomethingMalformed", &decoded_len) ==
-         nullptr);
+  EXPECT(DecodeBase64("SomethingMalformed", &decoded_len) == nullptr);
 }
 
 TEST_CASE(Base64DecodeEmpty) {
   intptr_t decoded_len;
-  EXPECT(DecodeBase64(thread->zone(), "", &decoded_len) == nullptr);
+  EXPECT(DecodeBase64("", &decoded_len) == nullptr);
 }
 }  // namespace dart
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 8c05417..a1921bf 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -79,8 +79,15 @@
                                      intptr_t kernel_buffer_size) {
   Zone* zone = thread->zone();
   const char* error = nullptr;
-  kernel::Program* program = kernel::Program::ReadFromBuffer(
-      kernel_buffer, kernel_buffer_size, &error);
+
+  // NOTE: We do not attach a finalizer for this object, because the embedder
+  // will free it once the isolate has shutdown.
+  // (The embedder provides this buffer to [Dart_CreateIsolateFromKernel])
+  const auto& td = ExternalTypedData::Handle(ExternalTypedData::New(
+      kExternalTypedDataUint8ArrayCid, const_cast<uint8_t*>(kernel_buffer),
+      kernel_buffer_size, Heap::kOld));
+
+  kernel::Program* program = kernel::Program::ReadFromTypedData(td, &error);
   if (program == nullptr) {
     const intptr_t kMessageBufferSize = 512;
     char message_buffer[kMessageBufferSize];
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index dba74ea..b226d6e 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1591,11 +1591,19 @@
 
   void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
     Bytecode& bytecode = Bytecode::Handle(zone);
-    ExternalTypedData& binary = ExternalTypedData::Handle(zone);
+    TypedDataBase& binary = TypedDataBase::Handle(zone);
 
     for (intptr_t i = start_index_; i < stop_index_; i++) {
       bytecode ^= refs.At(i);
       binary = bytecode.GetBinary(zone);
+
+      // The deserialization cluster for kBytecodeCid might be before
+      // kTypedDataViewCids, which means the inner pointer might not have been
+      // updated yet.
+      if (binary.IsTypedDataView()) {
+        TypedDataView::Cast(binary).raw()->RecomputeDataField();
+      }
+
       bytecode.set_instructions(reinterpret_cast<uword>(
           binary.DataAddr(bytecode.instructions_binary_offset())));
     }
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index 690d873..602d55b 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -2164,7 +2164,7 @@
 
     KernelReaderHelper reader_helper(
         zone, &translation_helper, script,
-        ExternalTypedData::Handle(zone, function.KernelData()),
+        TypedDataBase::Handle(zone, function.KernelData()),
         function.KernelDataProgramOffset());
     ActiveClass active_class;
 
@@ -2202,7 +2202,7 @@
 
   KernelReaderHelper reader_helper(
       zone, &translation_helper, script,
-      ExternalTypedData::Handle(zone, annotation_field.KernelData()),
+      TypedDataBase::Handle(zone, annotation_field.KernelData()),
       annotation_field.KernelDataProgramOffset());
   ActiveClass active_class;
 
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h
index 701cc2d..05ee4c2 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.h
+++ b/runtime/vm/compiler/frontend/bytecode_reader.h
@@ -267,7 +267,7 @@
 class BytecodeSourcePositionsIterator : ValueObject {
  public:
   BytecodeSourcePositionsIterator(Zone* zone, const Bytecode& bytecode)
-      : reader_(ExternalTypedData::Handle(zone, bytecode.GetBinary(zone))),
+      : reader_(TypedDataBase::Handle(zone, bytecode.GetBinary(zone))),
         pairs_remaining_(0),
         pc_shifter_(
             Isolate::Current()->is_using_old_bytecode_instructions() ? 2 : 0),
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 706d2e6..590d0ef 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -225,8 +225,7 @@
     for (intptr_t i = 0; i < class_fields.Length(); ++i) {
       class_field ^= class_fields.At(i);
       if (!class_field.is_static()) {
-        ExternalTypedData& kernel_data =
-            ExternalTypedData::Handle(Z, class_field.KernelData());
+        auto& kernel_data = TypedDataBase::Handle(Z, class_field.KernelData());
         ASSERT(!kernel_data.IsNull());
         intptr_t field_offset = class_field.kernel_offset();
         AlternativeReadingScope alt(&reader_, &kernel_data, field_offset);
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index 2006924..cc489c0 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -22,7 +22,7 @@
 class StreamingFlowGraphBuilder : public KernelReaderHelper {
  public:
   StreamingFlowGraphBuilder(FlowGraphBuilder* flow_graph_builder,
-                            const ExternalTypedData& data,
+                            const TypedDataBase& data,
                             intptr_t data_program_offset)
       : KernelReaderHelper(
             flow_graph_builder->zone_,
diff --git a/runtime/vm/compiler/frontend/kernel_fingerprints.cc b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
index 2ac1adf..0680579e 100644
--- a/runtime/vm/compiler/frontend/kernel_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
@@ -18,7 +18,7 @@
   KernelFingerprintHelper(Zone* zone,
                           TranslationHelper* translation_helper,
                           const Script& script,
-                          const ExternalTypedData& data,
+                          const TypedDataBase& data,
                           intptr_t data_program_offset)
       : KernelReaderHelper(zone,
                            translation_helper,
@@ -838,7 +838,7 @@
 
   KernelFingerprintHelper helper(
       zone, &translation_helper, script,
-      ExternalTypedData::Handle(zone, field.KernelData()),
+      TypedDataBase::Handle(zone, field.KernelData()),
       field.KernelDataProgramOffset());
   helper.SetOffset(field.kernel_offset());
   return helper.CalculateFieldFingerprint();
@@ -853,10 +853,9 @@
   TranslationHelper translation_helper(thread);
   translation_helper.InitFromScript(script);
 
-  KernelFingerprintHelper helper(
-      zone, &translation_helper, script,
-      ExternalTypedData::Handle(zone, func.KernelData()),
-      func.KernelDataProgramOffset());
+  KernelFingerprintHelper helper(zone, &translation_helper, script,
+                                 TypedDataBase::Handle(zone, func.KernelData()),
+                                 func.KernelDataProgramOffset());
   helper.SetOffset(func.kernel_offset());
   return helper.CalculateFunctionFingerprint();
 }
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 6049959..485e7e7 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -724,7 +724,7 @@
 #endif
 
   StreamingFlowGraphBuilder streaming_flow_graph_builder(
-      this, ExternalTypedData::Handle(Z, function.KernelData()),
+      this, TypedDataBase::Handle(Z, function.KernelData()),
       function.KernelDataProgramOffset());
   return streaming_flow_graph_builder.BuildGraph();
 }
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 26f5476..9073d5c 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -27,10 +27,10 @@
       isolate_(thread->isolate()),
       allocation_space_(Heap::kNew),
       string_offsets_(TypedData::Handle(Z)),
-      string_data_(ExternalTypedData::Handle(Z)),
+      string_data_(TypedDataBase::Handle(Z)),
       canonical_names_(TypedData::Handle(Z)),
-      metadata_payloads_(ExternalTypedData::Handle(Z)),
-      metadata_mappings_(ExternalTypedData::Handle(Z)),
+      metadata_payloads_(TypedDataBase::Handle(Z)),
+      metadata_mappings_(TypedDataBase::Handle(Z)),
       constants_(Array::Handle(Z)),
       info_(KernelProgramInfo::Handle(Z)),
       name_index_handle_(Smi::Handle(Z)) {}
@@ -41,20 +41,20 @@
       isolate_(thread->isolate()),
       allocation_space_(space),
       string_offsets_(TypedData::Handle(Z)),
-      string_data_(ExternalTypedData::Handle(Z)),
+      string_data_(TypedDataBase::Handle(Z)),
       canonical_names_(TypedData::Handle(Z)),
-      metadata_payloads_(ExternalTypedData::Handle(Z)),
-      metadata_mappings_(ExternalTypedData::Handle(Z)),
+      metadata_payloads_(TypedDataBase::Handle(Z)),
+      metadata_mappings_(TypedDataBase::Handle(Z)),
       constants_(Array::Handle(Z)),
       info_(KernelProgramInfo::Handle(Z)),
       name_index_handle_(Smi::Handle(Z)) {}
 
 void TranslationHelper::Reset() {
   string_offsets_ = TypedData::null();
-  string_data_ = ExternalTypedData::null();
+  string_data_ = TypedDataBase::null();
   canonical_names_ = TypedData::null();
-  metadata_payloads_ = ExternalTypedData::null();
-  metadata_mappings_ = ExternalTypedData::null();
+  metadata_payloads_ = TypedDataBase::null();
+  metadata_mappings_ = TypedDataBase::null();
   constants_ = Array::null();
 }
 
@@ -74,10 +74,10 @@
 void TranslationHelper::InitFromKernelProgramInfo(
     const KernelProgramInfo& info) {
   SetStringOffsets(TypedData::Handle(Z, info.string_offsets()));
-  SetStringData(ExternalTypedData::Handle(Z, info.string_data()));
+  SetStringData(TypedDataBase::Handle(Z, info.string_data()));
   SetCanonicalNames(TypedData::Handle(Z, info.canonical_names()));
-  SetMetadataPayloads(ExternalTypedData::Handle(Z, info.metadata_payloads()));
-  SetMetadataMappings(ExternalTypedData::Handle(Z, info.metadata_mappings()));
+  SetMetadataPayloads(TypedDataBase::Handle(Z, info.metadata_payloads()));
+  SetMetadataMappings(TypedDataBase::Handle(Z, info.metadata_mappings()));
   SetConstants(Array::Handle(Z, info.constants()));
   SetKernelProgramInfo(info);
 }
@@ -97,7 +97,7 @@
   string_offsets_ = string_offsets.raw();
 }
 
-void TranslationHelper::SetStringData(const ExternalTypedData& string_data) {
+void TranslationHelper::SetStringData(const TypedDataBase& string_data) {
   ASSERT(string_data_.IsNull());
   string_data_ = string_data.raw();
 }
@@ -108,14 +108,14 @@
 }
 
 void TranslationHelper::SetMetadataPayloads(
-    const ExternalTypedData& metadata_payloads) {
+    const TypedDataBase& metadata_payloads) {
   ASSERT(metadata_payloads_.IsNull());
   ASSERT(Utils::IsAligned(metadata_payloads.DataAddr(0), kWordSize));
   metadata_payloads_ = metadata_payloads.raw();
 }
 
 void TranslationHelper::SetMetadataMappings(
-    const ExternalTypedData& metadata_mappings) {
+    const TypedDataBase& metadata_mappings) {
   ASSERT(metadata_mappings_.IsNull());
   metadata_mappings_ = metadata_mappings.raw();
 }
@@ -151,7 +151,7 @@
   // expression will try to return the address that is one past the backing
   // store of the string_data_ table.  Though this is safe in C++ as long as the
   // address is not dereferenced, it will trigger the assert in
-  // ExternalTypedData::DataAddr.
+  // TypedDataBase::DataAddr.
   ASSERT(Thread::Current()->no_safepoint_scope_depth() > 0);
   return reinterpret_cast<uint8_t*>(string_data_.DataAddr(0)) +
          StringOffset(string_index);
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 9508b70..eb3d31f 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -44,17 +44,17 @@
   const TypedData& string_offsets() { return string_offsets_; }
   void SetStringOffsets(const TypedData& string_offsets);
 
-  const ExternalTypedData& string_data() { return string_data_; }
-  void SetStringData(const ExternalTypedData& string_data);
+  const TypedDataBase& string_data() { return string_data_; }
+  void SetStringData(const TypedDataBase& string_data);
 
   const TypedData& canonical_names() { return canonical_names_; }
   void SetCanonicalNames(const TypedData& canonical_names);
 
-  const ExternalTypedData& metadata_payloads() { return metadata_payloads_; }
-  void SetMetadataPayloads(const ExternalTypedData& metadata_payloads);
+  const TypedDataBase& metadata_payloads() { return metadata_payloads_; }
+  void SetMetadataPayloads(const TypedDataBase& metadata_payloads);
 
-  const ExternalTypedData& metadata_mappings() { return metadata_mappings_; }
-  void SetMetadataMappings(const ExternalTypedData& metadata_mappings);
+  const TypedDataBase& metadata_mappings() { return metadata_mappings_; }
+  void SetMetadataMappings(const TypedDataBase& metadata_mappings);
 
   const Array& constants() { return constants_; }
   void SetConstants(const Array& constants);
@@ -200,10 +200,10 @@
   Heap::Space allocation_space_;
 
   TypedData& string_offsets_;
-  ExternalTypedData& string_data_;
+  TypedDataBase& string_data_;
   TypedData& canonical_names_;
-  ExternalTypedData& metadata_payloads_;
-  ExternalTypedData& metadata_mappings_;
+  TypedDataBase& metadata_payloads_;
+  TypedDataBase& metadata_mappings_;
   Array& constants_;
   KernelProgramInfo& info_;
   Smi& name_index_handle_;
@@ -967,7 +967,7 @@
   KernelReaderHelper(Zone* zone,
                      TranslationHelper* translation_helper,
                      const Script& script,
-                     const ExternalTypedData& data,
+                     const TypedDataBase& data,
                      intptr_t data_program_offset)
       : zone_(zone),
         translation_helper_(*translation_helper),
@@ -975,17 +975,6 @@
         script_(script),
         data_program_offset_(data_program_offset) {}
 
-  KernelReaderHelper(Zone* zone,
-                     TranslationHelper* translation_helper,
-                     const uint8_t* data_buffer,
-                     intptr_t buffer_length,
-                     intptr_t data_program_offset)
-      : zone_(zone),
-        translation_helper_(*translation_helper),
-        reader_(data_buffer, buffer_length),
-        script_(Script::Handle(zone_)),
-        data_program_offset_(data_program_offset) {}
-
   virtual ~KernelReaderHelper() = default;
 
   void SetOffset(intptr_t offset);
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index dde3667..e043d3c 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -57,8 +57,7 @@
           zone_,
           &translation_helper_,
           Script::Handle(Z, parsed_function->function().script()),
-          ExternalTypedData::Handle(Z,
-                                    parsed_function->function().KernelData()),
+          TypedDataBase::Handle(Z, parsed_function->function().KernelData()),
           parsed_function->function().KernelDataProgramOffset()),
       inferred_type_metadata_helper_(&helper_),
       procedure_attributes_metadata_helper_(&helper_),
@@ -185,8 +184,8 @@
           for (intptr_t i = 0; i < class_fields.Length(); ++i) {
             class_field ^= class_fields.At(i);
             if (!class_field.is_static()) {
-              ExternalTypedData& kernel_data =
-                  ExternalTypedData::Handle(Z, class_field.KernelData());
+              auto& kernel_data =
+                  TypedDataBase::Handle(Z, class_field.KernelData());
               ASSERT(!kernel_data.IsNull());
               intptr_t field_offset = class_field.kernel_offset();
               AlternativeReadingScope alt(&helper_.reader_, &kernel_data,
@@ -450,8 +449,7 @@
     for (intptr_t i = 0; i < class_fields.Length(); ++i) {
       class_field ^= class_fields.At(i);
       if (!class_field.is_static()) {
-        ExternalTypedData& kernel_data =
-            ExternalTypedData::Handle(Z, class_field.KernelData());
+        auto& kernel_data = TypedDataBase::Handle(Z, class_field.KernelData());
         ASSERT(!kernel_data.IsNull());
         intptr_t field_offset = class_field.kernel_offset();
         AlternativeReadingScope alt(&helper_.reader_, &kernel_data,
@@ -1705,8 +1703,7 @@
 StringIndex ScopeBuilder::GetNameFromVariableDeclaration(
     intptr_t kernel_offset,
     const Function& function) {
-  ExternalTypedData& kernel_data =
-      ExternalTypedData::Handle(Z, function.KernelData());
+  auto& kernel_data = TypedDataBase::Handle(Z, function.KernelData());
   ASSERT(!kernel_data.IsNull());
 
   // Temporarily go to the variable declaration, read the name.
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index d10c8c4..5a3cc98 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -243,10 +243,17 @@
     const uint8_t* kernel_bytes = compilation_result.kernel;
     intptr_t kernel_length = compilation_result.kernel_size;
 
+    const auto& kernel_td = ExternalTypedData::Handle(ExternalTypedData::New(
+        kExternalTypedDataUint8ArrayCid, const_cast<uint8_t*>(kernel_bytes),
+        kernel_length, Heap::kOld));
+    kernel_td.AddFinalizer(
+        const_cast<uint8_t*>(kernel_bytes),
+        [](void* _, Dart_WeakPersistentHandle h, void* peer) { free(peer); },
+        kernel_length);
+
     val = Instance::Cast(obj).EvaluateCompiledExpression(
-        receiver_cls, kernel_bytes, kernel_length, Array::empty_array(),
-        Array::empty_array(), TypeArguments::null_type_arguments());
-    free(const_cast<uint8_t*>(kernel_bytes));
+        receiver_cls, kernel_td, Array::empty_array(), Array::empty_array(),
+        TypeArguments::null_type_arguments());
   }
   EXPECT(!val.IsNull());
   EXPECT(!val.IsError());
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 7f7a646..16abbaa 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -5045,9 +5045,14 @@
   // instead of freelists.
   BumpAllocateScope bump_allocate_scope(T);
 
+  // NOTE: We do not attach a finalizer for this object, because the embedder
+  // will free it once the isolate has shutdown.
+  const auto& td = ExternalTypedData::Handle(ExternalTypedData::New(
+      kExternalTypedDataUint8ArrayCid, const_cast<uint8_t*>(buffer),
+      buffer_size, Heap::kOld));
+
   const char* error = nullptr;
-  kernel::Program* program =
-      kernel::Program::ReadFromBuffer(buffer, buffer_size, &error);
+  kernel::Program* program = kernel::Program::ReadFromTypedData(td, &error);
   if (program == nullptr) {
     return Api::NewError("Can't load Kernel binary: %s.", error);
   }
@@ -5291,9 +5296,15 @@
   // instead of freelists.
   BumpAllocateScope bump_allocate_scope(T);
 
+  // NOTE: We do not attach a finalizer for this object, because the embedder
+  // will/should free it once the isolate has shutdown.
+  // See also http://dartbug.com/37030.
+  const auto& td = ExternalTypedData::Handle(ExternalTypedData::New(
+      kExternalTypedDataUint8ArrayCid, const_cast<uint8_t*>(buffer),
+      buffer_size, Heap::kOld));
+
   const char* error = nullptr;
-  kernel::Program* program =
-      kernel::Program::ReadFromBuffer(buffer, buffer_size, &error);
+  kernel::Program* program = kernel::Program::ReadFromTypedData(td, &error);
   if (program == nullptr) {
     return Api::NewError("Can't load Kernel binary: %s.", error);
   }
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 13e4621..e84a517 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -1294,16 +1294,14 @@
 }
 
 RawObject* ActivationFrame::EvaluateCompiledExpression(
-    const uint8_t* kernel_bytes,
-    intptr_t kernel_length,
+    const ExternalTypedData& kernel_td,
     const Array& type_definitions,
     const Array& arguments,
     const TypeArguments& type_arguments) {
   if (function().is_static()) {
     const Class& cls = Class::Handle(function().Owner());
-    return cls.EvaluateCompiledExpression(kernel_bytes, kernel_length,
-                                          type_definitions, arguments,
-                                          type_arguments);
+    return cls.EvaluateCompiledExpression(kernel_td, type_definitions,
+                                          arguments, type_arguments);
   } else {
     const Object& receiver = Object::Handle(GetReceiver());
     const Class& method_cls = Class::Handle(function().origin());
@@ -1312,9 +1310,8 @@
       return Object::null();
     }
     const Instance& inst = Instance::Cast(receiver);
-    return inst.EvaluateCompiledExpression(method_cls, kernel_bytes,
-                                           kernel_length, type_definitions,
-                                           arguments, type_arguments);
+    return inst.EvaluateCompiledExpression(
+        method_cls, kernel_td, type_definitions, arguments, type_arguments);
   }
 }
 
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index 05230cd..2541c2d 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -332,8 +332,7 @@
       const GrowableObjectArray& param_values,
       const GrowableObjectArray& type_params_names);
 
-  RawObject* EvaluateCompiledExpression(const uint8_t* kernel_bytes,
-                                        intptr_t kernel_length,
+  RawObject* EvaluateCompiledExpression(const ExternalTypedData& kernel_td,
                                         const Array& arguments,
                                         const Array& type_definitions,
                                         const TypeArguments& type_arguments);
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index e9a303f..0072067 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -192,16 +192,24 @@
 
     const uint8_t* kernel_bytes = compilation_result.kernel;
     intptr_t kernel_length = compilation_result.kernel_size;
+
+    const auto& kernel_td = ExternalTypedData::Handle(ExternalTypedData::New(
+        kExternalTypedDataUint8ArrayCid, const_cast<uint8_t*>(kernel_bytes),
+        kernel_length, Heap::kOld));
+    kernel_td.AddFinalizer(
+        const_cast<uint8_t*>(kernel_bytes),
+        [](void* _, Dart_WeakPersistentHandle h, void* peer) { free(peer); },
+        kernel_length);
+
     Dart_Handle result = Api::NewHandle(
         T,
-        lib.EvaluateCompiledExpression(kernel_bytes, kernel_length,
+        lib.EvaluateCompiledExpression(kernel_td,
                                        /* type_definitions= */
                                        Array::empty_array(),
                                        /* param_values= */
                                        Array::empty_array(),
                                        /* type_param_values= */
                                        TypeArguments::null_type_arguments()));
-    free(const_cast<uint8_t*>(kernel_bytes));
     return result;
   }
 }
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index ba66dcd..4d4f057 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2,6 +2,8 @@
 // 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.
 
+#include <utility>
+
 #include "vm/isolate.h"
 
 #include "include/dart_api.h"
@@ -902,7 +904,6 @@
       tag_table_(GrowableObjectArray::null()),
       deoptimized_code_array_(GrowableObjectArray::null()),
       sticky_error_(Error::null()),
-      reloaded_kernel_blobs_(GrowableObjectArray::null()),
       field_list_mutex_(NOT_IN_PRODUCT("Isolate::field_list_mutex_")),
       boxed_field_list_(GrowableObjectArray::null()),
       spawn_count_monitor_(),
@@ -1115,14 +1116,6 @@
   return result;
 }
 
-void Isolate::RetainKernelBlob(const ExternalTypedData& kernel_blob) {
-  if (reloaded_kernel_blobs_ == Object::null()) {
-    reloaded_kernel_blobs_ = GrowableObjectArray::New();
-  }
-  auto& kernel_blobs = GrowableObjectArray::Handle(reloaded_kernel_blobs_);
-  kernel_blobs.Add(kernel_blob);
-}
-
 Thread* Isolate::mutator_thread() const {
   ASSERT(thread_registry() != nullptr);
   return thread_registry()->mutator_thread();
@@ -1939,7 +1932,6 @@
   visitor->VisitPointer(
       reinterpret_cast<RawObject**>(&deoptimized_code_array_));
   visitor->VisitPointer(reinterpret_cast<RawObject**>(&sticky_error_));
-  visitor->VisitPointer(reinterpret_cast<RawObject**>(&reloaded_kernel_blobs_));
 #if !defined(PRODUCT)
   visitor->VisitPointer(
       reinterpret_cast<RawObject**>(&pending_service_extension_calls_));
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 914a40f..0fa13bd 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -613,8 +613,6 @@
   RawError* sticky_error() const { return sticky_error_; }
   DART_WARN_UNUSED_RESULT RawError* StealStickyError();
 
-  void RetainKernelBlob(const ExternalTypedData& kernel_blob);
-
   bool compilation_allowed() const {
     return CompilationAllowedBit::decode(isolate_flags_);
   }
@@ -1035,12 +1033,6 @@
 
   RawError* sticky_error_;
 
-  // Issue(dartbug.com/33973): We keep a reference to [ExternalTypedData]s with
-  // finalizers to ensure we keep the hot-reloaded kernel blobs alive.
-  //
-  // -> We should get rid of this field once Issue 33973 is fixed.
-  RawGrowableObjectArray* reloaded_kernel_blobs_;
-
   // Isolate list next pointer.
   Isolate* next_ = nullptr;
 
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 2cd529b..5717e48 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -612,7 +612,8 @@
     kernel_program.set(kernel::Program::ReadFromFile(root_script_url));
     if (kernel_program.get() != NULL) {
       num_received_libs_ = kernel_program.get()->library_count();
-      bytes_received_libs_ = kernel_program.get()->kernel_data_size();
+      bytes_received_libs_ =
+          kernel_program.get()->kernel_data().LengthInBytes();
       p_num_received_classes = &num_received_classes_;
       p_num_received_procedures = &num_received_procedures_;
     } else {
@@ -662,13 +663,6 @@
              void* data) { free(data); },
           retval.kernel_size);
 
-      // TODO(dartbug.com/33973): Change the heap objects to have a proper
-      // retaining path to the kernel blob and ensure the finalizer will free it
-      // once there are no longer references to it.
-      // (The [ExternalTypedData] currently referenced by e.g. functions point
-      // into the middle of c-allocated buffer and don't have a finalizer).
-      I->RetainKernelBlob(typed_data);
-
       kernel_program.set(kernel::Program::ReadFromTypedData(typed_data));
     }
 
diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc
index a4a6eea..5c5b1ab 100644
--- a/runtime/vm/kernel.cc
+++ b/runtime/vm/kernel.cc
@@ -28,7 +28,7 @@
 
   KernelReaderHelper kernel_reader_helper(
       zone, &translation_helper, Script::Handle(zone, field.Script()),
-      ExternalTypedData::Handle(zone, field.KernelData()),
+      TypedDataBase::Handle(zone, field.KernelData()),
       field.KernelDataProgramOffset());
   kernel_reader_helper.SetOffset(field.kernel_offset());
   kernel::FieldHelper field_helper(&kernel_reader_helper);
@@ -148,7 +148,7 @@
       Zone* zone,
       TranslationHelper* translation_helper,
       const Script& script,
-      const ExternalTypedData& data,
+      const TypedDataBase& data,
       intptr_t data_program_offset,
       intptr_t initial_script_index,
       intptr_t record_for_script_id,
@@ -257,7 +257,7 @@
 }
 
 static void ProcessTokenPositionsEntry(
-    const ExternalTypedData& kernel_data,
+    const TypedDataBase& kernel_data,
     const Script& script,
     const Script& entry_script,
     intptr_t kernel_offset,
@@ -293,7 +293,7 @@
   Library& lib = Library::Handle(zone);
   Object& entry = Object::Handle(zone);
   Script& entry_script = Script::Handle(zone);
-  ExternalTypedData& data = ExternalTypedData::Handle(zone);
+  TypedDataBase& data = TypedDataBase::Handle(zone);
 
   auto& temp_array = Array::Handle(zone);
   auto& temp_field = Field::Handle(zone);
@@ -304,7 +304,7 @@
     DictionaryIterator it(lib);
     while (it.HasNext()) {
       entry = it.GetNext();
-      data = ExternalTypedData::null();
+      data = TypedDataBase::null();
       if (entry.IsClass()) {
         const Class& klass = Class::Cast(entry);
         if (klass.script() == interesting_script.raw()) {
@@ -416,7 +416,7 @@
   MetadataEvaluator(Zone* zone,
                     TranslationHelper* translation_helper,
                     const Script& script,
-                    const ExternalTypedData& data,
+                    const TypedDataBase& data,
                     intptr_t data_program_offset,
                     ActiveClass* active_class)
       : KernelReaderHelper(zone,
@@ -480,7 +480,7 @@
 
     MetadataEvaluator metadata_evaluator(
         zone, &helper, script,
-        ExternalTypedData::Handle(zone, metadata_field.KernelData()),
+        TypedDataBase::Handle(zone, metadata_field.KernelData()),
         metadata_field.KernelDataProgramOffset(), &active_class);
 
     return metadata_evaluator.EvaluateMetadata(metadata_field.kernel_offset(),
@@ -496,7 +496,7 @@
   ParameterDescriptorBuilder(TranslationHelper* translation_helper,
                              const Script& script,
                              Zone* zone,
-                             const ExternalTypedData& data,
+                             const TypedDataBase& data,
                              intptr_t data_program_offset,
                              ActiveClass* active_class)
       : KernelReaderHelper(zone,
@@ -589,7 +589,7 @@
 
     ParameterDescriptorBuilder builder(
         &helper, Script::Handle(zone, function.script()), zone,
-        ExternalTypedData::Handle(zone, function.KernelData()),
+        TypedDataBase::Handle(zone, function.KernelData()),
         function.KernelDataProgramOffset(), &active_class);
 
     return builder.BuildParameterDescriptor(function.kernel_offset());
@@ -614,7 +614,7 @@
 
   KernelReaderHelper reader_helper(
       zone, &translation_helper, script,
-      ExternalTypedData::Handle(zone, function.KernelData()),
+      TypedDataBase::Handle(zone, function.KernelData()),
       function.KernelDataProgramOffset());
 
   if (function.is_declared_in_bytecode()) {
@@ -710,7 +710,7 @@
 static ProcedureAttributesMetadata ProcedureAttributesOf(
     Zone* zone,
     const Script& script,
-    const ExternalTypedData& kernel_data,
+    const TypedDataBase& kernel_data,
     intptr_t kernel_data_program_offset,
     intptr_t kernel_offset) {
   TranslationHelper translation_helper(Thread::Current());
@@ -729,7 +729,7 @@
                                                   Zone* zone) {
   const Script& script = Script::Handle(zone, function.script());
   return ProcedureAttributesOf(
-      zone, script, ExternalTypedData::Handle(zone, function.KernelData()),
+      zone, script, TypedDataBase::Handle(zone, function.KernelData()),
       function.KernelDataProgramOffset(), function.kernel_offset());
 }
 
@@ -738,7 +738,7 @@
   const Class& parent = Class::Handle(zone, field.Owner());
   const Script& script = Script::Handle(zone, parent.script());
   return ProcedureAttributesOf(
-      zone, script, ExternalTypedData::Handle(zone, field.KernelData()),
+      zone, script, TypedDataBase::Handle(zone, field.KernelData()),
       field.KernelDataProgramOffset(), field.kernel_offset());
 }
 
diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h
index 0de9d5d..d9a5ca1 100644
--- a/runtime/vm/kernel.h
+++ b/runtime/vm/kernel.h
@@ -66,9 +66,6 @@
 
   static Program* ReadFromFile(const char* script_uri,
                                const char** error = nullptr);
-  static Program* ReadFromBuffer(const uint8_t* buffer,
-                                 intptr_t buffer_length,
-                                 const char** error = nullptr);
   static Program* ReadFromTypedData(const ExternalTypedData& typed_data,
                                     const char** error = nullptr);
 
@@ -85,12 +82,12 @@
     return metadata_mappings_offset_;
   }
   intptr_t constant_table_offset() { return constant_table_offset_; }
-  const uint8_t* kernel_data() { return kernel_data_; }
-  intptr_t kernel_data_size() { return kernel_data_size_; }
   intptr_t library_count() { return library_count_; }
 
+  const TypedDataBase& kernel_data() const { return *kernel_data_; }
+
  private:
-  Program() : kernel_data_(NULL), kernel_data_size_(-1) {}
+  Program() : kernel_data_(NULL) {}
 
   bool single_program_;
   uint32_t binary_version_;
@@ -115,8 +112,8 @@
   // The offset from the start of the binary to the start of the string table.
   intptr_t string_table_offset_;
 
-  const uint8_t* kernel_data_;
-  intptr_t kernel_data_size_;
+  // The kernel buffer for this program.
+  const TypedDataBase* kernel_data_;
 
   DISALLOW_COPY_AND_ASSIGN(Program);
 };
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index d3f2838..ae850f3 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -78,8 +78,8 @@
 
   Program* program = new Program();
   program->binary_version_ = formatVersion;
-  program->kernel_data_ = reader->buffer();
-  program->kernel_data_size_ = reader->size();
+  program->kernel_data_ =
+      &TypedDataBase::ZoneHandle(reader->typed_data()->raw());
 
   // Dill files can be concatenated (e.g. cat a.dill b.dill > c.dill). Find out
   // if this dill contains more than one program.
@@ -126,45 +126,25 @@
   if (script_uri == NULL) {
     return NULL;
   }
-  kernel::Program* kernel_program = NULL;
 
   const String& uri = String::Handle(String::New(script_uri));
   const Object& ret = Object::Handle(thread->isolate()->CallTagHandler(
       Dart_kKernelTag, Object::null_object(), uri));
-  Api::Scope api_scope(thread);
-  Dart_Handle retval = Api::NewHandle(thread, ret.raw());
-  {
+  if (ret.IsError()) {
+    Api::Scope api_scope(thread);
+    Dart_Handle retval = Api::NewHandle(thread, ret.raw());
     TransitionVMToNative transition(thread);
-    if (!Dart_IsError(retval)) {
-      Dart_TypedData_Type data_type;
-      uint8_t* data;
-      ASSERT(Dart_IsTypedData(retval));
-
-      uint8_t* kernel_buffer;
-      intptr_t kernel_buffer_size;
-      Dart_Handle val = Dart_TypedDataAcquireData(
-          retval, &data_type, reinterpret_cast<void**>(&data),
-          &kernel_buffer_size);
-      ASSERT(!Dart_IsError(val));
-      ASSERT(data_type == Dart_TypedData_kUint8);
-      kernel_buffer = reinterpret_cast<uint8_t*>(malloc(kernel_buffer_size));
-      memmove(kernel_buffer, data, kernel_buffer_size);
-      Dart_TypedDataReleaseData(retval);
-
-      kernel_program = kernel::Program::ReadFromBuffer(
-          kernel_buffer, kernel_buffer_size, error);
-    } else if (error != nullptr) {
+    if (error != nullptr) {
       *error = Dart_GetError(retval);
     }
+    return nullptr;
   }
-  return kernel_program;
-}
 
-Program* Program::ReadFromBuffer(const uint8_t* buffer,
-                                 intptr_t buffer_length,
-                                 const char** error) {
-  kernel::Reader reader(buffer, buffer_length);
-  return kernel::Program::ReadFrom(&reader, error);
+  // NOTE: We require the embedder to supply an external typed data (with a
+  // finalizer) so we can simply use it and don't need to make a copy.
+  RELEASE_ASSERT(ret.IsExternalTypedData());
+  const auto& td = ExternalTypedData::Cast(ret);
+  return kernel::Program::ReadFromTypedData(td, error);
 }
 
 Program* Program::ReadFromTypedData(const ExternalTypedData& typed_data,
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index 760c6ac..2da794b 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -170,19 +170,23 @@
 
 class Reader : public ValueObject {
  public:
-  Reader(const uint8_t* buffer, intptr_t size)
-      : thread_(NULL),
-        raw_buffer_(buffer),
-        typed_data_(NULL),
-        size_(size),
-        offset_(0) {}
-
-  explicit Reader(const ExternalTypedData& typed_data)
+  explicit Reader(const TypedDataBase& typed_data)
       : thread_(Thread::Current()),
-        raw_buffer_(NULL),
         typed_data_(&typed_data),
         size_(typed_data.IsNull() ? 0 : typed_data.Length()),
-        offset_(0) {}
+        offset_(0) {
+    // The reader expects that the actual data is external, though allows
+    // having a view into this external typed data.
+#if defined(DEBUG)
+    if (typed_data_->IsTypedDataView()) {
+      const auto& backing_store =
+          TypedDataBase::Handle(TypedDataView::Cast(*typed_data_).typed_data());
+      ASSERT(backing_store.IsExternalTypedData());
+    } else {
+      ASSERT(typed_data_->IsExternalTypedData());
+    }
+#endif
+  }
 
   uint32_t ReadFromIndex(intptr_t end_offset,
                          intptr_t fields_before,
@@ -198,11 +202,7 @@
   uint32_t ReadUInt32At(intptr_t offset) const {
     ASSERT((size_ >= 4) && (offset >= 0) && (offset <= size_ - 4));
     uint32_t value;
-    if (raw_buffer_ != NULL) {
-      value = *reinterpret_cast<const uint32_t*>(raw_buffer_ + offset);
-    } else {
-      value = typed_data_->GetUint32(offset);
-    }
+    value = typed_data_->GetUint32(offset);
     return Utils::BigEndianToHost32(value);
   }
 
@@ -347,20 +347,11 @@
   intptr_t size() const { return size_; }
   void set_size(intptr_t size) { size_ = size; }
 
-  const ExternalTypedData* typed_data() const { return typed_data_; }
-  void set_typed_data(const ExternalTypedData* typed_data) {
+  const TypedDataBase* typed_data() const { return typed_data_; }
+  void set_typed_data(const TypedDataBase* typed_data) {
     typed_data_ = typed_data;
   }
 
-  const uint8_t* raw_buffer() const { return raw_buffer_; }
-  void set_raw_buffer(const uint8_t* raw_buffer) { raw_buffer_ = raw_buffer; }
-
-  RawExternalTypedData* ExternalDataFromTo(intptr_t start, intptr_t end) {
-    return ExternalTypedData::New(kExternalTypedDataUint8ArrayCid,
-                                  const_cast<uint8_t*>(buffer() + start),
-                                  end - start, Heap::kOld);
-  }
-
   const uint8_t* BufferAt(intptr_t offset) {
     ASSERT((offset >= 0) && (offset < size_));
     return &buffer()[offset];
@@ -368,16 +359,12 @@
 
  private:
   const uint8_t* buffer() const {
-    if (raw_buffer_ != NULL) {
-      return raw_buffer_;
-    }
     NoSafepointScope no_safepoint(thread_);
     return reinterpret_cast<uint8_t*>(typed_data_->DataAddr(0));
   }
 
   Thread* thread_;
-  const uint8_t* raw_buffer_;
-  const ExternalTypedData* typed_data_;
+  const TypedDataBase* typed_data_;
   intptr_t size_;
   intptr_t offset_;
   TokenPosition max_position_;
@@ -395,21 +382,18 @@
   AlternativeReadingScope(Reader* reader, intptr_t new_position)
       : reader_(reader),
         saved_size_(reader_->size()),
-        saved_raw_buffer_(reader_->raw_buffer()),
         saved_typed_data_(reader_->typed_data()),
         saved_offset_(reader_->offset()) {
     reader_->set_offset(new_position);
   }
 
   AlternativeReadingScope(Reader* reader,
-                          const ExternalTypedData* new_typed_data,
+                          const TypedDataBase* new_typed_data,
                           intptr_t new_position)
       : reader_(reader),
         saved_size_(reader_->size()),
-        saved_raw_buffer_(reader_->raw_buffer()),
         saved_typed_data_(reader_->typed_data()),
         saved_offset_(reader_->offset()) {
-    reader_->set_raw_buffer(NULL);
     reader_->set_typed_data(new_typed_data);
     reader_->set_size(new_typed_data->Length());
     reader_->set_offset(new_position);
@@ -418,12 +402,10 @@
   explicit AlternativeReadingScope(Reader* reader)
       : reader_(reader),
         saved_size_(reader_->size()),
-        saved_raw_buffer_(reader_->raw_buffer()),
         saved_typed_data_(reader_->typed_data()),
         saved_offset_(reader_->offset()) {}
 
   ~AlternativeReadingScope() {
-    reader_->set_raw_buffer(saved_raw_buffer_);
     reader_->set_typed_data(saved_typed_data_);
     reader_->set_size(saved_size_);
     reader_->set_offset(saved_offset_);
@@ -434,8 +416,7 @@
  private:
   Reader* reader_;
   intptr_t saved_size_;
-  const uint8_t* saved_raw_buffer_;
-  const ExternalTypedData* saved_typed_data_;
+  const TypedDataBase* saved_typed_data_;
   intptr_t saved_offset_;
 
   DISALLOW_COPY_AND_ASSIGN(AlternativeReadingScope);
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 962d878..9c89a2d 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -143,7 +143,7 @@
   return loader_->LookupClass(library_lookup_handle_, klass);
 }
 
-LibraryIndex::LibraryIndex(const ExternalTypedData& kernel_data,
+LibraryIndex::LibraryIndex(const TypedDataBase& kernel_data,
                            int32_t binary_version)
     : reader_(kernel_data), binary_version_(binary_version) {
   intptr_t data_size = reader_.size();
@@ -160,15 +160,7 @@
   }
 }
 
-ClassIndex::ClassIndex(const uint8_t* buffer,
-                       intptr_t buffer_size,
-                       intptr_t class_offset,
-                       intptr_t class_size)
-    : reader_(buffer, buffer_size) {
-  Init(class_offset, class_size);
-}
-
-ClassIndex::ClassIndex(const ExternalTypedData& library_kernel_data,
+ClassIndex::ClassIndex(const TypedDataBase& library_kernel_data,
                        intptr_t class_offset,
                        intptr_t class_size)
     : reader_(library_kernel_data) {
@@ -193,13 +185,13 @@
       library_kernel_offset_(-1),  // Set to the correct value in LoadLibrary
       correction_offset_(-1),      // Set to the correct value in LoadLibrary
       loading_native_wrappers_library_(false),
-      library_kernel_data_(ExternalTypedData::ZoneHandle(zone_)),
+      library_kernel_data_(TypedDataBase::ZoneHandle(zone_)),
       kernel_program_info_(KernelProgramInfo::ZoneHandle(zone_)),
       translation_helper_(this, thread_, Heap::kOld),
       helper_(zone_,
               &translation_helper_,
-              program_->kernel_data(),
-              program_->kernel_data_size(),
+              Script::Handle(thread_->zone()),
+              program->kernel_data(),
               0),
       type_translator_(&helper_, &active_class_, /* finalize= */ false),
       inferred_type_metadata_helper_(&helper_),
@@ -236,9 +228,11 @@
     return Object::Handle(loader.LoadProgram(process_pending_classes));
   }
 
-  kernel::Reader reader(program->kernel_data(), program->kernel_data_size());
   GrowableArray<intptr_t> subprogram_file_starts;
-  index_programs(&reader, &subprogram_file_starts);
+  {
+    kernel::Reader reader(program->kernel_data());
+    index_programs(&reader, &subprogram_file_starts);
+  }
 
   Zone* zone = thread->zone();
   Library& library = Library::Handle(zone);
@@ -247,15 +241,19 @@
   // First index all source tables.
   UriToSourceTable uri_to_source_table;
   UriToSourceTableEntry wrapper;
+  auto& subprogram_view = TypedDataView::Handle(zone);
   for (intptr_t i = subprogram_count - 1; i >= 0; --i) {
     intptr_t subprogram_start = subprogram_file_starts.At(i);
     intptr_t subprogram_end = subprogram_file_starts.At(i + 1);
     Thread* thread_ = Thread::Current();
     Zone* zone_ = thread_->zone();
     TranslationHelper translation_helper(thread);
-    KernelReaderHelper helper_(zone_, &translation_helper,
-                               program->kernel_data() + subprogram_start,
-                               subprogram_end - subprogram_start, 0);
+
+    subprogram_view = program->kernel_data().CreateUint8View(
+        subprogram_start, subprogram_end - subprogram_start);
+
+    KernelReaderHelper helper_(zone_, &translation_helper, Script::Handle(),
+                               subprogram_view, 0);
     const intptr_t source_table_size = helper_.SourceTableSize();
     for (intptr_t index = 0; index < source_table_size; ++index) {
       const String& uri_string = helper_.SourceTableUriFor(index);
@@ -287,11 +285,13 @@
 
   // Create "fake programs" for each sub-program.
   for (intptr_t i = subprogram_count - 1; i >= 0; --i) {
-    intptr_t subprogram_start = subprogram_file_starts.At(i);
-    intptr_t subprogram_end = subprogram_file_starts.At(i + 1);
-    reader.set_raw_buffer(program->kernel_data() + subprogram_start);
-    reader.set_size(subprogram_end - subprogram_start);
-    reader.set_offset(0);
+    const intptr_t subprogram_start = subprogram_file_starts.At(i);
+    const intptr_t subprogram_end = subprogram_file_starts.At(i + 1);
+
+    subprogram_view = program->kernel_data().CreateUint8View(
+        subprogram_start, subprogram_end - subprogram_start);
+
+    kernel::Reader reader(subprogram_view);
     Program* subprogram = Program::ReadFrom(&reader);
     ASSERT(subprogram->is_single_program());
     KernelLoader loader(subprogram, &uri_to_source_table);
@@ -334,14 +334,13 @@
   subprogram_file_starts->Reverse();
 }
 
-RawString* KernelLoader::FindSourceForScript(const uint8_t* kernel_buffer,
-                                             intptr_t kernel_buffer_length,
+RawString* KernelLoader::FindSourceForScript(const ExternalTypedData& kernel_td,
                                              const String& uri) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
   TranslationHelper translation_helper(thread);
-  KernelReaderHelper reader(zone, &translation_helper, kernel_buffer,
-                            kernel_buffer_length, 0);
+  KernelReaderHelper reader(zone, &translation_helper, Script::Handle(zone),
+                            kernel_td, 0);
   intptr_t source_table_size = reader.SourceTableSize();
   for (intptr_t i = 0; i < source_table_size; ++i) {
     const String& source_uri = reader.SourceTableUriFor(i);
@@ -360,7 +359,7 @@
 
   // Copy the Kernel string offsets out of the binary and into the VM's heap.
   ASSERT(program_->string_table_offset() >= 0);
-  Reader reader(program_->kernel_data(), program_->kernel_data_size());
+  Reader reader(program_->kernel_data());
   reader.set_offset(program_->string_table_offset());
   intptr_t count = reader.ReadUInt() + 1;
   TypedData& offsets = TypedData::Handle(
@@ -372,16 +371,18 @@
     offsets.SetUint32(i << 2, end_offset);
   }
 
+  const auto& kernel_data = *reader.typed_data();
+
   // Create view of the string data.
-  const ExternalTypedData& data = ExternalTypedData::Handle(
-      Z,
-      reader.ExternalDataFromTo(reader.offset(), reader.offset() + end_offset));
+  const auto& data = TypedDataBase::Handle(
+      Z, kernel_data.CreateUint8View(reader.offset(), end_offset));
 
   // Create a view of the constants table. The trailing ComponentIndex is
   // negligible in size.
-  const ExternalTypedData& constants_table = ExternalTypedData::Handle(
-      Z, reader.ExternalDataFromTo(program_->constant_table_offset(),
-                                   program_->kernel_data_size()));
+  const auto& constants_table = TypedDataBase::Handle(
+      Z, kernel_data.CreateUint8View(
+             program_->constant_table_offset(),
+             kernel_data.LengthInBytes() - program_->constant_table_offset()));
 
   // Copy the canonical names into the VM's heap.  Encode them as unsigned, so
   // the parent indexes are adjusted when extracted.
@@ -394,15 +395,18 @@
   }
 
   // Create view of metadata payloads.
-  const ExternalTypedData& metadata_payloads = ExternalTypedData::Handle(
-      Z, reader.ExternalDataFromTo(program_->metadata_payloads_offset(),
-                                   program_->metadata_mappings_offset()));
+  const auto& metadata_payloads = TypedDataBase::Handle(
+      Z, kernel_data.CreateUint8View(program_->metadata_payloads_offset(),
+                                     program_->metadata_mappings_offset() -
+                                         program_->metadata_payloads_offset()));
+
   ASSERT(Utils::IsAligned(metadata_payloads.DataAddr(0), kWordSize));
 
   // Create view of metadata mappings.
-  const ExternalTypedData& metadata_mappings = ExternalTypedData::Handle(
-      Z, reader.ExternalDataFromTo(program_->metadata_mappings_offset(),
-                                   program_->string_table_offset()));
+  const auto& metadata_mappings = TypedDataBase::Handle(
+      Z, kernel_data.CreateUint8View(program_->metadata_mappings_offset(),
+                                     program_->string_table_offset() -
+                                         program_->metadata_mappings_offset()));
 
   const Array& libraries_cache =
       Array::Handle(Z, HashTables::New<UnorderedHashMap<SmiTraits>>(
@@ -431,7 +435,7 @@
 }
 
 KernelLoader::KernelLoader(const Script& script,
-                           const ExternalTypedData& kernel_data,
+                           const TypedDataBase& kernel_data,
                            intptr_t data_program_offset)
     : program_(NULL),
       thread_(Thread::Current()),
@@ -441,7 +445,7 @@
       library_kernel_offset_(data_program_offset),
       correction_offset_(0),
       loading_native_wrappers_library_(false),
-      library_kernel_data_(ExternalTypedData::ZoneHandle(zone_)),
+      library_kernel_data_(TypedDataBase::ZoneHandle(zone_)),
       kernel_program_info_(
           KernelProgramInfo::ZoneHandle(zone_, script.kernel_program_info())),
       translation_helper_(this, thread_, Heap::kOld),
@@ -759,7 +763,7 @@
     //     c) update all scripts with the constants array
     ASSERT(kernel_program_info_.constants() == Array::null());
     kernel_program_info_.set_constants(constants);
-    kernel_program_info_.set_constants_table(ExternalTypedData::Handle(Z));
+    kernel_program_info_.set_constants_table(TypedDataBase::Handle(Z));
 
     //     d) evaluate pending field initializers
     Error& error = Error::Handle(Z);
@@ -825,8 +829,8 @@
 
   // Make the expression evaluation function have the right kernel data and
   // parent.
-  auto& eval_data = ExternalTypedData::Handle(
-      Z, expression_evaluation_library_.kernel_data());
+  auto& eval_data =
+      TypedDataBase::Handle(Z, expression_evaluation_library_.kernel_data());
   auto& eval_script =
       Script::Handle(Z, expression_evaluation_function_.script());
   expression_evaluation_function_.SetKernelDataAndScript(
@@ -877,18 +881,24 @@
       loader.walk_incremental_kernel(modified_libs, is_empty_program,
                                      p_num_classes, p_num_procedures);
     }
-    kernel::Reader reader(program->kernel_data(), program->kernel_data_size());
+
     GrowableArray<intptr_t> subprogram_file_starts;
-    index_programs(&reader, &subprogram_file_starts);
+    {
+      kernel::Reader reader(program->kernel_data());
+      index_programs(&reader, &subprogram_file_starts);
+    }
 
     // Create "fake programs" for each sub-program.
     intptr_t subprogram_count = subprogram_file_starts.length() - 1;
+    auto& subprogram_view = TypedDataView::Handle(zone);
     for (intptr_t i = 0; i < subprogram_count; ++i) {
       intptr_t subprogram_start = subprogram_file_starts.At(i);
       intptr_t subprogram_end = subprogram_file_starts.At(i + 1);
-      reader.set_raw_buffer(program->kernel_data() + subprogram_start);
-      reader.set_size(subprogram_end - subprogram_start);
-      reader.set_offset(0);
+
+      subprogram_view = program->kernel_data().CreateUint8View(
+          subprogram_start, subprogram_end - subprogram_start);
+
+      kernel::Reader reader(subprogram_view);
       Program* subprogram = Program::ReadFrom(&reader);
       ASSERT(subprogram->is_single_program());
       KernelLoader loader(subprogram, /*uri_to_source_table=*/nullptr);
@@ -922,8 +932,8 @@
     }
     if (collect_library_stats) {
       intptr_t library_end = library_offset(i + 1);
-      library_kernel_data_ =
-          helper_.reader_.ExternalDataFromTo(kernel_offset, library_end);
+      library_kernel_data_ = helper_.reader_.typed_data()->CreateUint8View(
+          kernel_offset, library_end - kernel_offset);
 
       LibraryIndex library_index(library_kernel_data_,
                                  program_->binary_version());
@@ -1012,8 +1022,8 @@
   ASSERT(!library_helper.IsExternal() || library.Loaded());
   if (library.Loaded()) return library.raw();
 
-  library_kernel_data_ = helper_.reader_.ExternalDataFromTo(
-      library_kernel_offset_, library_kernel_offset_ + library_size);
+  library_kernel_data_ = helper_.reader_.typed_data()->CreateUint8View(
+      library_kernel_offset_, library_size);
   library.set_kernel_data(library_kernel_data_);
   library.set_kernel_offset(library_kernel_offset_);
 
@@ -1389,8 +1399,8 @@
                              intptr_t class_end,
                              Class* out_class) {
   intptr_t class_offset = helper_.ReaderOffset();
-  ClassIndex class_index(program_->kernel_data(), program_->kernel_data_size(),
-                         class_offset, class_end - class_offset);
+  ClassIndex class_index(program_->kernel_data(), class_offset,
+                         class_end - class_offset);
 
   ClassHelper class_helper(&helper_);
   class_helper.ReadUntilIncluding(ClassHelper::kCanonicalName);
@@ -1689,8 +1699,8 @@
   const Script& script = Script::Handle(zone, klass.script());
   const Library& library = Library::Handle(zone, klass.library());
   const Class& toplevel_class = Class::Handle(zone, library.toplevel_class());
-  const ExternalTypedData& library_kernel_data =
-      ExternalTypedData::Handle(zone, library.kernel_data());
+  const TypedDataBase& library_kernel_data =
+      TypedDataBase::Handle(zone, library.kernel_data());
   ASSERT(!library_kernel_data.IsNull());
   const intptr_t library_kernel_offset = library.kernel_offset();
   ASSERT(library_kernel_offset > 0);
@@ -1766,8 +1776,7 @@
         // constants in the annotation list to later.
         *is_potential_native = true;
 
-        ASSERT(kernel_program_info_.constants_table() !=
-               ExternalTypedData::null());
+        ASSERT(kernel_program_info_.constants_table() != TypedDataBase::null());
 
         // For pragma annotations, we seek into the constants table and peek
         // into the Kernel representation of the constant.
@@ -1785,8 +1794,7 @@
 
         AlternativeReadingScope scope(
             &helper_.reader_,
-            &ExternalTypedData::Handle(Z,
-                                       kernel_program_info_.constants_table()),
+            &TypedDataBase::Handle(Z, kernel_program_info_.constants_table()),
             0);
 
         // Seek into the position within the constant table where we can inspect
@@ -2266,7 +2274,7 @@
       PatchClass::Handle(zone, PatchClass::New(field_owner, script));
   const Library& lib = Library::Handle(zone, field_owner.library());
   initializer_owner.set_library_kernel_data(
-      ExternalTypedData::Handle(zone, lib.kernel_data()));
+      TypedDataBase::Handle(zone, lib.kernel_data()));
   initializer_owner.set_library_kernel_offset(lib.kernel_offset());
 
   // Create a static initializer.
diff --git a/runtime/vm/kernel_loader.h b/runtime/vm/kernel_loader.h
index 79c58b6..e0cd207 100644
--- a/runtime/vm/kernel_loader.h
+++ b/runtime/vm/kernel_loader.h
@@ -84,7 +84,7 @@
   // |kernel_data| is the kernel data for one library alone.
   // binary_version can be -1 in which case some parts of the index might not
   // be read.
-  explicit LibraryIndex(const ExternalTypedData& kernel_data,
+  explicit LibraryIndex(const TypedDataBase& kernel_data,
                         int32_t binary_version);
 
   intptr_t class_count() const { return class_count_; }
@@ -130,16 +130,9 @@
 
 class ClassIndex {
  public:
-  // |class_offset| is the offset of class' kernel data in |buffer| of
-  // size |size|. The size of the class' kernel data is |class_size|.
-  ClassIndex(const uint8_t* buffer,
-             intptr_t buffer_size,
-             intptr_t class_offset,
-             intptr_t class_size);
-
   // |class_offset| is the offset of class' kernel data in |kernel_data|.
   // The size of the class' kernel data is |class_size|.
-  ClassIndex(const ExternalTypedData& kernel_data,
+  ClassIndex(const TypedDataBase& kernel_data,
              intptr_t class_offset,
              intptr_t class_size);
 
@@ -215,8 +208,7 @@
                                     intptr_t* p_num_classes,
                                     intptr_t* p_num_procedures);
 
-  static RawString* FindSourceForScript(const uint8_t* kernel_buffer,
-                                        intptr_t kernel_buffer_length,
+  static RawString* FindSourceForScript(const ExternalTypedData& kernel_td,
                                         const String& url);
 
   RawLibrary* LoadLibrary(intptr_t index);
@@ -265,16 +257,14 @@
   }
 
   intptr_t library_offset(intptr_t index) {
-    kernel::Reader reader(program_->kernel_data(),
-                          program_->kernel_data_size());
+    kernel::Reader reader(program_->kernel_data());
     return reader.ReadFromIndexNoReset(reader.size(),
                                        LibraryCountFieldCountFromEnd + 1,
                                        program_->library_count() + 1, index);
   }
 
   NameIndex library_canonical_name(intptr_t index) {
-    kernel::Reader reader(program_->kernel_data(),
-                          program_->kernel_data_size());
+    kernel::Reader reader(program_->kernel_data());
     reader.set_offset(library_offset(index));
 
     // Start reading library.
@@ -288,7 +278,7 @@
   friend class BuildingTranslationHelper;
 
   KernelLoader(const Script& script,
-               const ExternalTypedData& kernel_data,
+               const TypedDataBase& kernel_data,
                intptr_t data_program_offset);
 
   void InitializeFields(
@@ -411,7 +401,7 @@
 
   NameIndex skip_vmservice_library_;
 
-  ExternalTypedData& library_kernel_data_;
+  TypedDataBase& library_kernel_data_;
   KernelProgramInfo& kernel_program_info_;
   BuildingTranslationHelper translation_helper_;
   KernelReaderHelper helper_;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index bbad5ca..eb7824b 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -3540,8 +3540,7 @@
 }
 
 static RawObject* EvaluateCompiledExpressionHelper(
-    const uint8_t* kernel_bytes,
-    intptr_t kernel_length,
+    const ExternalTypedData& kernel_data,
     const Array& type_definitions,
     const String& library_url,
     const String& klass,
@@ -3549,8 +3548,7 @@
     const TypeArguments& type_arguments);
 
 RawObject* Class::EvaluateCompiledExpression(
-    const uint8_t* kernel_bytes,
-    intptr_t kernel_length,
+    const ExternalTypedData& kernel_data,
     const Array& type_definitions,
     const Array& arguments,
     const TypeArguments& type_arguments) const {
@@ -3563,7 +3561,7 @@
   }
 
   return EvaluateCompiledExpressionHelper(
-      kernel_bytes, kernel_length, type_definitions,
+      kernel_data, type_definitions,
       String::Handle(Library::Handle(library()).url()),
       IsTopLevel() ? String::Handle() : String::Handle(UserVisibleName()),
       arguments, type_arguments);
@@ -4013,8 +4011,7 @@
   if (scr.kind() == RawScript::kKernelTag) {
     ASSERT(kernel_offset() > 0);
     const Library& lib = Library::Handle(zone, library());
-    const ExternalTypedData& kernel_data =
-        ExternalTypedData::Handle(zone, lib.kernel_data());
+    const auto& kernel_data = TypedDataBase::Handle(zone, lib.kernel_data());
     ASSERT(!kernel_data.IsNull());
     const intptr_t library_kernel_offset = lib.kernel_offset();
     ASSERT(library_kernel_offset > 0);
@@ -5628,7 +5625,7 @@
   StorePointer(&raw_ptr()->script_, value.raw());
 }
 
-void PatchClass::set_library_kernel_data(const ExternalTypedData& data) const {
+void PatchClass::set_library_kernel_data(const TypedDataBase& data) const {
   StorePointer(&raw_ptr()->library_kernel_data_, data.raw());
 }
 
@@ -7693,7 +7690,7 @@
 }
 
 void Function::SetKernelDataAndScript(const Script& script,
-                                      const ExternalTypedData& data,
+                                      const TypedDataBase& data,
                                       intptr_t offset) {
   Array& data_field = Array::Handle(Array::New(3));
   data_field.SetAt(0, script);
@@ -7735,12 +7732,12 @@
   return Class::Cast(obj).script();
 }
 
-RawExternalTypedData* Function::KernelData() const {
+RawTypedDataBase* Function::KernelData() const {
   Object& data = Object::Handle(raw_ptr()->data_);
   if (data.IsArray()) {
     Object& script = Object::Handle(Array::Cast(data).At(0));
     if (script.IsScript()) {
-      return ExternalTypedData::RawCast(Array::Cast(data).At(1));
+      return TypedDataBase::RawCast(Array::Cast(data).At(1));
     }
   }
   if (IsClosureFunction()) {
@@ -8363,7 +8360,7 @@
   return PatchClass::Cast(obj).script();
 }
 
-RawExternalTypedData* Field::KernelData() const {
+RawTypedDataBase* Field::KernelData() const {
   const Object& obj = Object::Handle(this->raw_ptr()->owner_);
   // During background JIT compilation field objects are copied
   // and copy points to the original field via the owner field.
@@ -9204,11 +9201,10 @@
 }
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-void Script::LoadSourceFromKernel(const uint8_t* kernel_buffer,
-                                  intptr_t kernel_buffer_len) const {
+void Script::LoadSourceFromKernel(const ExternalTypedData& kernel_td) const {
   String& uri = String::Handle(resolved_url());
-  String& source = String::Handle(kernel::KernelLoader::FindSourceForScript(
-      kernel_buffer, kernel_buffer_len, uri));
+  String& source =
+      String::Handle(kernel::KernelLoader::FindSourceForScript(kernel_td, uri));
   set_source(source);
 }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
@@ -9784,7 +9780,7 @@
   StorePointer(&raw_ptr()->url_, name.raw());
 }
 
-void Library::set_kernel_data(const ExternalTypedData& data) const {
+void Library::set_kernel_data(const TypedDataBase& data) const {
   StorePointer(&raw_ptr()->kernel_data_, data.raw());
 }
 
@@ -11182,14 +11178,13 @@
 }
 
 RawObject* Library::EvaluateCompiledExpression(
-    const uint8_t* kernel_bytes,
-    intptr_t kernel_length,
+    const ExternalTypedData& kernel_data,
     const Array& type_definitions,
     const Array& arguments,
     const TypeArguments& type_arguments) const {
   return EvaluateCompiledExpressionHelper(
-      kernel_bytes, kernel_length, type_definitions, String::Handle(url()),
-      String::Handle(), arguments, type_arguments);
+      kernel_data, type_definitions, String::Handle(url()), String::Handle(),
+      arguments, type_arguments);
 }
 
 void Library::InitNativeWrappersLibrary(Isolate* isolate, bool is_kernel) {
@@ -11247,8 +11242,7 @@
 typedef UnorderedHashMap<LibraryLookupTraits> LibraryLookupMap;
 
 static RawObject* EvaluateCompiledExpressionHelper(
-    const uint8_t* kernel_bytes,
-    intptr_t kernel_length,
+    const ExternalTypedData& kernel_td,
     const Array& type_definitions,
     const String& library_url,
     const String& klass,
@@ -11259,8 +11253,7 @@
       String::New("Expression evaluation not available in precompiled mode."));
   return ApiError::New(error_str);
 #else
-  kernel::Program* kernel_pgm =
-      kernel::Program::ReadFromBuffer(kernel_bytes, kernel_length);
+  kernel::Program* kernel_pgm = kernel::Program::ReadFromTypedData(kernel_td);
 
   if (kernel_pgm == NULL) {
     return ApiError::New(String::Handle(
@@ -12027,11 +12020,11 @@
 
 RawKernelProgramInfo* KernelProgramInfo::New(
     const TypedData& string_offsets,
-    const ExternalTypedData& string_data,
+    const TypedDataBase& string_data,
     const TypedData& canonical_names,
-    const ExternalTypedData& metadata_payloads,
-    const ExternalTypedData& metadata_mappings,
-    const ExternalTypedData& constants_table,
+    const TypedDataBase& metadata_payload,
+    const TypedDataBase& metadata_mappings,
+    const TypedDataBase& constants_table,
     const Array& scripts,
     const Array& libraries_cache,
     const Array& classes_cache) {
@@ -12041,7 +12034,7 @@
   info.StorePointer(&info.raw_ptr()->string_data_, string_data.raw());
   info.StorePointer(&info.raw_ptr()->canonical_names_, canonical_names.raw());
   info.StorePointer(&info.raw_ptr()->metadata_payloads_,
-                    metadata_payloads.raw());
+                    metadata_payload.raw());
   info.StorePointer(&info.raw_ptr()->metadata_mappings_,
                     metadata_mappings.raw());
   info.StorePointer(&info.raw_ptr()->scripts_, scripts.raw());
@@ -12069,8 +12062,7 @@
   StorePointer(&raw_ptr()->constants_, constants.raw());
 }
 
-void KernelProgramInfo::set_constants_table(
-    const ExternalTypedData& value) const {
+void KernelProgramInfo::set_constants_table(const TypedDataBase& value) const {
   StorePointer(&raw_ptr()->constants_table_, value.raw());
 }
 
@@ -15134,10 +15126,10 @@
   return result.raw();
 }
 
-RawExternalTypedData* Bytecode::GetBinary(Zone* zone) const {
+RawTypedDataBase* Bytecode::GetBinary(Zone* zone) const {
   const Function& func = Function::Handle(zone, function());
   if (func.IsNull()) {
-    return ExternalTypedData::null();
+    return TypedDataBase::null();
   }
   const Script& script = Script::Handle(zone, func.script());
   const KernelProgramInfo& info =
@@ -16103,8 +16095,7 @@
 
 RawObject* Instance::EvaluateCompiledExpression(
     const Class& method_cls,
-    const uint8_t* kernel_bytes,
-    intptr_t kernel_length,
+    const ExternalTypedData& kernel_data,
     const Array& type_definitions,
     const Array& arguments,
     const TypeArguments& type_arguments) const {
@@ -16118,7 +16109,7 @@
   }
 
   return EvaluateCompiledExpressionHelper(
-      kernel_bytes, kernel_length, type_definitions,
+      kernel_data, type_definitions,
       String::Handle(Library::Handle(method_cls.library()).url()),
       String::Handle(method_cls.UserVisibleName()), arguments_with_receiver,
       type_arguments);
@@ -21139,6 +21130,20 @@
   return nullptr;
 }
 
+RawTypedDataView* TypedDataBase::CreateUint8View(intptr_t offset_in_bytes,
+                                                 intptr_t length_in_bytes,
+                                                 Heap::Space space) const {
+  auto& backing_store = TypedDataBase::Handle(raw());
+  if (IsTypedDataView()) {
+    const auto& this_view = TypedDataView::Cast(*this);
+    offset_in_bytes += ValueFromRawSmi(this_view.offset_in_bytes());
+    backing_store = this_view.typed_data();
+  }
+  ASSERT((offset_in_bytes + length_in_bytes) <= backing_store.LengthInBytes());
+  return TypedDataView::New(kTypedDataUint8ArrayViewCid, backing_store,
+                            offset_in_bytes, length_in_bytes, space);
+}
+
 const char* TypedDataView::ToCString() const {
   auto zone = Thread::Current()->zone();
   return OS::SCreate(zone, "TypedDataView(cid: %" Pd ")", GetClassId());
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 499939e..d9cf880 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1235,8 +1235,7 @@
   // (type_)param_names, and is invoked with the (type)argument values given in
   // (type_)param_values.
   RawObject* EvaluateCompiledExpression(
-      const uint8_t* kernel_bytes,
-      intptr_t kernel_length,
+      const ExternalTypedData& kernel_data,
       const Array& type_definitions,
       const Array& param_values,
       const TypeArguments& type_param_values) const;
@@ -1463,10 +1462,10 @@
   RawClass* patched_class() const { return raw_ptr()->patched_class_; }
   RawClass* origin_class() const { return raw_ptr()->origin_class_; }
   RawScript* script() const { return raw_ptr()->script_; }
-  RawExternalTypedData* library_kernel_data() const {
+  RawTypedDataBase* library_kernel_data() const {
     return raw_ptr()->library_kernel_data_;
   }
-  void set_library_kernel_data(const ExternalTypedData& data) const;
+  void set_library_kernel_data(const TypedDataBase& data) const;
 
   intptr_t library_kernel_offset() const {
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -2525,12 +2524,12 @@
   }
 
   void SetKernelDataAndScript(const Script& script,
-                              const ExternalTypedData& data,
+                              const TypedDataBase& data,
                               intptr_t offset);
 
   intptr_t KernelDataProgramOffset() const;
 
-  RawExternalTypedData* KernelData() const;
+  RawTypedDataBase* KernelData() const;
 
   bool IsOptimizable() const;
   void SetIsOptimizable(bool value) const;
@@ -3302,7 +3301,7 @@
 
   void InheritBinaryDeclarationFrom(const Field& src) const;
 
-  RawExternalTypedData* KernelData() const;
+  RawTypedDataBase* KernelData() const;
 
   intptr_t KernelDataProgramOffset() const;
 
@@ -3721,8 +3720,7 @@
                         RawScript::Kind kind);
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-  void LoadSourceFromKernel(const uint8_t* kernel_buffer,
-                            intptr_t kernel_buffer_len) const;
+  void LoadSourceFromKernel(const ExternalTypedData& kernel_td) const;
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
  private:
@@ -3850,8 +3848,7 @@
   // parameters given in (type_)param_names, and is invoked with the (type)
   // argument values given in (type_)param_values.
   RawObject* EvaluateCompiledExpression(
-      const uint8_t* kernel_bytes,
-      intptr_t kernel_length,
+      const ExternalTypedData& kernel_data,
       const Array& type_definitions,
       const Array& param_values,
       const TypeArguments& type_param_values) const;
@@ -4002,8 +3999,8 @@
 
   inline intptr_t UrlHash() const;
 
-  RawExternalTypedData* kernel_data() const { return raw_ptr()->kernel_data_; }
-  void set_kernel_data(const ExternalTypedData& data) const;
+  RawTypedDataBase* kernel_data() const { return raw_ptr()->kernel_data_; }
+  void set_kernel_data(const TypedDataBase& data) const;
 
   intptr_t kernel_offset() const {
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -4190,11 +4187,11 @@
 class KernelProgramInfo : public Object {
  public:
   static RawKernelProgramInfo* New(const TypedData& string_offsets,
-                                   const ExternalTypedData& string_data,
+                                   const TypedDataBase& string_data,
                                    const TypedData& canonical_names,
-                                   const ExternalTypedData& metadata_payload,
-                                   const ExternalTypedData& metadata_mappings,
-                                   const ExternalTypedData& constants_table,
+                                   const TypedDataBase& metadata_payload,
+                                   const TypedDataBase& metadata_mappings,
+                                   const TypedDataBase& constants_table,
                                    const Array& scripts,
                                    const Array& libraries_cache,
                                    const Array& classes_cache);
@@ -4205,23 +4202,23 @@
 
   RawTypedData* string_offsets() const { return raw_ptr()->string_offsets_; }
 
-  RawExternalTypedData* string_data() const { return raw_ptr()->string_data_; }
+  RawTypedDataBase* string_data() const { return raw_ptr()->string_data_; }
 
   RawTypedData* canonical_names() const { return raw_ptr()->canonical_names_; }
 
-  RawExternalTypedData* metadata_payloads() const {
+  RawTypedDataBase* metadata_payloads() const {
     return raw_ptr()->metadata_payloads_;
   }
 
-  RawExternalTypedData* metadata_mappings() const {
+  RawTypedDataBase* metadata_mappings() const {
     return raw_ptr()->metadata_mappings_;
   }
 
-  RawExternalTypedData* constants_table() const {
+  RawTypedDataBase* constants_table() const {
     return raw_ptr()->constants_table_;
   }
 
-  void set_constants_table(const ExternalTypedData& value) const;
+  void set_constants_table(const TypedDataBase& value) const;
 
   RawArray* scripts() const { return raw_ptr()->scripts_; }
   void set_scripts(const Array& scripts) const;
@@ -5486,7 +5483,7 @@
                           intptr_t instructions_offset,
                           const ObjectPool& object_pool);
 
-  RawExternalTypedData* GetBinary(Zone* zone) const;
+  RawTypedDataBase* GetBinary(Zone* zone) const;
 
   TokenPosition GetTokenIndexOfPC(uword pc) const;
 
@@ -6069,8 +6066,7 @@
   // argument values given in (type_)param_values.
   RawObject* EvaluateCompiledExpression(
       const Class& method_cls,
-      const uint8_t* kernel_bytes,
-      intptr_t kernel_length,
+      const ExternalTypedData& kernel_data,
       const Array& type_definitions,
       const Array& param_values,
       const TypeArguments& type_param_values) const;
@@ -8421,6 +8417,19 @@
     return element_size(ElementType(raw()->GetClassId()));
   }
 
+  void* DataAddr(intptr_t byte_offset) const {
+    ASSERT(byte_offset == 0 ||
+           (byte_offset > 0 && byte_offset < LengthInBytes()));
+#if defined(DEBUG)
+    ValidateInvariant();
+#endif
+    return reinterpret_cast<void*>(raw_ptr()->data_ + byte_offset);
+  }
+
+  RawTypedDataView* CreateUint8View(intptr_t offset_in_bytes,
+                                    intptr_t length_in_bytes,
+                                    Heap::Space space = Heap::kNew) const;
+
   static intptr_t ElementSizeInBytes(classid_t cid) {
     return element_size(ElementType(cid));
   }
@@ -8444,12 +8453,45 @@
     }
   }
 
+#define TYPED_GETTER_SETTER(name, type)                                        \
+  type Get##name(intptr_t byte_offset) const {                                 \
+    ASSERT(byte_offset >= 0 &&                                                 \
+           (byte_offset + static_cast<intptr_t>(sizeof(type)) - 1) <           \
+               LengthInBytes());                                               \
+    return ReadUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset)));      \
+  }                                                                            \
+  void Set##name(intptr_t byte_offset, type value) const {                     \
+    ASSERT(byte_offset >= 0 &&                                                 \
+           (byte_offset + static_cast<intptr_t>(sizeof(type)) - 1) <           \
+               LengthInBytes());                                               \
+    NoSafepointScope no_safepoint;                                             \
+    StoreUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset)), value);     \
+  }
+
+  TYPED_GETTER_SETTER(Int8, int8_t)
+  TYPED_GETTER_SETTER(Uint8, uint8_t)
+  TYPED_GETTER_SETTER(Int16, int16_t)
+  TYPED_GETTER_SETTER(Uint16, uint16_t)
+  TYPED_GETTER_SETTER(Int32, int32_t)
+  TYPED_GETTER_SETTER(Uint32, uint32_t)
+  TYPED_GETTER_SETTER(Int64, int64_t)
+  TYPED_GETTER_SETTER(Uint64, uint64_t)
+  TYPED_GETTER_SETTER(Float32, float)
+  TYPED_GETTER_SETTER(Float64, double)
+  TYPED_GETTER_SETTER(Float32x4, simd128_value_t)
+  TYPED_GETTER_SETTER(Int32x4, simd128_value_t)
+  TYPED_GETTER_SETTER(Float64x2, simd128_value_t)
+
+#undef TYPED_GETTER_SETTER
+
  protected:
   void SetLength(intptr_t value) const {
     ASSERT(value <= Smi::kMaxValue);
     StoreSmi(&raw_ptr()->length_, Smi::New(value));
   }
 
+  virtual void ValidateInvariant() const {}
+
  private:
   friend class Class;
 
@@ -8473,44 +8515,9 @@
   // architecture.
   static const intptr_t kHashBits = 30;
 
-  void* DataAddr(intptr_t byte_offset) const {
-    ASSERT((byte_offset == 0) ||
-           ((byte_offset > 0) && (byte_offset < LengthInBytes())));
-    return reinterpret_cast<void*>(UnsafeMutableNonPointer(raw_ptr()->data()) +
-                                   byte_offset);
-  }
-
   virtual bool CanonicalizeEquals(const Instance& other) const;
   virtual uint32_t CanonicalizeHash() const;
 
-#define TYPED_GETTER_SETTER(name, type)                                        \
-  type Get##name(intptr_t byte_offset) const {                                 \
-    ASSERT((byte_offset >= 0) &&                                               \
-           (byte_offset + static_cast<intptr_t>(sizeof(type)) - 1) <           \
-               LengthInBytes());                                               \
-    return ReadUnaligned(ReadOnlyDataAddr<type>(byte_offset));                 \
-  }                                                                            \
-  void Set##name(intptr_t byte_offset, type value) const {                     \
-    NoSafepointScope no_safepoint;                                             \
-    StoreUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset)), value);     \
-  }
-
-  TYPED_GETTER_SETTER(Int8, int8_t)
-  TYPED_GETTER_SETTER(Uint8, uint8_t)
-  TYPED_GETTER_SETTER(Int16, int16_t)
-  TYPED_GETTER_SETTER(Uint16, uint16_t)
-  TYPED_GETTER_SETTER(Int32, int32_t)
-  TYPED_GETTER_SETTER(Uint32, uint32_t)
-  TYPED_GETTER_SETTER(Int64, int64_t)
-  TYPED_GETTER_SETTER(Uint64, uint64_t)
-  TYPED_GETTER_SETTER(Float32, float)
-  TYPED_GETTER_SETTER(Float64, double)
-  TYPED_GETTER_SETTER(Float32x4, simd128_value_t)
-  TYPED_GETTER_SETTER(Int32x4, simd128_value_t)
-  TYPED_GETTER_SETTER(Float64x2, simd128_value_t)
-
-#undef TYPED_GETTER_SETTER
-
   static intptr_t data_offset() { return RawTypedData::payload_offset(); }
 
   static intptr_t InstanceSize() {
@@ -8595,6 +8602,10 @@
  protected:
   void RecomputeDataField() { raw()->RecomputeDataField(); }
 
+  virtual void ValidateInvariant() const {
+    ASSERT(raw_ptr()->data_ == raw_ptr()->internal_data());
+  }
+
  private:
   // Provides const access to non-pointer, non-aligned data within the object.
   // Such access does not need a write barrier, but it is *not* GC-safe, since
@@ -8620,35 +8631,6 @@
   // snapshot. Should be independent of word size.
   static const int kDataSerializationAlignment = 8;
 
-  void* DataAddr(intptr_t byte_offset) const {
-    ASSERT((byte_offset == 0) ||
-           ((byte_offset > 0) && (byte_offset < LengthInBytes())));
-    return reinterpret_cast<void*>(raw_ptr()->data_ + byte_offset);
-  }
-
-#define TYPED_GETTER_SETTER(name, type)                                        \
-  type Get##name(intptr_t byte_offset) const {                                 \
-    return ReadUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset)));      \
-  }                                                                            \
-  void Set##name(intptr_t byte_offset, type value) const {                     \
-    StoreUnaligned(reinterpret_cast<type*>(DataAddr(byte_offset)), value);     \
-  }
-  TYPED_GETTER_SETTER(Int8, int8_t)
-  TYPED_GETTER_SETTER(Uint8, uint8_t)
-  TYPED_GETTER_SETTER(Int16, int16_t)
-  TYPED_GETTER_SETTER(Uint16, uint16_t)
-  TYPED_GETTER_SETTER(Int32, int32_t)
-  TYPED_GETTER_SETTER(Uint32, uint32_t)
-  TYPED_GETTER_SETTER(Int64, int64_t)
-  TYPED_GETTER_SETTER(Uint64, uint64_t)
-  TYPED_GETTER_SETTER(Float32, float)
-  TYPED_GETTER_SETTER(Float64, double)
-  TYPED_GETTER_SETTER(Float32x4, simd128_value_t)
-  TYPED_GETTER_SETTER(Int32x4, simd128_value_t)
-  TYPED_GETTER_SETTER(Float64x2, simd128_value_t)
-
-#undef TYPED_GETTER_SETTER
-
   FinalizablePersistentHandle* AddFinalizer(
       void* peer,
       Dart_WeakPersistentHandleFinalizer callback,
@@ -8733,7 +8715,7 @@
     return OFFSET_OF(RawTypedDataView, offset_in_bytes_);
   }
 
-  RawInstance* typed_data() const { return raw_ptr()->typed_data_; }
+  RawTypedDataBase* typed_data() const { return raw_ptr()->typed_data_; }
 
   void InitializeWith(const TypedDataBase& typed_data,
                       intptr_t offset_in_bytes,
@@ -8751,6 +8733,9 @@
 
   RawSmi* offset_in_bytes() const { return raw_ptr()->offset_in_bytes_; }
 
+ protected:
+  virtual void ValidateInvariant() const { raw()->ValidateInnerPointer(); }
+
  private:
   void RecomputeDataField() { raw()->RecomputeDataField(); }
 
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index f9eb462..dd6cc87 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -362,7 +362,7 @@
       PatchClass::Handle(PatchClass::New(*this, Script::Handle(script())));
   ASSERT(!patch.IsNull());
   const Library& lib = Library::Handle(library());
-  patch.set_library_kernel_data(ExternalTypedData::Handle(lib.kernel_data()));
+  patch.set_library_kernel_data(TypedDataBase::Handle(lib.kernel_data()));
   patch.set_library_kernel_offset(lib.kernel_offset());
 
   const Array& funcs = Array::Handle(functions());
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 75e7a92..2325fa2 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -812,7 +812,7 @@
   RawClass* patched_class_;
   RawClass* origin_class_;
   RawScript* script_;
-  RawExternalTypedData* library_kernel_data_;
+  RawTypedDataBase* library_kernel_data_;
   VISIT_TO(RawObject*, library_kernel_data_);
 
   RawObject** to_snapshot(Snapshot::Kind kind) {
@@ -1154,7 +1154,7 @@
   RawArray* imports_;        // List of Namespaces imported without prefix.
   RawArray* exports_;        // List of re-exported Namespaces.
   RawInstance* load_error_;  // Error iff load_state_ == kLoadError.
-  RawExternalTypedData* kernel_data_;
+  RawTypedDataBase* kernel_data_;
   RawObject** to_snapshot(Snapshot::Kind kind) {
     switch (kind) {
       case Snapshot::kFullAOT:
@@ -1209,16 +1209,16 @@
 
   VISIT_FROM(RawObject*, string_offsets_);
   RawTypedData* string_offsets_;
-  RawExternalTypedData* string_data_;
+  RawTypedDataBase* string_data_;
   RawTypedData* canonical_names_;
-  RawExternalTypedData* metadata_payloads_;
-  RawExternalTypedData* metadata_mappings_;
+  RawTypedDataBase* metadata_payloads_;
+  RawTypedDataBase* metadata_mappings_;
   RawArray* scripts_;
   RawArray* constants_;
   RawArray* bytecode_component_;
   RawGrowableObjectArray* potential_natives_;
   RawGrowableObjectArray* potential_pragma_functions_;
-  RawExternalTypedData* constants_table_;
+  RawTypedDataBase* constants_table_;
   RawArray* libraries_cache_;
   RawArray* classes_cache_;
   VISIT_TO(RawObject*, classes_cache_);
@@ -2080,6 +2080,7 @@
 
  private:
   friend class RawTypedDataView;
+  friend class TypedDataView;
   RAW_HEAP_OBJECT_IMPLEMENTATION(TypedDataBase);
 };
 
@@ -2135,8 +2136,8 @@
     ptr()->data_ = payload + offset_in_bytes;
   }
 
-  // Recopute [data_] based on internal [typed_data_] - needs to be called by GC
-  // whenever the backing store moved.
+  // Recompute [data_] based on internal [typed_data_] - needs to be called by
+  // GC whenever the backing store moved.
   //
   // NOTICE: This method assumes [this] is the forwarded object and the
   // [typed_data_] pointer points to the new backing store. The backing store's
@@ -2148,7 +2149,7 @@
     ptr()->data_ = payload + offset_in_bytes;
   }
 
-  void ValidateInnerPointer() {
+  void ValidateInnerPointer() const {
     if (ptr()->typed_data_->GetClassId() == kNullCid) {
       // The view object must have gotten just initialized.
       if (ptr()->data_ != nullptr ||
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 50ba1c5..1532bf9 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -2878,7 +2878,17 @@
 
   intptr_t kernel_length;
   const char* kernel_bytes_str = js->LookupParam("kernelBytes");
-  uint8_t* kernel_bytes = DecodeBase64(zone, kernel_bytes_str, &kernel_length);
+  uint8_t* kernel_bytes = DecodeBase64(kernel_bytes_str, &kernel_length);
+
+  const auto& kernel_td = ExternalTypedData::Handle(
+      ExternalTypedData::New(kExternalTypedDataUint8ArrayCid, kernel_bytes,
+                             kernel_length, Heap::kOld));
+  kernel_td.AddFinalizer(
+      kernel_bytes,
+      [](void* _, Dart_WeakPersistentHandle h, void* peer) {
+        delete[] reinterpret_cast<uint8_t*>(peer);
+      },
+      kernel_length);
 
   if (js->HasParam("frameIndex")) {
     DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
@@ -2896,7 +2906,7 @@
     const Object& result = Object::Handle(
         zone,
         frame->EvaluateCompiledExpression(
-            kernel_bytes, kernel_length,
+            kernel_td,
             Array::Handle(zone, Array::MakeFixedLength(type_params_names)),
             Array::Handle(zone, Array::MakeFixedLength(param_values)),
             type_arguments));
@@ -2929,7 +2939,7 @@
       const Object& result = Object::Handle(
           zone,
           lib.EvaluateCompiledExpression(
-              kernel_bytes, kernel_length,
+              kernel_td,
               Array::Handle(zone, Array::MakeFixedLength(type_params_names)),
               Array::Handle(zone, Array::MakeFixedLength(param_values)),
               type_arguments));
@@ -2941,7 +2951,7 @@
       const Object& result = Object::Handle(
           zone,
           cls.EvaluateCompiledExpression(
-              kernel_bytes, kernel_length,
+              kernel_td,
               Array::Handle(zone, Array::MakeFixedLength(type_params_names)),
               Array::Handle(zone, Array::MakeFixedLength(param_values)),
               type_arguments));
@@ -2956,7 +2966,7 @@
       const Object& result = Object::Handle(
           zone,
           instance.EvaluateCompiledExpression(
-              receiver_cls, kernel_bytes, kernel_length,
+              receiver_cls, kernel_td,
               Array::Handle(zone, Array::MakeFixedLength(type_params_names)),
               Array::Handle(zone, Array::MakeFixedLength(param_values)),
               type_arguments));
@@ -4395,7 +4405,16 @@
         const uint8_t* kernel_buffer = Service::dart_library_kernel();
         const intptr_t kernel_buffer_len =
             Service::dart_library_kernel_length();
-        script.LoadSourceFromKernel(kernel_buffer, kernel_buffer_len);
+
+        // NOTE: We do not add a finalizer to this buffer since the embedder
+        // will free it once the VM shuts down (it was provided via
+        // [Dart_SetDartLibrarySourcesKernel]).
+        const auto& kernel_td = ExternalTypedData::Handle(
+            ExternalTypedData::New(kExternalTypedDataUint8ArrayCid,
+                                   const_cast<uint8_t*>(kernel_buffer),
+                                   kernel_buffer_len, Heap::kOld));
+
+        script.LoadSourceFromKernel(kernel_td);
       }
     }
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index 398ecc8..8cbd3fc 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -682,8 +682,16 @@
     const uint8_t* kernel_bytes = compilation_result.kernel;
     intptr_t kernel_length = compilation_result.kernel_size;
 
-    val = lib.EvaluateCompiledExpression(kernel_bytes, kernel_length,
-                                         Array::empty_array(), param_values,
+    const auto& kernel_td = ExternalTypedData::Handle(ExternalTypedData::New(
+        kExternalTypedDataUint8ArrayCid, const_cast<uint8_t*>(kernel_bytes),
+        kernel_length, Heap::kOld));
+    kernel_td.AddFinalizer(
+        const_cast<uint8_t*>(kernel_bytes),
+        [](void* _, Dart_WeakPersistentHandle h, void* peer) { free(peer); },
+        kernel_length);
+
+    val = lib.EvaluateCompiledExpression(kernel_td, Array::empty_array(),
+                                         param_values,
                                          TypeArguments::null_type_arguments());
 
     free(const_cast<uint8_t*>(kernel_bytes));