Version 2.14.0-191.0.dev

Merge commit 'db17c490f8147b9b0b104b8b4ad9dfb2bc2f1a4f' into 'dev'
diff --git a/pkg/analysis_server/test/analysis/get_navigation_test.dart b/pkg/analysis_server/test/analysis/get_navigation_test.dart
index 38def2f..4c24110 100644
--- a/pkg/analysis_server/test/analysis/get_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/get_navigation_test.dart
@@ -139,6 +139,37 @@
     expect(testTargets[0].kind, ElementKind.LIBRARY);
   }
 
+  Future<void> test_importUri_configurations() async {
+    final ioFile = newFile(join(testFolder, 'io.dart'));
+    final htmlFile = newFile(join(testFolder, 'html.dart'));
+    addTestFile('''
+import 'foo.dart'
+  if (dart.library.io) 'io.dart'
+  if (dart.library.html) 'html.dart';
+
+main() {
+}''');
+    await waitForTasksFinished();
+
+    // Request navigations for 'io.dart'
+    await _getNavigation(testFile, 41, 9);
+    expect(regions, hasLength(1));
+    assertHasRegionString("'io.dart'");
+    expect(testTargets, hasLength(1));
+    var target = testTargets.first;
+    expect(target.kind, ElementKind.LIBRARY);
+    expect(targetFiles[target.fileIndex], equals(ioFile.path));
+
+    // Request navigations for 'html.dart'
+    await _getNavigation(testFile, 76, 11);
+    expect(regions, hasLength(1));
+    assertHasRegionString("'html.dart'");
+    expect(testTargets, hasLength(1));
+    target = testTargets.first;
+    expect(target.kind, ElementKind.LIBRARY);
+    expect(targetFiles[target.fileIndex], equals(htmlFile.path));
+  }
+
   Future<void> test_invalidFilePathFormat_notAbsolute() async {
     var request = _createGetNavigationRequest('test.dart', 0, 0);
     var response = await waitResponse(request);
diff --git a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
index e96926c..13c0f9b 100644
--- a/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
+++ b/pkg/analyzer_plugin/lib/utilities/navigation/navigation_dart.dart
@@ -68,9 +68,7 @@
       return;
     }
     // Discard elements that don't span the offset/range given (if provided).
-    if (requestedOffset != null &&
-        (offset > requestedOffset! + (requestedLength ?? 0) ||
-            offset + length < requestedOffset!)) {
+    if (!_isWithinRequestedRange(offset, length)) {
       return;
     }
     var converter = AnalyzerConverter();
@@ -154,6 +152,26 @@
         offset: codeOffset, length: codeLength);
   }
 
+  /// Checks if offset/length intersect with the range the user requested
+  /// navigation regions for.
+  ///
+  /// If the request did not specify a range, always returns true.
+  bool _isWithinRequestedRange(int offset, int length) {
+    final requestedOffset = this.requestedOffset;
+    if (requestedOffset == null) {
+      return true;
+    }
+    if (offset > requestedOffset + (requestedLength ?? 0)) {
+      // Starts after the requested range.
+      return false;
+    }
+    if (offset + length < requestedOffset) {
+      // Ends before the requested range.
+      return false;
+    }
+    return true;
+  }
+
   static ElementDeclarationResult? _parsedDeclaration(Element element) {
     var session = element.session;
     if (session == null) {
@@ -243,11 +261,13 @@
         // TODO(brianwilkerson) If the analyzer ever resolves the URI to a
         //  library, use that library element to create the region.
         var uriNode = node.uri;
-        computer.collector.addRegion(
-            uriNode.offset,
-            uriNode.length,
-            protocol.ElementKind.LIBRARY,
-            protocol.Location(source.fullName, 0, 0, 0, 0, 0, 0));
+        if (computer._isWithinRequestedRange(uriNode.offset, uriNode.length)) {
+          computer.collector.addRegion(
+              uriNode.offset,
+              uriNode.length,
+              protocol.ElementKind.LIBRARY,
+              protocol.Location(source.fullName, 0, 0, 0, 0, 0, 0));
+        }
       }
     }
     super.visitConfiguration(node);
diff --git a/pkg/dev_compiler/lib/src/compiler/shared_command.dart b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
index cf67f91..c0a9c24 100644
--- a/pkg/dev_compiler/lib/src/compiler/shared_command.dart
+++ b/pkg/dev_compiler/lib/src/compiler/shared_command.dart
@@ -92,6 +92,13 @@
   /// the browser.
   final bool emitDebugMetadata;
 
+  /// Whether to emit the debug symbols
+  ///
+  /// Debugger uses this information about to construct mapping between
+  /// dart and js objecys that otherwise requires expensive communication with
+  /// the browser.
+  final bool emitDebugSymbols;
+
   final Map<String, String> summaryModules;
 
   final List<ModuleFormat> moduleFormats;
@@ -123,6 +130,7 @@
       this.enableAsserts = true,
       this.replCompile = false,
       this.emitDebugMetadata = false,
+      this.emitDebugSymbols = false,
       this.emitFullCompiledKernel = false,
       this.summaryModules = const {},
       this.moduleFormats = const [],
@@ -140,6 +148,7 @@
             enableAsserts: args['enable-asserts'] as bool,
             replCompile: args['repl-compile'] as bool,
             emitDebugMetadata: args['experimental-emit-debug-metadata'] as bool,
+            emitDebugSymbols: args['emit-debug-symbols'] as bool,
             emitFullCompiledKernel:
                 args['experimental-output-compiled-kernel'] as bool,
             summaryModules:
@@ -195,6 +204,11 @@
               'Output a metadata file for debug tools next to the .js output.',
           defaultsTo: false,
           hide: true)
+      ..addFlag('emit-debug-symbols',
+          help: 'Experimental option for compiler development.\n'
+              'Output a symbols file for debug tools next to the .js output.',
+          defaultsTo: false,
+          hide: true)
       ..addFlag('experimental-output-compiled-kernel',
           help: 'Experimental option for compiler development.\n'
               'Output a full kernel file for currently compiled module next to '
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 8ddd4dc..2bac27d 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -11,6 +11,7 @@
 import 'package:args/args.dart';
 import 'package:build_integration/file_system/multi_root.dart';
 import 'package:cli_util/cli_util.dart' show getSdkPath;
+import 'package:dev_compiler/src/kernel/module_symbols.dart';
 import 'package:front_end/src/api_unstable/ddc.dart' as fe;
 import 'package:kernel/binary/ast_to_binary.dart' as kernel show BinaryPrinter;
 import 'package:kernel/class_hierarchy.dart';
@@ -443,11 +444,13 @@
         buildSourceMap: options.sourceMap,
         inlineSourceMap: options.inlineSourceMap,
         emitDebugMetadata: options.emitDebugMetadata,
+        emitDebugSymbols: options.emitDebugSymbols,
         jsUrl: p.toUri(output).toString(),
         mapUrl: mapUrl,
         fullDillUri: fullDillUri,
         customScheme: options.multiRootScheme,
         multiRootOutputPath: multiRootOutputPath,
+        compiler: compiler,
         component: compiledLibraries);
 
     outFiles.add(file.writeAsString(jsCode.code));
@@ -459,6 +462,11 @@
       outFiles.add(
           File('$output.metadata').writeAsString(json.encode(jsCode.metadata)));
     }
+
+    if (jsCode.symbols != null) {
+      outFiles.add(
+          File('$output.symbols').writeAsString(json.encode(jsCode.symbols)));
+    }
   }
 
   if (recordUsedInputs) {
@@ -635,7 +643,13 @@
   /// see: https://goto.google.com/dart-web-debugger-metadata
   final ModuleMetadata metadata;
 
-  JSCode(this.code, this.sourceMap, {this.metadata});
+  /// Module debug symbols.
+  ///
+  /// The [symbols] is a contract between compiler and the debugger,
+  /// helping the debugger map between dart and JS objects.
+  final ModuleSymbols symbols;
+
+  JSCode(this.code, this.sourceMap, {this.symbols, this.metadata});
 }
 
 /// Converts [moduleTree] to [JSCode], using [format].
@@ -646,12 +660,14 @@
     {bool buildSourceMap = false,
     bool inlineSourceMap = false,
     bool emitDebugMetadata = false,
+    bool emitDebugSymbols = false,
     String jsUrl,
     String mapUrl,
     String fullDillUri,
     String sourceMapBase,
     String customScheme,
     String multiRootOutputPath,
+    ProgramCompiler compiler,
     Component component}) {
   var opts = js_ast.JavaScriptPrintingOptions(
       allowKeywordsInProperties: true, allowSingleLineIfStatements: true);
@@ -666,8 +682,8 @@
   }
 
   var tree = transformModuleFormat(format, moduleTree);
-  tree.accept(
-      js_ast.Printer(opts, printer, localNamer: js_ast.TemporaryNamer(tree)));
+  var namer = js_ast.TemporaryNamer(tree);
+  tree.accept(js_ast.Printer(opts, printer, localNamer: namer));
 
   Map builtMap;
   if (buildSourceMap && sourceMap != null) {
@@ -710,7 +726,15 @@
       ? _emitMetadata(moduleTree, component, mapUrl, jsUrl, fullDillUri)
       : null;
 
-  return JSCode(text, builtMap, metadata: debugMetadata);
+  var debugSymbols =
+      emitDebugSymbols ? _emitSymbols(compiler, component) : null;
+
+  return JSCode(text, builtMap, symbols: debugSymbols, metadata: debugMetadata);
+}
+
+ModuleSymbols _emitSymbols(ProgramCompiler compiler, Component component) {
+  // TODO(annagrin): collect module symbols.
+  return ModuleSymbols();
 }
 
 ModuleMetadata _emitMetadata(js_ast.Program program, Component component,
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
index 7f79898..7300029 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_e2e_suite.dart
@@ -152,8 +152,10 @@
       inlineSourceMap: true,
       buildSourceMap: true,
       emitDebugMetadata: true,
+      emitDebugSymbols: true,
       jsUrl: '$output',
       mapUrl: '$output.map',
+      compiler: kernel2jsCompiler,
       component: component,
     );
     metadata = code.metadata;
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
index 8cda5d8..7141bb4 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_worker_test.dart
@@ -769,6 +769,7 @@
       config.testModule3.jsPath.toFilePath(),
       '--source-map',
       '--experimental-emit-debug-metadata',
+      '--emit-debug-symbols',
       '--experimental-output-compiled-kernel',
       '--dart-sdk-summary',
       config.sdkSummaryPath.path,
@@ -797,6 +798,7 @@
       config.testModule2.jsPath.toFilePath(),
       '--source-map',
       '--experimental-emit-debug-metadata',
+      '--emit-debug-symbols',
       '--experimental-output-compiled-kernel',
       '--dart-sdk-summary',
       config.sdkSummaryPath.path,
@@ -827,6 +829,7 @@
       config.testModule.jsPath.toFilePath(),
       '--source-map',
       '--experimental-emit-debug-metadata',
+      '--emit-debug-symbols',
       '--experimental-output-compiled-kernel',
       '--dart-sdk-summary',
       config.sdkSummaryPath.path,
@@ -859,6 +862,7 @@
       config.mainModule.jsPath.toFilePath(),
       '--source-map',
       '--experimental-emit-debug-metadata',
+      '--emit-debug-symbols',
       '--experimental-output-compiled-kernel',
       '--dart-sdk-summary',
       config.sdkSummaryPath.path,
diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index 5881625..4ba6641 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -168,6 +168,8 @@
   ..addFlag('experimental-emit-debug-metadata',
       help: 'Emit module and library metadata for the debugger',
       defaultsTo: false)
+  ..addFlag('emit-debug-symbols',
+      help: 'Emit debug symbols for the debugger', defaultsTo: false)
   ..addOption('dartdevc-module-format',
       help: 'The module format to use on for the dartdevc compiler',
       defaultsTo: 'amd')
@@ -324,7 +326,8 @@
       this.unsafePackageSerialization,
       this.incrementalSerialization: true,
       this.useDebuggerModuleNames: false,
-      this.emitDebugMetadata: false}) {
+      this.emitDebugMetadata: false,
+      this.emitDebugSymbols: false}) {
     _outputStream ??= stdout;
     printerFactory ??= new BinaryPrinterFactory();
   }
@@ -335,6 +338,7 @@
   bool incrementalSerialization;
   bool useDebuggerModuleNames;
   bool emitDebugMetadata;
+  bool emitDebugSymbols;
   bool _printIncrementalDependencies;
 
   CompilerOptions _compilerOptions;
@@ -625,6 +629,7 @@
     final File manifestFile = File('$filename.json');
     final File sourceMapsFile = File('$filename.map');
     final File metadataFile = File('$filename.metadata');
+    final File symbolsFile = File('$filename.symbols');
     if (!sourceFile.parent.existsSync()) {
       sourceFile.parent.createSync(recursive: true);
     }
@@ -632,6 +637,7 @@
         component, strongComponents, fileSystemScheme, packageConfig,
         useDebuggerModuleNames: useDebuggerModuleNames,
         emitDebugMetadata: emitDebugMetadata,
+        emitDebugSymbols: emitDebugSymbols,
         moduleFormat: moduleFormat,
         soundNullSafety: soundNullSafety);
     final sourceFileSink = sourceFile.openWrite();
@@ -639,6 +645,7 @@
     final sourceMapsFileSink = sourceMapsFile.openWrite();
     final metadataFileSink =
         emitDebugMetadata ? metadataFile.openWrite() : null;
+    final symbolsFileSink = emitDebugSymbols ? symbolsFile.openWrite() : null;
     final kernel2JsCompilers = await _bundler.compile(
         results.classHierarchy,
         results.coreTypes,
@@ -646,7 +653,8 @@
         sourceFileSink,
         manifestFileSink,
         sourceMapsFileSink,
-        metadataFileSink);
+        metadataFileSink,
+        symbolsFileSink);
     cachedProgramCompilers.addAll(kernel2JsCompilers);
     await Future.wait([
       sourceFileSink.close(),
@@ -1346,7 +1354,8 @@
       unsafePackageSerialization: options["unsafe-package-serialization"],
       incrementalSerialization: options["incremental-serialization"],
       useDebuggerModuleNames: options['debugger-module-names'],
-      emitDebugMetadata: options['experimental-emit-debug-metadata']);
+      emitDebugMetadata: options['experimental-emit-debug-metadata'],
+      emitDebugSymbols: options['emit-debug-symbols']);
 
   if (options.rest.isNotEmpty) {
     return await compiler.compile(options.rest[0], options,
diff --git a/pkg/frontend_server/lib/src/javascript_bundle.dart b/pkg/frontend_server/lib/src/javascript_bundle.dart
index 9829c57..a989fb1 100644
--- a/pkg/frontend_server/lib/src/javascript_bundle.dart
+++ b/pkg/frontend_server/lib/src/javascript_bundle.dart
@@ -27,6 +27,7 @@
       this._fileSystemScheme, this._packageConfig,
       {this.useDebuggerModuleNames = false,
       this.emitDebugMetadata = false,
+      this.emitDebugSymbols = false,
       this.soundNullSafety = false,
       String moduleFormat})
       : _moduleFormat = parseModuleFormat(moduleFormat ?? 'amd') {
@@ -63,6 +64,7 @@
   final PackageConfig _packageConfig;
   final bool useDebuggerModuleNames;
   final bool emitDebugMetadata;
+  final bool emitDebugSymbols;
   final ModuleFormat _moduleFormat;
   final bool soundNullSafety;
 
@@ -74,16 +76,19 @@
 
   /// Compile each component into a single JavaScript module.
   Future<Map<String, ProgramCompiler>> compile(
-      ClassHierarchy classHierarchy,
-      CoreTypes coreTypes,
-      Set<Library> loadedLibraries,
-      IOSink codeSink,
-      IOSink manifestSink,
-      IOSink sourceMapsSink,
-      IOSink metadataSink) async {
+    ClassHierarchy classHierarchy,
+    CoreTypes coreTypes,
+    Set<Library> loadedLibraries,
+    IOSink codeSink,
+    IOSink manifestSink,
+    IOSink sourceMapsSink,
+    IOSink metadataSink,
+    IOSink symbolsSink,
+  ) async {
     var codeOffset = 0;
     var sourceMapOffset = 0;
     var metadataOffset = 0;
+    var symbolsOffset = 0;
     final manifest = <String, Map<String, List<int>>>{};
     final Set<Uri> visited = <Uri>{};
     final Map<String, ProgramCompiler> kernel2JsCompilers = {};
@@ -135,6 +140,7 @@
           sourceMap: true,
           summarizeApi: false,
           emitDebugMetadata: emitDebugMetadata,
+          emitDebugSymbols: emitDebugSymbols,
           moduleName: moduleName,
           soundNullSafety: soundNullSafety,
         ),
@@ -145,10 +151,6 @@
 
       final jsModule = compiler.emitModule(summaryComponent);
 
-      // TODO:(annagrin): create symbol tables and pass to expression compiler
-      // so it can map dart symbols to js symbols
-      // [issue 40273](https://github.com/dart-lang/sdk/issues/40273)
-
       // Save program compiler to reuse for expression evaluation.
       kernel2JsCompilers[moduleName] = compiler;
 
@@ -168,22 +170,29 @@
         inlineSourceMap: true,
         buildSourceMap: true,
         emitDebugMetadata: emitDebugMetadata,
+        emitDebugSymbols: emitDebugSymbols,
         jsUrl: '$moduleUrl.lib.js',
         mapUrl: '$moduleUrl.lib.js.map',
         sourceMapBase: sourceMapBase,
         customScheme: _fileSystemScheme,
+        compiler: compiler,
         component: summaryComponent,
       );
       final codeBytes = utf8.encode(code.code);
       final sourceMapBytes = utf8.encode(json.encode(code.sourceMap));
       final metadataBytes =
           emitDebugMetadata ? utf8.encode(json.encode(code.metadata)) : null;
+      final symbolsBytes =
+          emitDebugSymbols ? utf8.encode(json.encode(code.symbols)) : null;
 
       codeSink.add(codeBytes);
       sourceMapsSink.add(sourceMapBytes);
       if (emitDebugMetadata) {
         metadataSink.add(metadataBytes);
       }
+      if (emitDebugSymbols) {
+        symbolsSink.add(symbolsBytes);
+      }
       final String moduleKey = _moduleImportForSummary[moduleUri];
       manifest[moduleKey] = {
         'code': <int>[codeOffset, codeOffset += codeBytes.length],
@@ -196,6 +205,11 @@
             metadataOffset,
             metadataOffset += metadataBytes.length
           ],
+        if (emitDebugSymbols)
+          'symbols': <int>[
+            symbolsOffset,
+            symbolsOffset += symbolsBytes.length,
+          ],
       };
     }
     manifestSink.add(utf8.encode(json.encode(manifest)));
diff --git a/pkg/frontend_server/test/frontend_server_test.dart b/pkg/frontend_server/test/frontend_server_test.dart
index ee69ecb..8205380 100644
--- a/pkg/frontend_server/test/frontend_server_test.dart
+++ b/pkg/frontend_server/test/frontend_server_test.dart
@@ -1979,12 +1979,14 @@
       var manifestFile = File('${dillFile.path}.json');
       var sourceMapsFile = File('${dillFile.path}.map');
       var metadataFile = File('${dillFile.path}.metadata');
+      var symbolsFile = File('${dillFile.path}.symbols');
 
       expect(dillFile.existsSync(), false);
       expect(sourceFile.existsSync(), false);
       expect(manifestFile.existsSync(), false);
       expect(sourceMapsFile.existsSync(), false);
       expect(metadataFile.existsSync(), false);
+      expect(symbolsFile.existsSync(), false);
 
       final List<String> args = <String>[
         '--sdk-root=${sdkRoot.toFilePath()}',
@@ -1994,6 +1996,7 @@
         '--target=dartdevc',
         '--packages=${package_config.path}',
         '--experimental-emit-debug-metadata',
+        '--emit-debug-symbols',
       ];
 
       final StreamController<List<int>> streamController =
@@ -2022,6 +2025,7 @@
         expect(manifestFile.existsSync(), equals(true));
         expect(sourceMapsFile.existsSync(), equals(true));
         expect(metadataFile.existsSync(), equals(true));
+        expect(symbolsFile.existsSync(), equals(true));
         expect(result.filename, dillFile.path);
         streamController.add('accept\n'.codeUnits);
         outputParser.expectSources = false;
diff --git a/pkg/frontend_server/test/src/javascript_bundle_test.dart b/pkg/frontend_server/test/src/javascript_bundle_test.dart
index 898cbcc..d927f82 100644
--- a/pkg/frontend_server/test/src/javascript_bundle_test.dart
+++ b/pkg/frontend_server/test/src/javascript_bundle_test.dart
@@ -111,16 +111,19 @@
     final codeSink = _MemorySink();
     final sourcemapSink = _MemorySink();
     final metadataSink = _MemorySink();
+    final symbolsSink = _MemorySink();
     final coreTypes = CoreTypes(testComponent);
 
     final compilers = await javaScriptBundler.compile(
-        ClassHierarchy(testComponent, coreTypes),
-        coreTypes,
-        {},
-        codeSink,
-        manifestSink,
-        sourcemapSink,
-        metadataSink);
+      ClassHierarchy(testComponent, coreTypes),
+      coreTypes,
+      {},
+      codeSink,
+      manifestSink,
+      sourcemapSink,
+      metadataSink,
+      symbolsSink,
+    );
 
     final Map manifest = json.decode(utf8.decode(manifestSink.buffer));
     final String code = utf8.decode(codeSink.buffer);
@@ -162,10 +165,19 @@
     final codeSink = _MemorySink();
     final sourcemapSink = _MemorySink();
     final metadataSink = _MemorySink();
+    final symbolsSink = _MemorySink();
     final coreTypes = CoreTypes(testComponent);
 
-    await javaScriptBundler.compile(ClassHierarchy(testComponent, coreTypes),
-        coreTypes, {}, codeSink, manifestSink, sourcemapSink, metadataSink);
+    await javaScriptBundler.compile(
+      ClassHierarchy(testComponent, coreTypes),
+      coreTypes,
+      {},
+      codeSink,
+      manifestSink,
+      sourcemapSink,
+      metadataSink,
+      symbolsSink,
+    );
 
     final Map manifest = json.decode(utf8.decode(manifestSink.buffer));
     final String code = utf8.decode(codeSink.buffer);
@@ -204,10 +216,19 @@
     final codeSink = _MemorySink();
     final sourcemapSink = _MemorySink();
     final metadataSink = _MemorySink();
+    final symbolsSink = _MemorySink();
     final coreTypes = CoreTypes(testComponent);
 
-    await javaScriptBundler.compile(ClassHierarchy(testComponent, coreTypes),
-        coreTypes, {}, codeSink, manifestSink, sourcemapSink, metadataSink);
+    await javaScriptBundler.compile(
+      ClassHierarchy(testComponent, coreTypes),
+      coreTypes,
+      {},
+      codeSink,
+      manifestSink,
+      sourcemapSink,
+      metadataSink,
+      symbolsSink,
+    );
 
     final Map manifest = json.decode(utf8.decode(manifestSink.buffer));
     final String code = utf8.decode(codeSink.buffer);
@@ -256,10 +277,19 @@
     final codeSink = _MemorySink();
     final sourcemapSink = _MemorySink();
     final metadataSink = _MemorySink();
+    final symbolsSink = _MemorySink();
     final coreTypes = CoreTypes(testComponent);
 
-    javaScriptBundler.compile(ClassHierarchy(testComponent, coreTypes),
-        coreTypes, {}, codeSink, manifestSink, sourcemapSink, metadataSink);
+    javaScriptBundler.compile(
+      ClassHierarchy(testComponent, coreTypes),
+      coreTypes,
+      {},
+      codeSink,
+      manifestSink,
+      sourcemapSink,
+      metadataSink,
+      symbolsSink,
+    );
 
     final code = utf8.decode(codeSink.buffer);
     final manifest = json.decode(utf8.decode(manifestSink.buffer));
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/encode_all_fields.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/encode_all_fields.dart.expect
index 084a1d5..4720666 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/encode_all_fields.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/protobuf_handler/lib/encode_all_fields.dart.expect
@@ -27,8 +27,8 @@
   } =>#t1;
   final typ::Uint8List* buffer = [@vm.direct-call.metadata=protobuf::GeneratedMessage.writeToBuffer] [@vm.inferred-type.metadata=dart.typed_data::_Uint8List (skip check)] foo.{pro::GeneratedMessage::writeToBuffer}(){() →* typ::Uint8List*};
   core::print("List<int> buffer = <int>[");
-  for (core::int* i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i.{core::num::<}([@vm.direct-call.metadata=dart.typed_data::_TypedList.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int*}){(core::num*) →* core::bool*}; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num*) →* core::int*}) {
-    final core::String* numbers = [@vm.direct-call.metadata=dart.typed_data::_TypedListBase.join] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=dart.typed_data::__Uint8List&_TypedList&_IntListMixin&_TypedIntListMixin.sublist] [@vm.inferred-type.metadata=dart.typed_data::_Uint8List (skip check)] buffer.{typ::Uint8List::sublist}(i, [@vm.inferred-type.metadata=int] math::min<core::int*>([@vm.direct-call.metadata=dart.typed_data::_TypedList.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int*}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num*) →* core::int*})){(core::int*, [core::int*]) →* typ::Uint8List*}.{core::Iterable::join}(", "){([core::String*]) →* core::String*};
+  for (core::int* i = 0; [@vm.direct-call.metadata=dart.core::_IntegerImplementation.<] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i.{core::num::<}([@vm.direct-call.metadata=dart.typed_data::_TypedListBase.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int*}){(core::num*) →* core::bool*}; i = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num*) →* core::int*}) {
+    final core::String* numbers = [@vm.direct-call.metadata=dart.typed_data::_TypedListBase.join] [@vm.inferred-type.metadata=!? (skip check)] [@vm.direct-call.metadata=dart.typed_data::__Uint8List&_TypedList&_IntListMixin&_TypedIntListMixin.sublist] [@vm.inferred-type.metadata=dart.typed_data::_Uint8List (skip check)] buffer.{typ::Uint8List::sublist}(i, [@vm.inferred-type.metadata=int] math::min<core::int*>([@vm.direct-call.metadata=dart.typed_data::_TypedListBase.length] [@vm.inferred-type.metadata=dart.core::_Smi] buffer.{core::List::length}{core::int*}, [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(5){(core::num*) →* core::int*})){(core::int*, [core::int*]) →* typ::Uint8List*}.{core::Iterable::join}(", "){([core::String*]) →* core::String*};
     core::print("  ${numbers},${[@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] i =={core::num::==}{(core::Object*) →* core::bool*} 0 ?{core::String*} " //" : ""}");
   }
   core::print("];");
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 93b086d..129caeb 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -114,11 +114,23 @@
 
   const Class& cls = Class::Handle(left.clazz());
   if (cls.IsClosureClass()) {
-    // TODO(vegorov): provide faster implementation for closure classes.
+    const Function& left_function =
+        Function::Handle(zone, Closure::Cast(left).function());
+    const Function& right_function =
+        Function::Handle(zone, Closure::Cast(right).function());
+    if (left_function.signature() == right_function.signature() &&
+        Closure::Cast(left).function_type_arguments() ==
+            Closure::Cast(right).function_type_arguments() &&
+        Closure::Cast(left).delayed_type_arguments() ==
+            Closure::Cast(right).delayed_type_arguments() &&
+        Closure::Cast(left).instantiator_type_arguments() ==
+            Closure::Cast(right).instantiator_type_arguments()) {
+      return Bool::True().ptr();
+    }
     const AbstractType& left_type =
-        AbstractType::Handle(left.GetType(Heap::kNew));
+        AbstractType::Handle(zone, left.GetType(Heap::kNew));
     const AbstractType& right_type =
-        AbstractType::Handle(right.GetType(Heap::kNew));
+        AbstractType::Handle(zone, right.GetType(Heap::kNew));
     return Bool::Get(
                left_type.IsEquivalent(right_type, TypeEquality::kSyntactical))
         .ptr();
@@ -132,9 +144,9 @@
     return Bool::True().ptr();
   }
   const TypeArguments& left_type_arguments =
-      TypeArguments::Handle(left.GetTypeArguments());
+      TypeArguments::Handle(zone, left.GetTypeArguments());
   const TypeArguments& right_type_arguments =
-      TypeArguments::Handle(right.GetTypeArguments());
+      TypeArguments::Handle(zone, right.GetTypeArguments());
   const intptr_t num_type_args = cls.NumTypeArguments();
   const intptr_t num_type_params = cls.NumTypeParameters();
   return Bool::Get(left_type_arguments.IsSubvectorEquivalent(
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc
index 4e1fc80..996d92d 100644
--- a/runtime/lib/string.cc
+++ b/runtime/lib/string.cc
@@ -322,57 +322,28 @@
   intptr_t start = start_obj.Value();
   intptr_t end = end_obj.Value();
   if (start < 0) {
-    const Array& args = Array::Handle(Array::New(1));
-    args.SetAt(0, start_obj);
-    Exceptions::ThrowByType(Exceptions::kArgument, args);
+    Exceptions::ThrowArgumentError(start_obj);
   }
   intptr_t length = end - start;
   if (length < 0) {
-    const Array& args = Array::Handle(Array::New(1));
-    args.SetAt(0, end_obj);
-    Exceptions::ThrowByType(Exceptions::kArgument, args);
+    Exceptions::ThrowArgumentError(end_obj);
   }
   ASSERT(length >= 0);
 
   Heap::Space space = Heap::kNew;
-  if (list.IsTypedData()) {
-    const TypedData& array = TypedData::Cast(list);
-    if (end > array.LengthInBytes()) {
-      const Array& args = Array::Handle(Array::New(1));
-      args.SetAt(0, end_obj);
-      Exceptions::ThrowByType(Exceptions::kArgument, args);
+  if (list.IsTypedDataBase()) {
+    const TypedDataBase& array = TypedDataBase::Cast(list);
+    if (array.ElementType() != kUint8ArrayElement) {
+      Exceptions::ThrowArgumentError(list);
+    }
+    if (end > array.Length()) {
+      Exceptions::ThrowArgumentError(end_obj);
     }
     return OneByteString::New(array, start, length, space);
-  } else if (list.IsExternalTypedData()) {
-    const ExternalTypedData& array = ExternalTypedData::Cast(list);
-    if (end > array.LengthInBytes()) {
-      const Array& args = Array::Handle(Array::New(1));
-      args.SetAt(0, end_obj);
-      Exceptions::ThrowByType(Exceptions::kArgument, args);
-    }
-    return OneByteString::New(array, start, length, space);
-  } else if (list.IsTypedDataView()) {
-    const auto& view = TypedDataView::Cast(list);
-    if (end > Smi::Value(view.length())) {
-      const Array& args = Array::Handle(Array::New(1));
-      args.SetAt(0, end_obj);
-      Exceptions::ThrowByType(Exceptions::kArgument, args);
-    }
-    const Instance& data_obj = Instance::Handle(view.typed_data());
-    intptr_t data_offset = Smi::Value(view.offset_in_bytes());
-    if (data_obj.IsTypedData()) {
-      const TypedData& array = TypedData::Cast(data_obj);
-      return OneByteString::New(array, data_offset + start, length, space);
-    } else if (data_obj.IsExternalTypedData()) {
-      const ExternalTypedData& array = ExternalTypedData::Cast(data_obj);
-      return OneByteString::New(array, data_offset + start, length, space);
-    }
   } else if (list.IsArray()) {
     const Array& array = Array::Cast(list);
     if (end > array.Length()) {
-      const Array& args = Array::Handle(Array::New(1));
-      args.SetAt(0, end_obj);
-      Exceptions::ThrowByType(Exceptions::kArgument, args);
+      Exceptions::ThrowArgumentError(end_obj);
     }
     String& string = String::Handle(OneByteString::New(length, space));
     for (int i = 0; i < length; i++) {
@@ -383,9 +354,7 @@
   } else if (list.IsGrowableObjectArray()) {
     const GrowableObjectArray& array = GrowableObjectArray::Cast(list);
     if (end > array.Length()) {
-      const Array& args = Array::Handle(Array::New(1));
-      args.SetAt(0, end_obj);
-      Exceptions::ThrowByType(Exceptions::kArgument, args);
+      Exceptions::ThrowArgumentError(end_obj);
     }
     String& string = String::Handle(OneByteString::New(length, space));
     for (int i = 0; i < length; i++) {
@@ -434,8 +403,8 @@
   }
 
   Heap::Space space = Heap::kNew;
-  if (list.IsTypedData()) {
-    const TypedData& array = TypedData::Cast(list);
+  if (list.IsTypedDataBase()) {
+    const TypedDataBase& array = TypedDataBase::Cast(list);
     if (array.ElementType() != kUint16ArrayElement) {
       Exceptions::ThrowArgumentError(list);
     }
@@ -443,35 +412,6 @@
       Exceptions::ThrowArgumentError(end_obj);
     }
     return TwoByteString::New(array, start * sizeof(uint16_t), length, space);
-  } else if (list.IsExternalTypedData()) {
-    const ExternalTypedData& array = ExternalTypedData::Cast(list);
-    if (array.ElementType() != kUint16ArrayElement) {
-      Exceptions::ThrowArgumentError(list);
-    }
-    if (end > array.Length()) {
-      Exceptions::ThrowArgumentError(end_obj);
-    }
-    return TwoByteString::New(array, start * sizeof(uint16_t), length, space);
-  } else if (IsTypedDataViewClassId(list.GetClassId())) {
-    const auto& view = TypedDataView::Cast(list);
-    const intptr_t cid = list.GetClassId();
-    if (cid != kTypedDataUint16ArrayViewCid) {
-      Exceptions::ThrowArgumentError(list);
-    }
-    if (end > Smi::Value(view.length())) {
-      Exceptions::ThrowArgumentError(end_obj);
-    }
-    const auto& data_obj = Instance::Handle(zone, view.typed_data());
-    const intptr_t data_offset = Smi::Value(view.offset_in_bytes());
-    if (data_obj.IsTypedData()) {
-      const TypedData& array = TypedData::Cast(data_obj);
-      return TwoByteString::New(array, data_offset + start * sizeof(uint16_t),
-                                length, space);
-    } else if (data_obj.IsExternalTypedData()) {
-      const ExternalTypedData& array = ExternalTypedData::Cast(data_obj);
-      return TwoByteString::New(array, data_offset + start * sizeof(uint16_t),
-                                length, space);
-    }
   } else if (list.IsArray()) {
     const Array& array = Array::Cast(list);
     if (end > array.Length()) {
diff --git a/runtime/lib/typed_data.cc b/runtime/lib/typed_data.cc
index 28d9331..eb21c47 100644
--- a/runtime/lib/typed_data.cc
+++ b/runtime/lib/typed_data.cc
@@ -47,20 +47,9 @@
   }
 }
 
-DEFINE_NATIVE_ENTRY(TypedData_length, 0, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
-  if (instance.IsTypedData()) {
-    const TypedData& array = TypedData::Cast(instance);
-    return Smi::New(array.Length());
-  }
-  if (instance.IsExternalTypedData()) {
-    const ExternalTypedData& array = ExternalTypedData::Cast(instance);
-    return Smi::New(array.Length());
-  }
-  const String& error = String::Handle(String::NewFormatted(
-      "Expected a TypedData object but found %s", instance.ToCString()));
-  Exceptions::ThrowArgumentError(error);
-  return Integer::null();
+DEFINE_NATIVE_ENTRY(TypedDataBase_length, 0, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, array, arguments->NativeArgAt(0));
+  return Smi::New(array.Length());
 }
 
 DEFINE_NATIVE_ENTRY(TypedDataView_offsetInBytes, 0, 1) {
@@ -70,13 +59,6 @@
   return TypedDataView::Cast(instance).offset_in_bytes();
 }
 
-DEFINE_NATIVE_ENTRY(TypedDataView_length, 0, 1) {
-  // "this" is either a _*ArrayView class or _ByteDataView.
-  GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
-  ASSERT(instance.IsTypedDataView());
-  return TypedDataView::Cast(instance).length();
-}
-
 DEFINE_NATIVE_ENTRY(TypedDataView_typedData, 0, 1) {
   // "this" is either a _*ArrayView class or _ByteDataView.
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance, arguments->NativeArgAt(0));
@@ -84,15 +66,12 @@
   return TypedDataView::Cast(instance).typed_data();
 }
 
-template <typename DstType, typename SrcType>
-static BoolPtr CopyData(const Instance& dst,
-                        const Instance& src,
+static BoolPtr CopyData(const TypedDataBase& dst_array,
+                        const TypedDataBase& src_array,
                         const Smi& dst_start,
                         const Smi& src_start,
                         const Smi& length,
                         bool clamped) {
-  const DstType& dst_array = DstType::Cast(dst);
-  const SrcType& src_array = SrcType::Cast(src);
   const intptr_t dst_offset_in_bytes = dst_start.Value();
   const intptr_t src_offset_in_bytes = src_start.Value();
   const intptr_t length_in_bytes = length.Value();
@@ -101,12 +80,11 @@
   ASSERT(Utils::RangeCheck(dst_offset_in_bytes, length_in_bytes,
                            dst_array.LengthInBytes()));
   if (clamped) {
-    TypedData::ClampedCopy<DstType, SrcType>(dst_array, dst_offset_in_bytes,
-                                             src_array, src_offset_in_bytes,
-                                             length_in_bytes);
+    TypedData::ClampedCopy(dst_array, dst_offset_in_bytes, src_array,
+                           src_offset_in_bytes, length_in_bytes);
   } else {
-    TypedData::Copy<DstType, SrcType>(dst_array, dst_offset_in_bytes, src_array,
-                                      src_offset_in_bytes, length_in_bytes);
+    TypedData::Copy(dst_array, dst_offset_in_bytes, src_array,
+                    src_offset_in_bytes, length_in_bytes);
   }
   return Bool::True().ptr();
 }
@@ -136,13 +114,13 @@
   }
 }
 
-DEFINE_NATIVE_ENTRY(TypedData_setRange, 0, 7) {
-  const Instance& dst =
-      Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
+DEFINE_NATIVE_ENTRY(TypedDataBase_setRange, 0, 7) {
+  const TypedDataBase& dst =
+      TypedDataBase::CheckedHandle(zone, arguments->NativeArgAt(0));
   const Smi& dst_start = Smi::CheckedHandle(zone, arguments->NativeArgAt(1));
   const Smi& length = Smi::CheckedHandle(zone, arguments->NativeArgAt(2));
-  const Instance& src =
-      Instance::CheckedHandle(zone, arguments->NativeArgAt(3));
+  const TypedDataBase& src =
+      TypedDataBase::CheckedHandle(zone, arguments->NativeArgAt(3));
   const Smi& src_start = Smi::CheckedHandle(zone, arguments->NativeArgAt(4));
   const Smi& to_cid_smi = Smi::CheckedHandle(zone, arguments->NativeArgAt(5));
   const Smi& from_cid_smi = Smi::CheckedHandle(zone, arguments->NativeArgAt(6));
@@ -156,25 +134,7 @@
   const intptr_t from_cid = from_cid_smi.Value();
 
   const bool needs_clamping = IsClamped(to_cid) && !IsUint8(from_cid);
-  if (dst.IsTypedData()) {
-    if (src.IsTypedData()) {
-      return CopyData<TypedData, TypedData>(dst, src, dst_start, src_start,
-                                            length, needs_clamping);
-    } else if (src.IsExternalTypedData()) {
-      return CopyData<TypedData, ExternalTypedData>(
-          dst, src, dst_start, src_start, length, needs_clamping);
-    }
-  } else if (dst.IsExternalTypedData()) {
-    if (src.IsTypedData()) {
-      return CopyData<ExternalTypedData, TypedData>(
-          dst, src, dst_start, src_start, length, needs_clamping);
-    } else if (src.IsExternalTypedData()) {
-      return CopyData<ExternalTypedData, ExternalTypedData>(
-          dst, src, dst_start, src_start, length, needs_clamping);
-    }
-  }
-  UNREACHABLE();
-  return Bool::False().ptr();
+  return CopyData(dst, src, dst_start, src_start, length, needs_clamping);
 }
 
 // Native methods for typed data allocation are recognized and implemented
@@ -203,19 +163,26 @@
 // into a _Smi.
 //
 // Argument 0 is type arguments and is ignored.
+static InstancePtr NewTypedDataView(intptr_t cid,
+                                    intptr_t element_size,
+                                    Zone* zone,
+                                    NativeArguments* arguments) {
+  GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, typed_data,
+                               arguments->NativeArgAt(1));
+  GET_NON_NULL_NATIVE_ARGUMENT(Smi, offset, arguments->NativeArgAt(2));
+  GET_NON_NULL_NATIVE_ARGUMENT(Smi, len, arguments->NativeArgAt(3));
+  const intptr_t backing_length = typed_data.LengthInBytes();
+  const intptr_t offset_in_bytes = offset.Value();
+  const intptr_t length = len.Value();
+  AlignmentCheck(offset_in_bytes, element_size);
+  LengthCheck(offset_in_bytes + length * element_size, backing_length);
+  return TypedDataView::New(cid, typed_data, offset_in_bytes, length);
+}
+
 #define TYPED_DATA_VIEW_NEW(native_name, cid)                                  \
   DEFINE_NATIVE_ENTRY(native_name, 0, 4) {                                     \
-    GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, typed_data,                    \
-                                 arguments->NativeArgAt(1));                   \
-    GET_NON_NULL_NATIVE_ARGUMENT(Smi, offset, arguments->NativeArgAt(2));      \
-    GET_NON_NULL_NATIVE_ARGUMENT(Smi, len, arguments->NativeArgAt(3));         \
-    const intptr_t backing_length = typed_data.LengthInBytes();                \
-    const intptr_t offset_in_bytes = offset.Value();                           \
-    const intptr_t length = len.Value();                                       \
-    const intptr_t element_size = TypedDataBase::ElementSizeInBytes(cid);      \
-    AlignmentCheck(offset_in_bytes, element_size);                             \
-    LengthCheck(offset_in_bytes + length * element_size, backing_length);      \
-    return TypedDataView::New(cid, typed_data, offset_in_bytes, length);       \
+    return NewTypedDataView(cid, TypedDataBase::ElementSizeInBytes(cid), zone, \
+                            arguments);                                        \
   }
 
 #define TYPED_DATA_NEW_NATIVE(name)                                            \
@@ -228,53 +195,27 @@
 
 #define TYPED_DATA_GETTER(getter, object, ctor, access_size)                   \
   DEFINE_NATIVE_ENTRY(TypedData_##getter, 0, 2) {                              \
-    GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance,                           \
+    GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, array,                         \
                                  arguments->NativeArgAt(0));                   \
     GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes,                           \
                                  arguments->NativeArgAt(1));                   \
-    if (instance.IsTypedData()) {                                              \
-      const TypedData& array = TypedData::Cast(instance);                      \
-      RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(),    \
-                 access_size);                                                 \
-      return object::ctor(array.getter(offsetInBytes.Value()));                \
-    }                                                                          \
-    if (instance.IsExternalTypedData()) {                                      \
-      const ExternalTypedData& array = ExternalTypedData::Cast(instance);      \
-      RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(),    \
-                 access_size);                                                 \
-      return object::ctor(array.getter(offsetInBytes.Value()));                \
-    }                                                                          \
-    const String& error = String::Handle(String::NewFormatted(                 \
-        "Expected a TypedData object but found %s", instance.ToCString()));    \
-    Exceptions::ThrowArgumentError(error);                                     \
-    return object::null();                                                     \
+    RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(),      \
+               access_size);                                                   \
+    return object::ctor(array.getter(offsetInBytes.Value()));                  \
   }
 
 #define TYPED_DATA_SETTER(setter, object, get_object_value, access_size,       \
                           access_type)                                         \
   DEFINE_NATIVE_ENTRY(TypedData_##setter, 0, 3) {                              \
-    GET_NON_NULL_NATIVE_ARGUMENT(Instance, instance,                           \
+    GET_NON_NULL_NATIVE_ARGUMENT(TypedDataBase, array,                         \
                                  arguments->NativeArgAt(0));                   \
     GET_NON_NULL_NATIVE_ARGUMENT(Smi, offsetInBytes,                           \
                                  arguments->NativeArgAt(1));                   \
     GET_NON_NULL_NATIVE_ARGUMENT(object, value, arguments->NativeArgAt(2));    \
-    if (instance.IsTypedData()) {                                              \
-      const TypedData& array = TypedData::Cast(instance);                      \
-      RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(),    \
-                 access_size);                                                 \
-      array.setter(offsetInBytes.Value(),                                      \
-                   static_cast<access_type>(value.get_object_value()));        \
-    } else if (instance.IsExternalTypedData()) {                               \
-      const ExternalTypedData& array = ExternalTypedData::Cast(instance);      \
-      RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(),    \
-                 access_size);                                                 \
-      array.setter(offsetInBytes.Value(),                                      \
-                   static_cast<access_type>(value.get_object_value()));        \
-    } else {                                                                   \
-      const String& error = String::Handle(String::NewFormatted(               \
-          "Expected a TypedData object but found %s", instance.ToCString()));  \
-      Exceptions::ThrowArgumentError(error);                                   \
-    }                                                                          \
+    RangeCheck(offsetInBytes.Value(), access_size, array.LengthInBytes(),      \
+               access_size);                                                   \
+    array.setter(offsetInBytes.Value(),                                        \
+                 static_cast<access_type>(value.get_object_value()));          \
     return Object::null();                                                     \
   }
 
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 5237e60..359d482 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -190,8 +190,8 @@
   V(TypedData_Float32x4Array_new, 2)                                           \
   V(TypedData_Int32x4Array_new, 2)                                             \
   V(TypedData_Float64x2Array_new, 2)                                           \
-  V(TypedData_length, 1)                                                       \
-  V(TypedData_setRange, 7)                                                     \
+  V(TypedDataBase_length, 1)                                                   \
+  V(TypedDataBase_setRange, 7)                                                 \
   V(TypedData_GetInt8, 2)                                                      \
   V(TypedData_SetInt8, 3)                                                      \
   V(TypedData_GetUint8, 2)                                                     \
@@ -233,7 +233,6 @@
   V(TypedDataView_Float32x4ArrayView_new, 4)                                   \
   V(TypedDataView_Int32x4ArrayView_new, 4)                                     \
   V(TypedDataView_Float64x2ArrayView_new, 4)                                   \
-  V(TypedDataView_length, 1)                                                   \
   V(TypedDataView_offsetInBytes, 1)                                            \
   V(TypedDataView_typedData, 1)                                                \
   V(Float32x4_fromDoubles, 4)                                                  \
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm.cc b/runtime/vm/compiler/asm_intrinsifier_arm.cc
index 2cfe3ad..f41c51d 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm.cc
@@ -1198,6 +1198,14 @@
              kIfNotInRange, target);
 }
 
+static void JumpIfType(Assembler* assembler,
+                       Register cid,
+                       Register tmp,
+                       Label* target) {
+  RangeCheck(assembler, cid, tmp, kTypeCid, kFunctionTypeCid, kIfInRange,
+             target);
+}
+
 static void JumpIfNotType(Assembler* assembler,
                           Register cid,
                           Register tmp,
@@ -1272,7 +1280,7 @@
                                Register cid1,
                                Register cid2,
                                Register scratch) {
-  Label different_cids, not_integer;
+  Label different_cids, not_integer, not_integer_or_string;
 
   // Check if left hand side is a closure. Closures are handled in the runtime.
   __ CompareImmediate(cid1, kClosureCid);
@@ -1295,7 +1303,7 @@
   __ b(equal);
 
   // Class ids are different. Check if we are comparing two string types (with
-  // different representations) or two integer types.
+  // different representations) or two integer types or two type types.
   __ Bind(&different_cids);
   __ CompareImmediate(cid1, kNumPredefinedCids);
   __ b(not_equal, HI);
@@ -1304,20 +1312,29 @@
   JumpIfNotInteger(assembler, cid1, scratch, &not_integer);
 
   // First type is an integer. Check if the second is an integer too.
-  // Otherwise types are unequiv because only integers have the same runtime
-  // type as other integers.
   JumpIfInteger(assembler, cid2, scratch, equal);
+  // Integer types are only equivalent to other integer types.
   __ b(not_equal);
 
   __ Bind(&not_integer);
-  // Check if the first type is String. If it is not then types are not
-  // equivalent because they have different class ids and they are not strings
-  // or integers.
-  JumpIfNotString(assembler, cid1, scratch, not_equal);
+  // Check if both are String types.
+  JumpIfNotString(assembler, cid1, scratch, &not_integer_or_string);
+
   // First type is String. Check if the second is a string too.
   JumpIfString(assembler, cid2, scratch, equal);
   // String types are only equivalent to other String types.
   __ b(not_equal);
+
+  __ Bind(&not_integer_or_string);
+  // Check if the first type is a Type. If it is not then types are not
+  // equivalent because they have different class ids and they are not String
+  // or integer or Type.
+  JumpIfNotType(assembler, cid1, scratch, not_equal);
+
+  // First type is a Type. Check if the second is a Type too.
+  JumpIfType(assembler, cid2, scratch, equal);
+  // Type types are only equivalent to other Type types.
+  __ b(not_equal);
 }
 
 void AsmIntrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler,
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index cf58e60..5749365 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1340,6 +1340,14 @@
              kIfNotInRange, target);
 }
 
+static void JumpIfType(Assembler* assembler,
+                       Register cid,
+                       Register tmp,
+                       Label* target) {
+  RangeCheck(assembler, cid, tmp, kTypeCid, kFunctionTypeCid, kIfInRange,
+             target);
+}
+
 static void JumpIfNotType(Assembler* assembler,
                           Register cid,
                           Register tmp,
@@ -1418,7 +1426,7 @@
                                Register cid1,
                                Register cid2,
                                Register scratch) {
-  Label different_cids, not_integer;
+  Label different_cids, not_integer, not_integer_or_string;
 
   // Check if left hand side is a closure. Closures are handled in the runtime.
   __ CompareImmediate(cid1, kClosureCid);
@@ -1442,7 +1450,7 @@
   __ b(equal);
 
   // Class ids are different. Check if we are comparing two string types (with
-  // different representations) or two integer types.
+  // different representations) or two integer types or two type types.
   __ Bind(&different_cids);
   __ CompareImmediate(cid1, kNumPredefinedCids);
   __ b(not_equal, HI);
@@ -1451,20 +1459,28 @@
   JumpIfNotInteger(assembler, cid1, scratch, &not_integer);
 
   // First type is an integer. Check if the second is an integer too.
-  // Otherwise types are unequiv because only integers have the same runtime
-  // type as other integers.
   JumpIfInteger(assembler, cid2, scratch, equal);
+  // Integer types are only equivalent to other integer types.
   __ b(not_equal);
 
   __ Bind(&not_integer);
-  // Check if the first type is String. If it is not then types are not
-  // equivalent because they have different class ids and they are not strings
-  // or integers.
-  JumpIfNotString(assembler, cid1, scratch, not_equal);
+  // Check if both are String types.
+  JumpIfNotString(assembler, cid1, scratch, &not_integer_or_string);
+
   // First type is String. Check if the second is a string too.
   JumpIfString(assembler, cid2, scratch, equal);
   // String types are only equivalent to other String types.
-  // Fall-through to the not equal case.
+  __ b(not_equal);
+
+  __ Bind(&not_integer_or_string);
+  // Check if the first type is a Type. If it is not then types are not
+  // equivalent because they have different class ids and they are not String
+  // or integer or Type.
+  JumpIfNotType(assembler, cid1, scratch, not_equal);
+
+  // First type is a Type. Check if the second is a Type too.
+  JumpIfType(assembler, cid2, scratch, equal);
+  // Type types are only equivalent to other Type types.
   __ b(not_equal);
 }
 
diff --git a/runtime/vm/compiler/asm_intrinsifier_ia32.cc b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
index a52f0ab..5909eab 100644
--- a/runtime/vm/compiler/asm_intrinsifier_ia32.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_ia32.cc
@@ -1281,6 +1281,10 @@
              kIfNotInRange, target);
 }
 
+static void JumpIfType(Assembler* assembler, Register cid, Label* target) {
+  RangeCheck(assembler, cid, kTypeCid, kFunctionTypeCid, kIfInRange, target);
+}
+
 static void JumpIfNotType(Assembler* assembler, Register cid, Label* target) {
   RangeCheck(assembler, cid, kTypeCid, kFunctionTypeCid, kIfNotInRange, target);
 }
@@ -1362,7 +1366,7 @@
                                Register cid1,
                                Register cid2,
                                Register scratch) {
-  Label different_cids, not_integer;
+  Label different_cids, not_integer, not_integer_or_string;
 
   // Check if left hand side is a closure. Closures are handled in the runtime.
   __ cmpl(cid1, Immediate(kClosureCid));
@@ -1381,11 +1385,11 @@
   __ movzxw(scratch,
             FieldAddress(scratch, target::Class::num_type_arguments_offset()));
   __ cmpl(scratch, Immediate(0));
-  __ j(NOT_EQUAL, normal_ir_body, Assembler::kNearJump);
+  __ j(NOT_EQUAL, normal_ir_body);
   __ jmp(equal);
 
   // Class ids are different. Check if we are comparing two string types (with
-  // different representations) or two integer types.
+  // different representations) or two integer types or two type types.
   __ Bind(&different_cids);
   __ cmpl(cid1, Immediate(kNumPredefinedCids));
   __ j(ABOVE_EQUAL, not_equal);
@@ -1395,20 +1399,29 @@
   JumpIfNotInteger(assembler, scratch, &not_integer);
 
   // First type is an integer. Check if the second is an integer too.
-  // Otherwise types are unequiv because only integers have the same runtime
-  // type as other integers.
   JumpIfInteger(assembler, cid2, equal);
+  // Integer types are only equivalent to other integer types.
   __ jmp(not_equal);
 
   __ Bind(&not_integer);
-  // Check if the first type is String. If it is not then types are not
-  // equivalent because they have different class ids and they are not strings
-  // or integers.
-  JumpIfNotString(assembler, cid1, not_equal);
-  // First type is String. Check if the second is a string too.
+  // Check if both are String types.
+  JumpIfNotString(assembler, cid1, &not_integer_or_string);
+
+  // First type is a String. Check if the second is a String too.
   JumpIfString(assembler, cid2, equal);
   // String types are only equivalent to other String types.
   __ jmp(not_equal);
+
+  __ Bind(&not_integer_or_string);
+  // Check if the first type is a Type. If it is not then types are not
+  // equivalent because they have different class ids and they are not String
+  // or integer or Type.
+  JumpIfNotType(assembler, cid1, not_equal);
+
+  // First type is a Type. Check if the second is a Type too.
+  JumpIfType(assembler, cid2, equal);
+  // Type types are only equivalent to other Type types.
+  __ jmp(not_equal);
 }
 
 void AsmIntrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler,
diff --git a/runtime/vm/compiler/asm_intrinsifier_x64.cc b/runtime/vm/compiler/asm_intrinsifier_x64.cc
index da97a49..f691931 100644
--- a/runtime/vm/compiler/asm_intrinsifier_x64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_x64.cc
@@ -1183,9 +1183,14 @@
              kIfNotInRange, target);
 }
 
+static void JumpIfType(Assembler* assembler, Register cid, Label* target) {
+  RangeCheck(assembler, cid, kTypeCid, kFunctionTypeCid, kIfInRange, target);
+}
+
 static void JumpIfNotType(Assembler* assembler, Register cid, Label* target) {
   RangeCheck(assembler, cid, kTypeCid, kFunctionTypeCid, kIfNotInRange, target);
 }
+
 // Return type quickly for simple types (not parameterized and not signature).
 void AsmIntrinsifier::ObjectRuntimeType(Assembler* assembler,
                                         Label* normal_ir_body) {
@@ -1265,7 +1270,7 @@
                                Register cid1,
                                Register cid2,
                                Register scratch) {
-  Label different_cids, not_integer;
+  Label different_cids, not_integer, not_integer_or_string;
 
   // Check if left hand side is a closure. Closures are handled in the runtime.
   __ cmpq(cid1, Immediate(kClosureCid));
@@ -1288,7 +1293,7 @@
   __ jmp(equal);
 
   // Class ids are different. Check if we are comparing two string types (with
-  // different representations) or two integer types.
+  // different representations) or two integer types or two type types.
   __ Bind(&different_cids);
   __ cmpq(cid1, Immediate(kNumPredefinedCids));
   __ j(ABOVE_EQUAL, not_equal);
@@ -1298,20 +1303,29 @@
   JumpIfNotInteger(assembler, scratch, &not_integer);
 
   // First type is an integer. Check if the second is an integer too.
-  // Otherwise types are unequiv because only integers have the same runtime
-  // type as other integers.
   JumpIfInteger(assembler, cid2, equal);
+  // Integer types are only equivalent to other integer types.
   __ jmp(not_equal);
 
   __ Bind(&not_integer);
-  // Check if the first type is String. If it is not then types are not
-  // equivalent because they have different class ids and they are not strings
-  // or integers.
-  JumpIfNotString(assembler, cid1, not_equal);
-  // First type is String. Check if the second is a string too.
+  // Check if both are String types.
+  JumpIfNotString(assembler, cid1, &not_integer_or_string);
+
+  // First type is a String. Check if the second is a String too.
   JumpIfString(assembler, cid2, equal);
   // String types are only equivalent to other String types.
   __ jmp(not_equal);
+
+  __ Bind(&not_integer_or_string);
+  // Check if the first type is a Type. If it is not then types are not
+  // equivalent because they have different class ids and they are not String
+  // or integer or Type.
+  JumpIfNotType(assembler, cid1, not_equal);
+
+  // First type is a Type. Check if the second is a Type too.
+  JumpIfType(assembler, cid2, equal);
+  // Type types are only equivalent to other Type types.
+  __ jmp(not_equal);
 }
 
 void AsmIntrinsifier::ObjectHaveSameRuntimeType(Assembler* assembler,
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index a3f7ea7..ab5f8aa 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -856,8 +856,7 @@
     case MethodRecognizer::kGrowableArrayLength:
     case MethodRecognizer::kObjectArrayLength:
     case MethodRecognizer::kImmutableArrayLength:
-    case MethodRecognizer::kTypedListLength:
-    case MethodRecognizer::kTypedListViewLength:
+    case MethodRecognizer::kTypedListBaseLength:
     case MethodRecognizer::kByteDataViewLength:
     case MethodRecognizer::kByteDataViewOffsetInBytes:
     case MethodRecognizer::kTypedDataViewOffsetInBytes:
@@ -1054,8 +1053,7 @@
       body += LoadLocal(parsed_function_->RawParameterVariable(0));
       body += LoadNativeField(Slot::Array_length());
       break;
-    case MethodRecognizer::kTypedListLength:
-    case MethodRecognizer::kTypedListViewLength:
+    case MethodRecognizer::kTypedListBaseLength:
     case MethodRecognizer::kByteDataViewLength:
       ASSERT(function.NumParameters() == 1);
       body += LoadLocal(parsed_function_->RawParameterVariable(0));
diff --git a/runtime/vm/compiler/graph_intrinsifier.cc b/runtime/vm/compiler/graph_intrinsifier.cc
index d0ca36b..49287d4 100644
--- a/runtime/vm/compiler/graph_intrinsifier.cc
+++ b/runtime/vm/compiler/graph_intrinsifier.cc
@@ -760,11 +760,7 @@
   return BuildLoadField(flow_graph, Slot::String_length());
 }
 
-bool GraphIntrinsifier::Build_TypedListLength(FlowGraph* flow_graph) {
-  return BuildLoadField(flow_graph, Slot::TypedDataBase_length());
-}
-
-bool GraphIntrinsifier::Build_TypedListViewLength(FlowGraph* flow_graph) {
+bool GraphIntrinsifier::Build_TypedListBaseLength(FlowGraph* flow_graph) {
   return BuildLoadField(flow_graph, Slot::TypedDataBase_length());
 }
 
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 58d8c8b..d2a757a 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -318,8 +318,7 @@
   V(_Int32x4List, []=, Int32x4ArraySetIndexed, 0x17a2cbc0)                     \
   V(_Float64x2List, [], Float64x2ArrayGetIndexed, 0xea0577df)                  \
   V(_Float64x2List, []=, Float64x2ArraySetIndexed, 0x8af8aa58)                 \
-  V(_TypedList, get:length, TypedListLength, 0x5850f06b)                       \
-  V(_TypedListView, get:length, TypedListViewLength, 0x5850f06b)               \
+  V(_TypedListBase, get:length, TypedListBaseLength, 0x5850f06b)               \
   V(_ByteDataView, get:length, ByteDataViewLength, 0x5850f06b)                 \
   V(_Float32x4, get:x, Float32x4ShuffleX, 0x3a398530)                          \
   V(_Float32x4, get:y, Float32x4ShuffleY, 0x27cae053)                          \
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index f26d236..54be0aa 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -3211,8 +3211,8 @@
     // Pass through errors.
     return list;
   }
-  if (obj.IsTypedData()) {
-    GET_LIST_LENGTH(Z, TypedData, obj, len);
+  if (obj.IsTypedDataBase()) {
+    GET_LIST_LENGTH(Z, TypedDataBase, obj, len);
   }
   if (obj.IsArray()) {
     GET_LIST_LENGTH(Z, Array, obj, len);
@@ -3220,9 +3220,6 @@
   if (obj.IsGrowableObjectArray()) {
     GET_LIST_LENGTH(Z, GrowableObjectArray, obj, len);
   }
-  if (obj.IsExternalTypedData()) {
-    GET_LIST_LENGTH(Z, ExternalTypedData, obj, len);
-  }
   CHECK_CALLBACK_STATE(T);
 
   // Now check and handle a dart object that implements the List interface.
@@ -3464,63 +3461,22 @@
   }                                                                            \
   return Api::NewError("Invalid length passed in to access array elements");
 
-template <typename T>
-static Dart_Handle CopyBytes(const T& array,
-                             intptr_t offset,
-                             uint8_t* native_array,
-                             intptr_t length) {
-  ASSERT(array.ElementSizeInBytes() == 1);
-  NoSafepointScope no_safepoint;
-  memmove(native_array, reinterpret_cast<uint8_t*>(array.DataAddr(offset)),
-          length);
-  return Api::Success();
-}
-
 DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list,
                                             intptr_t offset,
                                             uint8_t* native_array,
                                             intptr_t length) {
   DARTSCOPE(Thread::Current());
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
-  if (obj.IsTypedData()) {
-    const TypedData& array = TypedData::Cast(obj);
+  if (obj.IsTypedDataBase()) {
+    const TypedDataBase& array = TypedDataBase::Cast(obj);
     if (array.ElementSizeInBytes() == 1) {
-      if (!Utils::RangeCheck(offset, length, array.Length())) {
-        return Api::NewError(
-            "Invalid length passed in to access list elements");
+      if (Utils::RangeCheck(offset, length, array.Length())) {
+        NoSafepointScope no_safepoint;
+        memmove(native_array,
+                reinterpret_cast<uint8_t*>(array.DataAddr(offset)), length);
+        return Api::Success();
       }
-      return CopyBytes(array, offset, native_array, length);
-    }
-  }
-  if (obj.IsExternalTypedData()) {
-    const ExternalTypedData& external_array = ExternalTypedData::Cast(obj);
-    if (external_array.ElementSizeInBytes() == 1) {
-      if (!Utils::RangeCheck(offset, length, external_array.Length())) {
-        return Api::NewError(
-            "Invalid length passed in to access list elements");
-      }
-      return CopyBytes(external_array, offset, native_array, length);
-    }
-  }
-  if (IsTypedDataViewClassId(obj.GetClassId())) {
-    const auto& view = TypedDataView::Cast(obj);
-    if (view.ElementSizeInBytes() == 1) {
-      const intptr_t view_length = Smi::Value(view.length());
-      if (!Utils::RangeCheck(offset, length, view_length)) {
-        return Api::NewError(
-            "Invalid length passed in to access list elements");
-      }
-      const auto& data = Instance::Handle(view.typed_data());
-      if (data.IsTypedData()) {
-        const TypedData& array = TypedData::Cast(data);
-        if (array.ElementSizeInBytes() == 1) {
-          const intptr_t data_offset =
-              Smi::Value(view.offset_in_bytes()) + offset;
-          // Range check already performed on the view object.
-          ASSERT(Utils::RangeCheck(data_offset, length, array.Length()));
-          return CopyBytes(array, data_offset, native_array, length);
-        }
-      }
+      return Api::NewError("Invalid length passed in to access list elements");
     }
   }
   if (obj.IsArray()) {
@@ -3590,8 +3546,8 @@
                                             intptr_t length) {
   DARTSCOPE(Thread::Current());
   const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
-  if (obj.IsTypedData()) {
-    const TypedData& array = TypedData::Cast(obj);
+  if (obj.IsTypedDataBase()) {
+    const TypedDataBase& array = TypedDataBase::Cast(obj);
     if (array.ElementSizeInBytes() == 1) {
       if (Utils::RangeCheck(offset, length, array.Length())) {
         NoSafepointScope no_safepoint;
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 4f333c6..a008f7b 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -5631,7 +5631,7 @@
 
 TEST_CASE(DartAPI_New) {
   const char* kScriptChars =
-      "class MyClass {\n"
+      "class MyClass implements MyExtraHop {\n"
       "  MyClass() : foo = 7 {}\n"
       "  MyClass.named(value) : foo = value {}\n"
       "  MyClass._hidden(value) : foo = -value {}\n"
@@ -5644,7 +5644,7 @@
       "  var foo;\n"
       "}\n"
       "\n"
-      "abstract class MyExtraHop {\n"
+      "abstract class MyExtraHop implements MyInterface {\n"
       "  factory MyExtraHop.hop(value) = MyClass.named;\n"
       "}\n"
       "\n"
@@ -5841,26 +5841,6 @@
   result = Dart_New(type, NewString("exception"), 1, args);
   EXPECT_ERROR(result, "ConstructorDeath");
 
-  // Invoke two-hop redirecting factory constructor.
-  result = Dart_New(intf, NewString("named"), 1, args);
-  EXPECT_VALID(result);
-  EXPECT_VALID(Dart_ObjectIsType(result, type, &instanceOf));
-  EXPECT(instanceOf);
-  int_value = 0;
-  foo = Dart_GetField(result, NewString("foo"));
-  EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
-  EXPECT_EQ(11, int_value);
-
-  // Invoke one-hop redirecting factory constructor.
-  result = Dart_New(intf, NewString("multiply"), 1, args);
-  EXPECT_VALID(result);
-  EXPECT_VALID(Dart_ObjectIsType(result, type, &instanceOf));
-  EXPECT(instanceOf);
-  int_value = 0;
-  foo = Dart_GetField(result, NewString("foo"));
-  EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
-  EXPECT_EQ(1100, int_value);
-
   // Invoke a constructor that is missing in the interface.
   result = Dart_New(intf, Dart_Null(), 0, NULL);
   EXPECT_ERROR(result, "Dart_New: could not find constructor 'MyInterface.'.");
@@ -5872,6 +5852,71 @@
   EXPECT(!instanceOf);
 }
 
+// These two cases below currently fail because of issue
+// https://github.com/dart-lang/sdk/issues/42939
+TEST_CASE(DartAPI_New_Issue42939) {
+  const char* kScriptChars =
+      "class MyClass implements MyExtraHop {\n"
+      "  MyClass() : foo = 7 {}\n"
+      "  MyClass.named(value) : foo = value {}\n"
+      "  MyClass._hidden(value) : foo = -value {}\n"
+      "  MyClass.exception(value) : foo = value {\n"
+      "    throw 'ConstructorDeath';\n"
+      "  }\n"
+      "  factory MyClass.multiply(value) {\n"
+      "    return new MyClass.named(value * 100);\n"
+      "  }\n"
+      "  var foo;\n"
+      "}\n"
+      "\n"
+      "abstract class MyExtraHop implements MyInterface {\n"
+      "  factory MyExtraHop.hop(value) = MyClass.named;\n"
+      "}\n"
+      "\n"
+      "abstract class MyInterface {\n"
+      "  factory MyInterface.named(value) = MyExtraHop.hop;\n"
+      "  factory MyInterface.multiply(value) = MyClass.multiply;\n"
+      "  MyInterface.notfound(value);\n"
+      "}\n"
+      "\n";
+
+  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+  Dart_Handle type =
+      Dart_GetNonNullableType(lib, NewString("MyClass"), 0, NULL);
+  EXPECT_VALID(type);
+  Dart_Handle intf =
+      Dart_GetNonNullableType(lib, NewString("MyInterface"), 0, NULL);
+  EXPECT_VALID(intf);
+
+  Dart_Handle args[1];
+  args[0] = Dart_NewInteger(11);
+
+  // Invoke two-hop redirecting factory constructor.
+  bool instanceOf = false;
+  Dart_Handle result = Dart_New(intf, NewString("named"), 1, args);
+  EXPECT_VALID(result);
+  if (!Dart_IsError(result)) {
+    EXPECT_VALID(Dart_ObjectIsType(result, type, &instanceOf));
+    EXPECT(instanceOf);
+    int64_t int_value = 0;
+    Dart_Handle foo = Dart_GetField(result, NewString("foo"));
+    EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
+    EXPECT_EQ(11, int_value);
+  }
+
+  // Invoke one-hop redirecting factory constructor.
+  result = Dart_New(intf, NewString("multiply"), 1, args);
+  EXPECT_VALID(result);
+  if (!Dart_IsError(result)) {
+    EXPECT_VALID(Dart_ObjectIsType(result, type, &instanceOf));
+    EXPECT(instanceOf);
+    int64_t int_value = 0;
+    Dart_Handle foo = Dart_GetField(result, NewString("foo"));
+    EXPECT_VALID(Dart_IntegerToInt64(foo, &int_value));
+    EXPECT_EQ(1100, int_value);
+  }
+}
+
 TEST_CASE(DartAPI_New_Issue44205) {
   const char* kScriptChars =
       "class MyIntClass {\n"
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index cf4a20d..e153091 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -50,6 +50,7 @@
 #include "vm/object_store.h"
 #include "vm/parser.h"
 #include "vm/profiler.h"
+#include "vm/regexp.h"
 #include "vm/resolver.h"
 #include "vm/reusable_handles.h"
 #include "vm/runtime_entry.h"
@@ -11103,8 +11104,7 @@
 }
 
 static intptr_t GetListLength(const Object& value) {
-  if (value.IsTypedData() || value.IsTypedDataView() ||
-      value.IsExternalTypedData()) {
+  if (value.IsTypedDataBase()) {
     return TypedDataBase::Cast(value).Length();
   } else if (value.IsArray()) {
     return Array::Cast(value).Length();
@@ -23571,21 +23571,7 @@
   return OneByteString::raw(result);
 }
 
-OneByteStringPtr OneByteString::New(const TypedData& other_typed_data,
-                                    intptr_t other_start_index,
-                                    intptr_t other_len,
-                                    Heap::Space space) {
-  const String& result = String::Handle(OneByteString::New(other_len, space));
-  ASSERT(other_typed_data.ElementSizeInBytes() == 1);
-  if (other_len > 0) {
-    NoSafepointScope no_safepoint;
-    memmove(OneByteString::DataStart(result),
-            other_typed_data.DataAddr(other_start_index), other_len);
-  }
-  return OneByteString::raw(result);
-}
-
-OneByteStringPtr OneByteString::New(const ExternalTypedData& other_typed_data,
+OneByteStringPtr OneByteString::New(const TypedDataBase& other_typed_data,
                                     intptr_t other_start_index,
                                     intptr_t other_len,
                                     Heap::Space space) {
@@ -23765,21 +23751,7 @@
   return TwoByteString::raw(result);
 }
 
-TwoByteStringPtr TwoByteString::New(const TypedData& other_typed_data,
-                                    intptr_t other_start_index,
-                                    intptr_t other_len,
-                                    Heap::Space space) {
-  const String& result = String::Handle(TwoByteString::New(other_len, space));
-  if (other_len > 0) {
-    NoSafepointScope no_safepoint;
-    memmove(TwoByteString::DataStart(result),
-            other_typed_data.DataAddr(other_start_index),
-            other_len * sizeof(uint16_t));
-  }
-  return TwoByteString::raw(result);
-}
-
-TwoByteStringPtr TwoByteString::New(const ExternalTypedData& other_typed_data,
+TwoByteStringPtr TwoByteString::New(const TypedDataBase& other_typed_data,
                                     intptr_t other_start_index,
                                     intptr_t other_len,
                                     Heap::Space space) {
@@ -25049,7 +25021,7 @@
 }
 
 FunctionTypePtr Closure::GetInstantiatedSignature(Zone* zone) const {
-  Function& fun = Function::Handle(zone, function());
+  const Function& fun = Function::Handle(zone, function());
   FunctionType& sig = FunctionType::Handle(zone, fun.signature());
   TypeArguments& fn_type_args =
       TypeArguments::Handle(zone, function_type_arguments());
@@ -25518,7 +25490,7 @@
   untag()->set_capture_name_map(array.ptr());
 }
 
-RegExpPtr RegExp::New(Heap::Space space) {
+RegExpPtr RegExp::New(Zone* zone, Heap::Space space) {
   RegExp& result = RegExp::Handle();
   {
     ObjectPtr raw =
@@ -25532,6 +25504,21 @@
     result.set_num_registers(/*is_one_byte=*/false, -1);
     result.set_num_registers(/*is_one_byte=*/true, -1);
   }
+
+  if (!FLAG_interpret_irregexp) {
+    auto thread = Thread::Current();
+    const Library& lib = Library::Handle(zone, Library::CoreLibrary());
+    const Class& owner =
+        Class::Handle(zone, lib.LookupClass(Symbols::RegExp()));
+
+    for (intptr_t cid = kOneByteStringCid; cid <= kExternalTwoByteStringCid;
+         cid++) {
+      CreateSpecializedFunction(thread, zone, result, cid, /*sticky=*/false,
+                                owner);
+      CreateSpecializedFunction(thread, zone, result, cid, /*sticky=*/true,
+                                owner);
+    }
+  }
   return result.ptr();
 }
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index fe21539..105f60c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -9486,12 +9486,7 @@
                               intptr_t other_len,
                               Heap::Space space);
 
-  static OneByteStringPtr New(const TypedData& other_typed_data,
-                              intptr_t other_start_index,
-                              intptr_t other_len,
-                              Heap::Space space = Heap::kNew);
-
-  static OneByteStringPtr New(const ExternalTypedData& other_typed_data,
+  static OneByteStringPtr New(const TypedDataBase& other_typed_data,
                               intptr_t other_start_index,
                               intptr_t other_len,
                               Heap::Space space = Heap::kNew);
@@ -9622,12 +9617,7 @@
                               Heap::Space space);
   static TwoByteStringPtr New(const String& str, Heap::Space space);
 
-  static TwoByteStringPtr New(const TypedData& other_typed_data,
-                              intptr_t other_start_index,
-                              intptr_t other_len,
-                              Heap::Space space = Heap::kNew);
-
-  static TwoByteStringPtr New(const ExternalTypedData& other_typed_data,
+  static TwoByteStringPtr New(const TypedDataBase& other_typed_data,
                               intptr_t other_start_index,
                               intptr_t other_len,
                               Heap::Space space = Heap::kNew);
@@ -10408,6 +10398,32 @@
     return reinterpret_cast<void*>(Validate(untag()->data_) + byte_offset);
   }
 
+#define TYPED_GETTER_SETTER(name, type)                                        \
+  type Get##name(intptr_t byte_offset) const {                                 \
+    NoSafepointScope no_safepoint;                                             \
+    return LoadUnaligned(reinterpret_cast<type*>(DataAddr(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
+
  protected:
   void SetLength(intptr_t value) const {
     ASSERT(value <= Smi::kMaxValue);
@@ -10500,10 +10516,9 @@
                           intptr_t len,
                           Heap::Space space = Heap::kNew);
 
-  template <typename DstType, typename SrcType>
-  static void Copy(const DstType& dst,
+  static void Copy(const TypedDataBase& dst,
                    intptr_t dst_offset_in_bytes,
-                   const SrcType& src,
+                   const TypedDataBase& src,
                    intptr_t src_offset_in_bytes,
                    intptr_t length_in_bytes) {
     ASSERT(Utils::RangeCheck(src_offset_in_bytes, length_in_bytes,
@@ -10519,10 +10534,9 @@
     }
   }
 
-  template <typename DstType, typename SrcType>
-  static void ClampedCopy(const DstType& dst,
+  static void ClampedCopy(const TypedDataBase& dst,
                           intptr_t dst_offset_in_bytes,
-                          const SrcType& src,
+                          const TypedDataBase& src,
                           intptr_t src_offset_in_bytes,
                           intptr_t length_in_bytes) {
     ASSERT(Utils::RangeCheck(src_offset_in_bytes, length_in_bytes,
@@ -10580,29 +10594,6 @@
   // snapshot. Should be independent of word size.
   static const int kDataSerializationAlignment = 8;
 
-#define TYPED_GETTER_SETTER(name, type)                                        \
-  type Get##name(intptr_t byte_offset) const {                                 \
-    return LoadUnaligned(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_HandleFinalizer callback,
                                             intptr_t external_size) const;
@@ -11436,7 +11427,7 @@
     return RoundedAllocationSize(sizeof(UntaggedRegExp));
   }
 
-  static RegExpPtr New(Heap::Space space = Heap::kNew);
+  static RegExpPtr New(Zone* zone, Heap::Space space = Heap::kNew);
 
  private:
   void set_type(RegExType type) const {
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 655857e..a533e45 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -7,6 +7,7 @@
 #include "vm/native_entry.h"
 #include "vm/object.h"
 #include "vm/object_store.h"
+#include "vm/regexp.h"
 #include "vm/snapshot.h"
 #include "vm/stub_code.h"
 #include "vm/symbols.h"
@@ -1748,9 +1749,9 @@
                            Snapshot::Kind kind,
                            bool as_reference) {
   ASSERT(reader != NULL);
-
   // Allocate RegExp object.
-  RegExp& regex = RegExp::ZoneHandle(reader->zone(), RegExp::New());
+  RegExp& regex =
+      RegExp::ZoneHandle(reader->zone(), RegExp::New(reader->zone()));
   reader->AddBackRef(object_id, &regex, kIsDeserialized);
 
   // Read and Set all the other fields.
@@ -1766,14 +1767,6 @@
   regex.StoreNonPointer(&regex.untag()->num_two_byte_registers_,
                         reader->Read<int32_t>());
   regex.StoreNonPointer(&regex.untag()->type_flags_, reader->Read<int8_t>());
-
-  const Function& no_function = Function::Handle(reader->zone());
-  for (intptr_t cid = kOneByteStringCid; cid <= kExternalTwoByteStringCid;
-       cid++) {
-    regex.set_function(cid, /*sticky=*/false, no_function);
-    regex.set_function(cid, /*sticky=*/true, no_function);
-  }
-
   return regex.ptr();
 }
 
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index 782ecd1..bceb4e7 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -5515,12 +5515,12 @@
   return result;
 }
 
-static void CreateSpecializedFunction(Thread* thread,
-                                      Zone* zone,
-                                      const RegExp& regexp,
-                                      intptr_t specialization_cid,
-                                      bool sticky,
-                                      const Object& owner) {
+void CreateSpecializedFunction(Thread* thread,
+                               Zone* zone,
+                               const RegExp& regexp,
+                               intptr_t specialization_cid,
+                               bool sticky,
+                               const Object& owner) {
   const intptr_t kParamCount = RegExpMacroAssembler::kParamCount;
 
   const FunctionType& signature =
@@ -5569,7 +5569,7 @@
                                      const String& pattern,
                                      RegExpFlags flags) {
   Zone* zone = thread->zone();
-  const RegExp& regexp = RegExp::Handle(RegExp::New());
+  const RegExp& regexp = RegExp::Handle(RegExp::New(zone));
 
   regexp.set_pattern(pattern);
   regexp.set_flags(flags);
diff --git a/runtime/vm/regexp.h b/runtime/vm/regexp.h
index 3fed61b..9c2b8e9 100644
--- a/runtime/vm/regexp.h
+++ b/runtime/vm/regexp.h
@@ -1517,6 +1517,13 @@
   static void DotPrint(const char* label, RegExpNode* node, bool ignore_case);
 };
 
+void CreateSpecializedFunction(Thread* thread,
+                               Zone* zone,
+                               const RegExp& regexp,
+                               intptr_t specialization_cid,
+                               bool sticky,
+                               const Object& owner);
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_REGEXP_H_
diff --git a/sdk/lib/_internal/vm/lib/typed_data_patch.dart b/sdk/lib/_internal/vm/lib/typed_data_patch.dart
index b0c18d5..45b1dc9 100644
--- a/sdk/lib/_internal/vm/lib/typed_data_patch.dart
+++ b/sdk/lib/_internal/vm/lib/typed_data_patch.dart
@@ -58,7 +58,11 @@
 // to instances of _TypeListBase. Instead the subclasses use type specific
 // mixins (like _IntListMixin, _DoubleListMixin) to implement ListBase<T>.
 abstract class _TypedListBase {
-  int get length;
+  @pragma("vm:recognized", "graph-intrinsic")
+  @pragma("vm:exact-result-type", "dart:core#_Smi")
+  @pragma("vm:prefer-inline")
+  int get length native "TypedDataBase_length";
+
   int get elementSizeInBytes;
   int get offsetInBytes;
   _ByteBuffer get buffer;
@@ -108,8 +112,13 @@
   // match the cids of 'this' and 'from'.
   // Uses toCid and fromCid to decide if clamping is necessary.
   // Element size of toCid and fromCid must match (test at caller).
-  bool _setRange(int startInBytes, int lengthInBytes, _TypedListBase from,
-      int startFromInBytes, int toCid, int fromCid) native "TypedData_setRange";
+  bool _setRange(
+      int startInBytes,
+      int lengthInBytes,
+      _TypedListBase from,
+      int startFromInBytes,
+      int toCid,
+      int fromCid) native "TypedDataBase_setRange";
 }
 
 mixin _IntListMixin implements List<int> {
@@ -2035,13 +2044,6 @@
 
   _ByteBuffer get buffer => new _ByteBuffer(this);
 
-  // Methods implementing the collection interface.
-
-  @pragma("vm:recognized", "graph-intrinsic")
-  @pragma("vm:exact-result-type", "dart:core#_Smi")
-  @pragma("vm:prefer-inline")
-  int get length native "TypedData_length";
-
   // Internal utility methods.
 
   @pragma("vm:recognized", "other")
@@ -4009,11 +4011,6 @@
   @pragma("vm:exact-result-type", "dart:core#_Smi")
   @pragma("vm:prefer-inline")
   int get offsetInBytes native "TypedDataView_offsetInBytes";
-
-  @pragma("vm:recognized", "graph-intrinsic")
-  @pragma("vm:exact-result-type", "dart:core#_Smi")
-  @pragma("vm:prefer-inline")
-  int get length native "TypedDataView_length";
 }
 
 @pragma("vm:entry-point")
@@ -4859,7 +4856,7 @@
   @pragma("vm:recognized", "graph-intrinsic")
   @pragma("vm:exact-result-type", "dart:core#_Smi")
   @pragma("vm:prefer-inline")
-  int get length native "TypedDataView_length";
+  int get length native "TypedDataBase_length";
 }
 
 @pragma("vm:prefer-inline")
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 8e3de55..d649a5d 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -56,6 +56,9 @@
 regexp/global_test: Skip # Issue 21709
 regexp/pcre_test: Slow, Pass
 
+[ $runtime != vm ]
+reg_exp_receive_port_test : Skip # uses SendPort/ReceivePort
+
 [ $hot_reload || $hot_reload_rollback ]
 bigint_parse_radix_test: Skip # Issue 31659. Issue 34361.
 bigint_test: Skip # Issue 31659
diff --git a/tests/corelib/reg_exp_receive_port_test.dart b/tests/corelib/reg_exp_receive_port_test.dart
new file mode 100644
index 0000000..e894f30
--- /dev/null
+++ b/tests/corelib/reg_exp_receive_port_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Checks that you can send and receive regex in a message.
+
+import "dart:async";
+import "dart:isolate";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+main(args) async {
+  asyncStart();
+  final rp = ReceivePort();
+  final r = RegExp('b');
+  Expect.equals(r.firstMatch('bb')!.start, 0);
+  rp.sendPort.send(r);
+
+  final si = StreamIterator(rp);
+  await si.moveNext();
+  final x = si.current as RegExp;
+  Expect.equals(x.firstMatch('bb')!.start, 0);
+  rp.close();
+  asyncEnd();
+}
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index 8759284..5353258 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -16,6 +16,9 @@
 [ $runtime != none ]
 string_runes_test: Skip # See breaking change #40674
 
+[ $runtime != vm ]
+reg_exp_receive_port_test: Skip # uses SendPort/ReceivePort
+
 [ $system == android ]
 throw_half_surrogate_pair_test/*: Skip # Issue http://dartbug.com/42094
 
diff --git a/tests/corelib_2/reg_exp_receive_port_test.dart b/tests/corelib_2/reg_exp_receive_port_test.dart
new file mode 100644
index 0000000..a63f289
--- /dev/null
+++ b/tests/corelib_2/reg_exp_receive_port_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Checks that you can send and receive regex in a message.
+
+import "dart:async";
+import "dart:isolate";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+main(args) async {
+  asyncStart();
+  final rp = ReceivePort();
+  final r = RegExp('b');
+  final match = r.firstMatch('bb');
+  Expect.equals(match != null ? match.start : null, 0);
+  rp.sendPort.send(r);
+
+  final si = StreamIterator(rp);
+  await si.moveNext();
+  final x = si.current as RegExp;
+  final matchX = x.firstMatch('bb');
+  Expect.equals(matchX != null ? matchX.start : null, 0);
+  rp.close();
+  asyncEnd();
+}
diff --git a/tools/VERSION b/tools/VERSION
index a229bf4..9251a79 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 190
+PRERELEASE 191
 PRERELEASE_PATCH 0
\ No newline at end of file