Version 2.15.0-39.0.dev

Merge commit '3238d433faa3e31df2c3a8b671be1e225526e7b0' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index e70c308..b347d13 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -265,6 +265,12 @@
       "languageVersion": "2.12"
     },
     {
+      "name": "devtools_server",
+      "rootUri": "../third_party/devtools/devtools_server",
+      "packageUri": "lib/",
+      "languageVersion": "2.12"
+    },
+    {
       "name": "devtools_shared",
       "rootUri": "../third_party/devtools/devtools_shared",
       "packageUri": "lib/",
diff --git a/.packages b/.packages
index b22e6a2..d5fdbc9 100644
--- a/.packages
+++ b/.packages
@@ -39,6 +39,7 @@
 dartdoc:third_party/pkg/dartdoc/lib
 dds:pkg/dds/lib
 dev_compiler:pkg/dev_compiler/lib
+devtools_server:third_party/devtools/devtools_server/lib
 devtools_shared:third_party/devtools/devtools_shared/lib
 diagnostic:pkg/diagnostic/lib
 expect:pkg/expect/lib
diff --git a/DEPS b/DEPS
index 402eae5..1e12e6a 100644
--- a/DEPS
+++ b/DEPS
@@ -106,7 +106,7 @@
   "dart_style_rev": "14d9b6fd58cc4744676c12be3cc5eee2a779db82",
 
   "dartdoc_rev" : "5f39ec674d81f5c199151d823fa4ecd01fc59eb2",
-  "devtools_rev" : "64cffbed6366329ad05e44d48fa2298367643bb6",
+  "devtools_rev" : "2b47d9ed486479153ca2fd038000950674ed1beb",
   "jsshell_tag": "version:88.0",
   "ffi_rev": "4dd32429880a57b64edaf54c9d5af8a9fa9a4ffb",
   "fixnum_rev": "16d3890c6dc82ca629659da1934e412292508bba",
diff --git a/benchmarks/SDKArtifactSizes/dart/SDKArtifactSizes.dart b/benchmarks/SDKArtifactSizes/dart/SDKArtifactSizes.dart
index 291ad67..7deaa33 100644
--- a/benchmarks/SDKArtifactSizes/dart/SDKArtifactSizes.dart
+++ b/benchmarks/SDKArtifactSizes/dart/SDKArtifactSizes.dart
@@ -33,9 +33,9 @@
   'pub',
 ];
 
-Future<void> reportArtifactSize(String path, String name) async {
+void reportFileSize(String path, String name) {
   try {
-    final size = await File(path).length();
+    final size = File(path).lengthSync();
     print('SDKArtifactSizes.$name(CodeSize): $size');
   } on FileSystemException {
     // Report dummy data for artifacts that don't exist for specific platforms.
@@ -43,43 +43,43 @@
   }
 }
 
-Future<void> main() async {
+void reportDirectorySize(String path, String name) async {
+  final dir = Directory(path);
+
+  try {
+    final size = dir
+        .listSync(recursive: true, followLinks: false)
+        .whereType<File>()
+        .map((file) => file.lengthSync())
+        .fold<int>(0, (a, b) => a + b);
+    print('SDKArtifactSizes.$name(CodeSize): $size');
+  } on FileSystemException {
+    // Report dummy data on errors.
+    print('SDKArtifactSizes.$name(CodeSize): 0');
+  }
+}
+
+void main() {
   final topDirIndex =
       Platform.resolvedExecutable.lastIndexOf(Platform.pathSeparator);
   final rootDir = Platform.resolvedExecutable.substring(0, topDirIndex);
 
   for (final executable in executables) {
     final executablePath = '$rootDir/dart-sdk/bin/$executable';
-    await reportArtifactSize(executablePath, executable);
+    reportFileSize(executablePath, executable);
   }
 
   for (final lib in libs) {
     final libPath = '$rootDir/dart-sdk/lib/_internal/$lib';
-    await reportArtifactSize(libPath, lib);
+    reportFileSize(libPath, lib);
   }
 
   for (final snapshot in snapshots) {
     final snapshotPath =
         '$rootDir/dart-sdk/bin/snapshots/$snapshot.dart.snapshot';
-    await reportArtifactSize(snapshotPath, snapshot);
+    reportFileSize(snapshotPath, snapshot);
   }
 
-  // Measure the (compressed) sdk size.
-  final tempDir = Directory.systemTemp.createTempSync('dartdev');
-  final sdkArchive = compress(Directory('$rootDir/dart-sdk'), tempDir);
-  await reportArtifactSize(sdkArchive?.path ?? '', 'sdk');
-  tempDir.deleteSync(recursive: true);
-}
-
-File? compress(Directory sourceDir, Directory targetDir) {
-  final outFile = File('${targetDir.path}/sdk.zip');
-
-  if (Platform.isMacOS || Platform.isLinux) {
-    Process.runSync(
-        'zip', ['-r', outFile.absolute.path, sourceDir.absolute.path]);
-  } else {
-    return null;
-  }
-
-  return outFile;
+  // Measure the sdk size.
+  reportDirectorySize('$rootDir/dart-sdk', 'sdk');
 }
diff --git a/benchmarks/SDKArtifactSizes/dart2/SDKArtifactSizes.dart b/benchmarks/SDKArtifactSizes/dart2/SDKArtifactSizes.dart
index f5b7f05..71e5a48 100644
--- a/benchmarks/SDKArtifactSizes/dart2/SDKArtifactSizes.dart
+++ b/benchmarks/SDKArtifactSizes/dart2/SDKArtifactSizes.dart
@@ -35,9 +35,9 @@
   'pub',
 ];
 
-Future<void> reportArtifactSize(String path, String name) async {
+void reportFileSize(String path, String name) {
   try {
-    final size = await File(path).length();
+    final size = File(path).lengthSync();
     print('SDKArtifactSizes.$name(CodeSize): $size');
   } on FileSystemException {
     // Report dummy data for artifacts that don't exist for specific platforms.
@@ -45,43 +45,43 @@
   }
 }
 
-Future<void> main() async {
+void reportDirectorySize(String path, String name) async {
+  final dir = Directory(path);
+
+  try {
+    final size = dir
+        .listSync(recursive: true, followLinks: false)
+        .whereType<File>()
+        .map((file) => file.lengthSync())
+        .fold<int>(0, (a, b) => a + b);
+    print('SDKArtifactSizes.$name(CodeSize): $size');
+  } on FileSystemException {
+    // Report dummy data on errors.
+    print('SDKArtifactSizes.$name(CodeSize): 0');
+  }
+}
+
+void main() {
   final topDirIndex =
       Platform.resolvedExecutable.lastIndexOf(Platform.pathSeparator);
   final rootDir = Platform.resolvedExecutable.substring(0, topDirIndex);
 
   for (final executable in executables) {
     final executablePath = '$rootDir/dart-sdk/bin/$executable';
-    await reportArtifactSize(executablePath, executable);
+    reportFileSize(executablePath, executable);
   }
 
   for (final lib in libs) {
     final libPath = '$rootDir/dart-sdk/lib/_internal/$lib';
-    await reportArtifactSize(libPath, lib);
+    reportFileSize(libPath, lib);
   }
 
   for (final snapshot in snapshots) {
     final snapshotPath =
         '$rootDir/dart-sdk/bin/snapshots/$snapshot.dart.snapshot';
-    await reportArtifactSize(snapshotPath, snapshot);
+    reportFileSize(snapshotPath, snapshot);
   }
 
-  // Measure the (compressed) sdk size.
-  final tempDir = Directory.systemTemp.createTempSync('dartdev');
-  final sdkArchive = compress(Directory('$rootDir/dart-sdk'), tempDir);
-  await reportArtifactSize(sdkArchive?.path ?? '', 'sdk');
-  tempDir.deleteSync(recursive: true);
-}
-
-File compress(Directory sourceDir, Directory targetDir) {
-  final outFile = File('${targetDir.path}/sdk.zip');
-
-  if (Platform.isMacOS || Platform.isLinux) {
-    Process.runSync(
-        'zip', ['-r', outFile.absolute.path, sourceDir.absolute.path]);
-  } else {
-    return null;
-  }
-
-  return outFile;
+  // Measure the sdk size.
+  reportDirectorySize('$rootDir/dart-sdk', 'sdk');
 }
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 1b7a17f..76b327e 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -405,6 +405,7 @@
   CompileTimeErrorCode.SUPER_INITIALIZER_IN_OBJECT,
   CompileTimeErrorCode.SWITCH_CASE_COMPLETES_NORMALLY,
   CompileTimeErrorCode.SWITCH_EXPRESSION_NOT_ASSIGNABLE,
+  CompileTimeErrorCode.TEAROFF_OF_GENERATIVE_CONSTRUCTOR_OF_ABSTRACT_CLASS,
   CompileTimeErrorCode.THROW_OF_INVALID_TYPE,
   CompileTimeErrorCode.TOP_LEVEL_CYCLE,
   CompileTimeErrorCode.TYPE_ALIAS_CANNOT_REFERENCE_ITSELF,
diff --git a/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
index ac1868d..35706f4 100644
--- a/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/constructor_reference_resolver.dart
@@ -25,6 +25,17 @@
           HintCode.SDK_VERSION_CONSTRUCTOR_TEAROFFS, node, []);
     }
     node.constructorName.accept(_resolver);
+    var element = node.constructorName.staticElement;
+    if (element != null &&
+        !element.isFactory &&
+        element.enclosingElement.isAbstract) {
+      _resolver.errorReporter.reportErrorForNode(
+        CompileTimeErrorCode
+            .TEAROFF_OF_GENERATIVE_CONSTRUCTOR_OF_ABSTRACT_CLASS,
+        node,
+        [],
+      );
+    }
     _inferArgumentTypes(node);
   }
 
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index cadf3c7..f48af7c 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -12550,6 +12550,17 @@
           hasPublishedDocs: true);
 
   /**
+   * No parameters.
+   */
+  static const CompileTimeErrorCode
+      TEAROFF_OF_GENERATIVE_CONSTRUCTOR_OF_ABSTRACT_CLASS =
+      CompileTimeErrorCode(
+          'TEAROFF_OF_GENERATIVE_CONSTRUCTOR_OF_ABSTRACT_CLASS',
+          "A generative constructor of an abstract class can't be torn off",
+          correction: "Try tearing off a constructor of a concrete class, or a "
+              "non-generative constructor.");
+
+  /**
    * Parameters:
    * 0: the type that can't be thrown
    */
diff --git a/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart
index 21b86f7..5d29577 100644
--- a/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/constructor_reference_test.dart
@@ -389,6 +389,85 @@
 
 @reflectiveTest
 class ConstructorReferenceResolutionTest extends PubPackageResolutionTest {
+  test_abstractClass_factory() async {
+    await assertNoErrorsInCode('''
+abstract class A {
+  factory A() => A2();
+}
+
+class A2 implements A {}
+
+foo() {
+  A.new;
+}
+''');
+
+    var classElement = findElement.class_('A');
+    assertConstructorReference(
+      findNode.constructorReference('A.new;'),
+      classElement.unnamedConstructor,
+      classElement,
+      'A Function()',
+      expectedTypeNameType: 'A',
+    );
+  }
+
+  test_abstractClass_generative() async {
+    await assertErrorsInCode('''
+abstract class A {
+  A();
+}
+
+foo() {
+  A.new;
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .TEAROFF_OF_GENERATIVE_CONSTRUCTOR_OF_ABSTRACT_CLASS,
+          39,
+          5),
+    ]);
+
+    var classElement = findElement.class_('A');
+    assertConstructorReference(
+      findNode.constructorReference('A.new;'),
+      classElement.unnamedConstructor,
+      classElement,
+      'A Function()',
+      expectedTypeNameType: 'A',
+    );
+  }
+
+  test_abstractClass_redirecting() async {
+    await assertErrorsInCode('''
+abstract class A {
+  A(): this.two();
+
+  A.two();
+}
+
+foo() {
+  A.new;
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .TEAROFF_OF_GENERATIVE_CONSTRUCTOR_OF_ABSTRACT_CLASS,
+          63,
+          5),
+    ]);
+
+    var classElement = findElement.class_('A');
+    assertConstructorReference(
+      findNode.constructorReference('A.new;'),
+      classElement.unnamedConstructor,
+      classElement,
+      'A Function()',
+      expectedTypeNameType: 'A',
+    );
+  }
+
   test_class_generic_inferFromContext_badTypeArgument() async {
     await assertErrorsInCode('''
 class A<T extends num> {
diff --git a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
index 4947dab..c39a339 100644
--- a/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/function_reference_test.dart
@@ -24,8 +24,8 @@
       error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 10, 1),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_explicitReceiver_unknown_multipleProperties() async {
@@ -37,8 +37,8 @@
       error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 10, 1),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_extensionGetter_extensionOverride() async {
@@ -57,8 +57,8 @@
           CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION, 67, 8),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(findNode.functionReference('foo<int>;'),
+        findElement.getter('foo'), 'dynamic');
   }
 
   test_extensionMethod() async {
@@ -173,8 +173,8 @@
       error(CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER, 51, 3),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_extensionMethod_fromClassDeclaration() async {
@@ -210,8 +210,8 @@
           CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION, 66, 3),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'void Function(int)');
+    assertFunctionReference(findNode.functionReference('foo<int>;'),
+        findElement.getter('foo'), 'void Function(int)');
   }
 
   test_instanceGetter_explicitReceiver() async {
@@ -228,8 +228,8 @@
           CompileTimeErrorCode.DISALLOWED_TYPE_INSTANTIATION_EXPRESSION, 58, 5),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'void Function(int)');
+    assertFunctionReference(findNode.functionReference('foo<int>;'),
+        findElement.getter('foo'), 'void Function(int)');
   }
 
   test_instanceMethod() async {
@@ -279,8 +279,8 @@
 }
 ''');
 
-    var reference = findNode.functionReference('(a ?? b).foo<int>;');
-    assertType(reference, 'void Function(int)');
+    assertFunctionReference(findNode.functionReference('(a ?? b).foo<int>;'),
+        findElement.method('foo'), 'void Function(int)');
   }
 
   test_instanceMethod_explicitReceiver_super() async {
@@ -311,8 +311,8 @@
       error(CompileTimeErrorCode.UNDEFINED_SUPER_GETTER, 30, 3),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_instanceMethod_explicitReceiver_super_noSuper() async {
@@ -324,8 +324,8 @@
       error(CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, 10, 5),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_instanceMethod_explicitReceiver_this() async {
@@ -403,8 +403,8 @@
 
     assertImportPrefix(
         findNode.simple('prefix.'), findElement.prefix('prefix'));
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_instanceMethod_explicitReceiver_typeParameter() async {
@@ -416,8 +416,8 @@
       error(CompileTimeErrorCode.UNDEFINED_GETTER, 15, 3),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_instanceMethod_explicitReceiver_variable() async {
@@ -481,8 +481,8 @@
       error(CompileTimeErrorCode.UNDEFINED_METHOD, 24, 3),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_localFunction() async {
@@ -560,6 +560,7 @@
 
     var reference = findNode.functionReference('(1 == 2 ? foo : bar)<int>;');
     assertType(reference, 'void Function(int)');
+    // A ParenthesizedExpression has no element to assert on.
   }
 
   test_otherExpression_wrongNumberOfTypeArguments() async {
@@ -580,6 +581,7 @@
     var reference =
         findNode.functionReference('(1 == 2 ? foo : bar)<int, String>;');
     assertType(reference, 'void Function(dynamic)');
+    // A ParenthesizedExpression has no element to assert on.
   }
 
   test_receiverIsDynamic() async {
@@ -592,8 +594,8 @@
           19, 5),
     ]);
 
-    var reference = findNode.functionReference('a.foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('a.foo<int>;'), null, 'dynamic');
   }
 
   test_staticMethod() async {
@@ -624,9 +626,8 @@
 ''');
 
     assertClassRef(findNode.simple('A.'), findElement.class_('A'));
-    var reference = findNode.functionReference('foo<int>;');
-    assertElement(reference, findElement.method('foo'));
-    assertType(reference, 'void Function(int)');
+    assertFunctionReference(findNode.functionReference('foo<int>;'),
+        findElement.method('foo'), 'void Function(int)');
   }
 
   test_staticMethod_explicitReceiver_importPrefix() async {
@@ -800,8 +801,8 @@
       error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 10, 6),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_topLevelVariable_prefix_unknownIdentifier() async {
@@ -818,8 +819,8 @@
 
     assertImportPrefix(
         findNode.simple('prefix.'), findElement.prefix('prefix'));
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_typeAlias_function_unknownProperty() async {
@@ -831,8 +832,8 @@
       error(CompileTimeErrorCode.UNDEFINED_GETTER, 42, 3),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_typeAlias_typeVariable_unknownProperty() async {
@@ -844,8 +845,8 @@
       error(CompileTimeErrorCode.UNDEFINED_GETTER, 29, 3),
     ]);
 
-    var reference = findNode.functionReference('foo<int>;');
-    assertType(reference, 'dynamic');
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_unknownIdentifier() async {
@@ -856,6 +857,9 @@
 ''', [
       error(CompileTimeErrorCode.UNDEFINED_IDENTIFIER, 15, 3),
     ]);
+
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_unknownIdentifier_explicitReceiver() async {
@@ -870,6 +874,9 @@
 ''', [
       error(CompileTimeErrorCode.UNDEFINED_GETTER, 41, 3),
     ]);
+
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 
   test_unknownIdentifier_importPrefix() async {
@@ -883,5 +890,8 @@
 ''', [
       error(CompileTimeErrorCode.UNDEFINED_PREFIXED_NAME, 40, 3),
     ]);
+
+    assertFunctionReference(
+        findNode.functionReference('foo<int>;'), null, 'dynamic');
   }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index 514abe7..45fd9a6 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -364,7 +364,7 @@
   }
 
   void assertFunctionReference(
-      FunctionReference node, Element expectedElement, String expectedType) {
+      FunctionReference node, Element? expectedElement, String expectedType) {
     assertElement(node, expectedElement);
     assertType(node, expectedType);
   }
diff --git a/pkg/analyzer/test/src/diagnostics/tearoff_of_generative_constructor_of_abstract_class_test.dart b/pkg/analyzer/test/src/diagnostics/tearoff_of_generative_constructor_of_abstract_class_test.dart
new file mode 100644
index 0000000..39265e5
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/tearoff_of_generative_constructor_of_abstract_class_test.dart
@@ -0,0 +1,104 @@
+// Copyright (c) 2021, 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.
+
+import 'package:analyzer/src/error/codes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(TearoffOfGenerativeConstructorOfAbstractClassTest);
+  });
+}
+
+@reflectiveTest
+class TearoffOfGenerativeConstructorOfAbstractClassTest
+    extends PubPackageResolutionTest {
+  test_abstractClass_factoryConstructor() async {
+    await assertNoErrorsInCode('''
+abstract class A {
+  factory A() => B();
+}
+
+class B implements A {}
+
+void foo() {
+  A.new;
+}
+''');
+  }
+
+  test_abstractClass_factoryConstructor_viaEquals() async {
+    await assertNoErrorsInCode('''
+abstract class A {
+  factory A() = B;
+}
+
+class B implements A {}
+
+void foo() {
+  A.new;
+}
+''');
+  }
+
+  test_abstractClass_generativeConstructor() async {
+    await assertErrorsInCode('''
+abstract class A {
+  A();
+}
+
+void foo() {
+  A.new;
+}
+''', [
+      error(
+          CompileTimeErrorCode
+              .TEAROFF_OF_GENERATIVE_CONSTRUCTOR_OF_ABSTRACT_CLASS,
+          44,
+          5),
+    ]);
+  }
+
+  test_concreteClass_factoryConstructor() async {
+    await assertNoErrorsInCode('''
+class A {
+  factory A() => A.two();
+
+  A.two();
+}
+
+void foo() {
+  A.new;
+}
+''');
+  }
+
+  test_concreteClass_factoryConstructor_viaEquals() async {
+    await assertNoErrorsInCode('''
+class A {
+  factory A() = A.two;
+
+  A.two();
+}
+
+void foo() {
+  A.new;
+}
+''');
+  }
+
+  test_concreteClass_generativeConstructor() async {
+    await assertNoErrorsInCode('''
+class A {
+  A();
+}
+
+void foo() {
+  A.new;
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 176cb48..2d3ff59 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -628,6 +628,8 @@
     as switch_case_completes_normally;
 import 'switch_expression_not_assignable_test.dart'
     as switch_expression_not_assignable;
+import 'tearoff_of_generative_constructor_of_abstract_class_test.dart'
+    as tearoff_of_generative_constructor_of_abstract_class;
 import 'throw_of_invalid_type_test.dart' as throw_of_invalid_type;
 import 'todo_test.dart' as todo_test;
 import 'top_level_cycle_test.dart' as top_level_cycle;
@@ -1129,6 +1131,7 @@
     super_initializer_in_object.main();
     switch_case_completes_normally.main();
     switch_expression_not_assignable.main();
+    tearoff_of_generative_constructor_of_abstract_class.main();
     throw_of_invalid_type.main();
     todo_test.main();
     top_level_cycle.main();
diff --git a/pkg/dartdev/.gitignore b/pkg/dartdev/.gitignore
index 0bd726b..493289d 100644
--- a/pkg/dartdev/.gitignore
+++ b/pkg/dartdev/.gitignore
@@ -4,10 +4,6 @@
 .project
 .settings/
 build/
-pubspec.lock
 
 # Directory created by dartdoc
 doc/api/
-
-# Directory created by pub
-.dart_tool/
diff --git a/pkg/dartdev/lib/dartdev.dart b/pkg/dartdev/lib/dartdev.dart
index 5895deb..fefffae 100644
--- a/pkg/dartdev/lib/dartdev.dart
+++ b/pkg/dartdev/lib/dartdev.dart
@@ -11,6 +11,7 @@
 import 'package:cli_util/cli_logging.dart';
 import 'package:dart_style/src/cli/format_command.dart';
 import 'package:dartdev/src/commands/migrate.dart';
+import 'package:devtools_server/devtools_server.dart';
 import 'package:meta/meta.dart';
 import 'package:pedantic/pedantic.dart';
 import 'package:pub/pub.dart';
@@ -27,6 +28,7 @@
 import 'src/core.dart';
 import 'src/events.dart';
 import 'src/experiments.dart';
+import 'src/sdk.dart';
 import 'src/utils.dart';
 import 'src/vm_interop_handler.dart';
 
@@ -101,6 +103,13 @@
     addCommand(AnalyzeCommand(verbose: verbose));
     addCommand(CreateCommand(verbose: verbose));
     addCommand(CompileCommand(verbose: verbose));
+    addCommand(DevToolsCommand(
+      verbose: verbose,
+      // TODO(devoncarew): Un-hide this command after a stabilization period
+      // likely before the next stable release (before Dart 2.15).
+      hidden: !verbose,
+      customDevToolsPath: sdk.devToolsBinaries,
+    ));
     addCommand(FixCommand(verbose: verbose));
     addCommand(FormatCommand(verbose: verbose));
     addCommand(LanguageServerCommand(verbose: verbose));
@@ -116,6 +125,7 @@
   @override
   String get invocation =>
       'dart ${verbose ? '[vm-options] ' : ''}<command|dart-file> [arguments]';
+
   @override
   String get usageFooter =>
       'See https://dart.dev/tools/dart-tool for detailed documentation.';
diff --git a/pkg/dartdev/pubspec.yaml b/pkg/dartdev/pubspec.yaml
index 3887bdf..5f509c2 100644
--- a/pkg/dartdev/pubspec.yaml
+++ b/pkg/dartdev/pubspec.yaml
@@ -12,11 +12,12 @@
     path: ../analysis_server_client
   analyzer:
     path: ../analyzer
-  args: ^1.6.0
-  cli_util: '>=0.1.4 <0.3.0'
+  args: any
+  cli_util: any
   dart2native:
     path: ../dart2native
   dart_style: any
+  devtools_server: any
   front_end:
     path: ../front_end
   intl: any
@@ -24,15 +25,15 @@
     path: ../meta
   nnbd_migration:
     path: ../nnbd_migration
-  path: ^1.0.0
-  pedantic: ^1.9.0
+  path: any
+  pedantic: any
   pub: any
   telemetry:
     path: ../telemetry
-  usage: ^3.4.0
+  usage: any
 
 dev_dependencies:
   lints: any
   pub_semver: any
-  test: ^1.0.0
+  test: any
   yaml: any
diff --git a/pkg/dartdev/test/commands/devtools_test.dart b/pkg/dartdev/test/commands/devtools_test.dart
new file mode 100644
index 0000000..37bc32e
--- /dev/null
+++ b/pkg/dartdev/test/commands/devtools_test.dart
@@ -0,0 +1,94 @@
+// Copyright (c) 2021, 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.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:test/test.dart';
+
+import '../utils.dart';
+
+void main() {
+  group('devtools', devtools, timeout: longTimeout);
+}
+
+void devtools() {
+  TestProject p;
+
+  tearDown(() => p?.dispose());
+
+  test('--help', () {
+    p = project();
+    var result = p.runSync(['devtools', '--help']);
+    expect(result.exitCode, 0);
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, contains('Open DevTools'));
+    expect(result.stdout,
+        contains('Usage: dart devtools [arguments] [service protocol uri]'));
+
+    // Does not show verbose help.
+    expect(result.stdout.contains('--try-ports'), isFalse);
+  });
+
+  test('--help --verbose', () {
+    p = project();
+    var result = p.runSync(['devtools', '--help', '--verbose']);
+    expect(result.exitCode, 0);
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, contains('Open DevTools'));
+    expect(result.stdout,
+        contains('Usage: dart devtools [arguments] [service protocol uri]'));
+
+    // Shows verbose help.
+    expect(result.stdout, contains('--try-ports'));
+  });
+
+  group('integration', () {
+    Process process;
+
+    tearDown(() {
+      process?.kill();
+    });
+
+    test('serves resources', () async {
+      p = project();
+
+      // start the devtools server
+      process = await p.start(['devtools', '--no-launch-browser', '--machine']);
+
+      final Stream<String> inStream = process.stdout
+          .transform<String>(utf8.decoder)
+          .transform<String>(const LineSplitter());
+
+      final line = await inStream.first;
+      final json = jsonDecode(line);
+
+      // {"event":"server.started","method":"server.started","params":{
+      //   "host":"127.0.0.1","port":9100,"pid":93508,"protocolVersion":"1.1.0"
+      // }}
+      expect(json['event'], 'server.started');
+      expect(json['params'], isNotNull);
+
+      final host = json['params']['host'];
+      final port = json['params']['port'];
+      expect(host, isA<String>());
+      expect(port, isA<int>());
+
+      // Connect to the port and confirm we can load a devtools resource.
+      HttpClient client = HttpClient();
+      final httpRequest = await client.get(host, port, 'index.html');
+      final httpResponse = await httpRequest.close();
+
+      final contents =
+          (await httpResponse.transform(utf8.decoder).toList()).join();
+      client.close();
+
+      expect(contents, contains('DevTools'));
+
+      // kill the process
+      process.kill();
+      process = null;
+    });
+  });
+}
diff --git a/runtime/tests/vm/dart/isolates/long_regexp_process_oob_messages_test.dart b/runtime/tests/vm/dart/isolates/long_regexp_process_oob_messages_test.dart
new file mode 100644
index 0000000..404b978
--- /dev/null
+++ b/runtime/tests/vm/dart/isolates/long_regexp_process_oob_messages_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, 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.
+
+import 'dart:isolate';
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+worker(SendPort sendPort) {
+  final re = RegExp(r'(x+)*y');
+  final s = 'x' * 100 + '';
+  sendPort.send('worker started');
+  print(re.allMatches(s).iterator.moveNext());
+}
+
+main() async {
+  asyncStart();
+  ReceivePort onExit = ReceivePort();
+  ReceivePort workerStarted = ReceivePort();
+  final isolate = await Isolate.spawn(worker, workerStarted.sendPort,
+      onExit: onExit.sendPort, errorsAreFatal: true);
+  await workerStarted.first;
+  print('worker started, now killing worker');
+  isolate.kill(priority: Isolate.immediate);
+  await onExit.first;
+  print('worker exited');
+  asyncEnd();
+}
diff --git a/runtime/tests/vm/dart_2/isolates/long_regexp_process_oob_messages_test.dart b/runtime/tests/vm/dart_2/isolates/long_regexp_process_oob_messages_test.dart
new file mode 100644
index 0000000..404b978
--- /dev/null
+++ b/runtime/tests/vm/dart_2/isolates/long_regexp_process_oob_messages_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, 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.
+
+import 'dart:isolate';
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+worker(SendPort sendPort) {
+  final re = RegExp(r'(x+)*y');
+  final s = 'x' * 100 + '';
+  sendPort.send('worker started');
+  print(re.allMatches(s).iterator.moveNext());
+}
+
+main() async {
+  asyncStart();
+  ReceivePort onExit = ReceivePort();
+  ReceivePort workerStarted = ReceivePort();
+  final isolate = await Isolate.spawn(worker, workerStarted.sendPort,
+      onExit: onExit.sendPort, errorsAreFatal: true);
+  await workerStarted.first;
+  print('worker started, now killing worker');
+  isolate.kill(priority: Isolate.immediate);
+  await onExit.first;
+  print('worker exited');
+  asyncEnd();
+}
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index 5d41659..f8b17ab 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -717,6 +717,13 @@
       Dart_KernelCompilationVerbosityLevel verbosity) {
     // Build the message for the Kernel isolate.
     // tag is used to specify which operation the frontend should perform.
+    if (port_ == ILLEGAL_PORT) {
+      Dart_KernelCompilationResult result = {};
+      result.status = Dart_KernelCompilationStatus_Unknown;
+      result.error =
+          Utils::StrDup("Error Kernel Isolate : unable to create reply port");
+      return result;
+    }
     Dart_CObject tag;
     tag.type = Dart_CObject_kInt32;
     tag.value.as_int32 = request_tag;
diff --git a/runtime/vm/regexp_assembler_bytecode.cc b/runtime/vm/regexp_assembler_bytecode.cc
index 708297a..dbd71e2 100644
--- a/runtime/vm/regexp_assembler_bytecode.cc
+++ b/runtime/vm/regexp_assembler_bytecode.cc
@@ -468,13 +468,13 @@
          (regexp.num_bracket_expressions() + 1) * 2;
 }
 
-static IrregexpInterpreter::IrregexpResult ExecRaw(const RegExp& regexp,
-                                                   const String& subject,
-                                                   intptr_t index,
-                                                   bool sticky,
-                                                   int32_t* output,
-                                                   intptr_t output_size,
-                                                   Zone* zone) {
+static ObjectPtr ExecRaw(const RegExp& regexp,
+                         const String& subject,
+                         intptr_t index,
+                         bool sticky,
+                         int32_t* output,
+                         intptr_t output_size,
+                         Zone* zone) {
   bool is_one_byte =
       subject.IsOneByteString() || subject.IsExternalOneByteString();
 
@@ -493,14 +493,16 @@
   const TypedData& bytecode =
       TypedData::Handle(zone, regexp.bytecode(is_one_byte, sticky));
   ASSERT(!bytecode.IsNull());
-  IrregexpInterpreter::IrregexpResult result =
-      IrregexpInterpreter::Match(bytecode, subject, raw_output, index, zone);
+  const Object& result = Object::Handle(
+      zone,
+      IrregexpInterpreter::Match(bytecode, subject, raw_output, index, zone));
 
-  if (result == IrregexpInterpreter::RE_SUCCESS) {
+  if (result.ptr() == Bool::True().ptr()) {
     // Copy capture results to the start of the registers array.
     memmove(output, raw_output, number_of_capture_registers * sizeof(int32_t));
   }
-  if (result == IrregexpInterpreter::RE_EXCEPTION) {
+  if (result.ptr() == Object::null()) {
+    // Exception during regexp processing
     Thread* thread = Thread::Current();
     auto isolate_group = thread->isolate_group();
     const Instance& exception =
@@ -508,14 +510,14 @@
     Exceptions::Throw(thread, exception);
     UNREACHABLE();
   }
-  return result;
+  return result.ptr();
 }
 
-InstancePtr BytecodeRegExpMacroAssembler::Interpret(const RegExp& regexp,
-                                                    const String& subject,
-                                                    const Smi& start_index,
-                                                    bool sticky,
-                                                    Zone* zone) {
+ObjectPtr BytecodeRegExpMacroAssembler::Interpret(const RegExp& regexp,
+                                                  const String& subject,
+                                                  const Smi& start_index,
+                                                  bool sticky,
+                                                  Zone* zone) {
   intptr_t required_registers = Prepare(regexp, subject, sticky, zone);
   if (required_registers < 0) {
     // Compiling failed with an exception.
@@ -525,11 +527,10 @@
   // V8 uses a shared copy on the isolate when smaller than some threshold.
   int32_t* output_registers = zone->Alloc<int32_t>(required_registers);
 
-  IrregexpInterpreter::IrregexpResult result =
-      ExecRaw(regexp, subject, start_index.Value(), sticky, output_registers,
-              required_registers, zone);
-
-  if (result == IrregexpInterpreter::RE_SUCCESS) {
+  const Object& result =
+      Object::Handle(zone, ExecRaw(regexp, subject, start_index.Value(), sticky,
+                                   output_registers, required_registers, zone));
+  if (result.ptr() == Bool::True().ptr()) {
     intptr_t capture_count = regexp.num_bracket_expressions();
     intptr_t capture_register_count = (capture_count + 1) * 2;
     ASSERT(required_registers >= capture_register_count);
@@ -553,10 +554,15 @@
 
     return result.ptr();
   }
-  if (result == IrregexpInterpreter::RE_EXCEPTION) {
+  if (result.ptr() == Object::null()) {
+    // internal exception
     UNREACHABLE();
   }
-  ASSERT(result == IrregexpInterpreter::RE_FAILURE);
+  if (result.IsError()) {
+    Exceptions::PropagateError(Error::Cast(result));
+    UNREACHABLE();
+  }
+  ASSERT(result.ptr() == Bool::False().ptr());
   return Instance::null();
 }
 
diff --git a/runtime/vm/regexp_assembler_bytecode.h b/runtime/vm/regexp_assembler_bytecode.h
index cdedaa1..6bb8f94 100644
--- a/runtime/vm/regexp_assembler_bytecode.h
+++ b/runtime/vm/regexp_assembler_bytecode.h
@@ -107,11 +107,11 @@
   virtual void PrintBlocks() { UNIMPLEMENTED(); }
   /////
 
-  static InstancePtr Interpret(const RegExp& regexp,
-                               const String& str,
-                               const Smi& start_index,
-                               bool is_sticky,
-                               Zone* zone);
+  static ObjectPtr Interpret(const RegExp& regexp,
+                             const String& str,
+                             const Smi& start_index,
+                             bool is_sticky,
+                             Zone* zone);
 
  private:
   void Expand();
diff --git a/runtime/vm/regexp_interpreter.cc b/runtime/vm/regexp_interpreter.cc
index eb0a243..d9248ac 100644
--- a/runtime/vm/regexp_interpreter.cc
+++ b/runtime/vm/regexp_interpreter.cc
@@ -4,11 +4,12 @@
 
 // A simple interpreter for the Irregexp byte code.
 
-#include "vm/regexp_interpreter.h"
-
 #include <memory>
 #include <utility>
 
+#include "heap/safepoint.h"
+#include "vm/regexp_interpreter.h"
+
 #include "platform/unicode.h"
 #include "vm/object.h"
 #include "vm/regexp_assembler.h"
@@ -169,14 +170,16 @@
   DISALLOW_COPY_AND_ASSIGN(BacktrackStack);
 };
 
+// Returns True if success, False if failure, Null if internal exception,
+// Error if VM error needs to be propagated up the callchain.
 template <typename Char>
-static IrregexpInterpreter::IrregexpResult RawMatch(const uint8_t* code_base,
-                                                    const String& subject,
-                                                    int32_t* registers,
-                                                    intptr_t current,
-                                                    uint32_t current_char,
-                                                    Zone* zone) {
-  const uint8_t* pc = code_base;
+static ObjectPtr RawMatch(const TypedData& bytecode,
+                          const String& subject,
+                          int32_t* registers,
+                          intptr_t current,
+                          uint32_t current_char,
+                          Zone* zone) {
+  const auto thread = Thread::Current();
   // BacktrackStack ensures that the memory allocated for the backtracking stack
   // is returned to the system or cached if there is no stack being cached at
   // the moment.
@@ -196,482 +199,506 @@
     OS::PrintErr("Start irregexp bytecode interpreter\n");
   }
 #endif
+  const uint8_t* code_base;
+  const uint8_t* pc;
+  {
+    NoSafepointScope no_safepoint;
+    code_base = reinterpret_cast<uint8_t*>(bytecode.DataAddr(0));
+    pc = code_base;
+  }
   while (true) {
-    int32_t insn = Load32Aligned(pc);
-    switch (insn & BYTECODE_MASK) {
-      BYTECODE(BREAK)
-      UNREACHABLE();
-      return IrregexpInterpreter::RE_FAILURE;
-      BYTECODE(PUSH_CP)
-      if (--backtrack_stack_space < 0) {
-        return IrregexpInterpreter::RE_EXCEPTION;
+    if (UNLIKELY(thread->HasScheduledInterrupts())) {
+      intptr_t pc_offset = pc - code_base;
+      ErrorPtr error = thread->HandleInterrupts();
+      if (error != Object::null()) {
+        // Needs to be propagated to the Dart native invoking the
+        // regex matcher.
+        return error;
       }
-      *backtrack_sp++ = current;
-      pc += BC_PUSH_CP_LENGTH;
-      break;
-      BYTECODE(PUSH_BT)
-      if (--backtrack_stack_space < 0) {
-        return IrregexpInterpreter::RE_EXCEPTION;
-      }
-      *backtrack_sp++ = Load32Aligned(pc + 4);
-      pc += BC_PUSH_BT_LENGTH;
-      break;
-      BYTECODE(PUSH_REGISTER)
-      if (--backtrack_stack_space < 0) {
-        return IrregexpInterpreter::RE_EXCEPTION;
-      }
-      *backtrack_sp++ = registers[insn >> BYTECODE_SHIFT];
-      pc += BC_PUSH_REGISTER_LENGTH;
-      break;
-      BYTECODE(SET_REGISTER)
-      registers[insn >> BYTECODE_SHIFT] = Load32Aligned(pc + 4);
-      pc += BC_SET_REGISTER_LENGTH;
-      break;
-      BYTECODE(ADVANCE_REGISTER)
-      registers[insn >> BYTECODE_SHIFT] += Load32Aligned(pc + 4);
-      pc += BC_ADVANCE_REGISTER_LENGTH;
-      break;
-      BYTECODE(SET_REGISTER_TO_CP)
-      registers[insn >> BYTECODE_SHIFT] = current + Load32Aligned(pc + 4);
-      pc += BC_SET_REGISTER_TO_CP_LENGTH;
-      break;
-      BYTECODE(SET_CP_TO_REGISTER)
-      current = registers[insn >> BYTECODE_SHIFT];
-      pc += BC_SET_CP_TO_REGISTER_LENGTH;
-      break;
-      BYTECODE(SET_REGISTER_TO_SP)
-      registers[insn >> BYTECODE_SHIFT] =
-          static_cast<int>(backtrack_sp - backtrack_stack_base);
-      pc += BC_SET_REGISTER_TO_SP_LENGTH;
-      break;
-      BYTECODE(SET_SP_TO_REGISTER)
-      backtrack_sp = backtrack_stack_base + registers[insn >> BYTECODE_SHIFT];
-      backtrack_stack_space =
-          backtrack_stack.max_size() -
-          static_cast<int>(backtrack_sp - backtrack_stack_base);
-      pc += BC_SET_SP_TO_REGISTER_LENGTH;
-      break;
-      BYTECODE(POP_CP)
-      backtrack_stack_space++;
-      --backtrack_sp;
-      current = *backtrack_sp;
-      pc += BC_POP_CP_LENGTH;
-      break;
-      BYTECODE(POP_BT)
-      backtrack_stack_space++;
-      --backtrack_sp;
-      pc = code_base + *backtrack_sp;
-      break;
-      BYTECODE(POP_REGISTER)
-      backtrack_stack_space++;
-      --backtrack_sp;
-      registers[insn >> BYTECODE_SHIFT] = *backtrack_sp;
-      pc += BC_POP_REGISTER_LENGTH;
-      break;
-      BYTECODE(FAIL)
-      return IrregexpInterpreter::RE_FAILURE;
-      BYTECODE(SUCCEED)
-      return IrregexpInterpreter::RE_SUCCESS;
-      BYTECODE(ADVANCE_CP)
-      current += insn >> BYTECODE_SHIFT;
-      pc += BC_ADVANCE_CP_LENGTH;
-      break;
-      BYTECODE(GOTO)
-      pc = code_base + Load32Aligned(pc + 4);
-      break;
-      BYTECODE(ADVANCE_CP_AND_GOTO)
-      current += insn >> BYTECODE_SHIFT;
-      pc = code_base + Load32Aligned(pc + 4);
-      break;
-      BYTECODE(CHECK_GREEDY)
-      if (current == backtrack_sp[-1]) {
-        backtrack_sp--;
+      NoSafepointScope no_safepoint;
+      code_base = reinterpret_cast<uint8_t*>(bytecode.DataAddr(0));
+      pc = code_base + pc_offset;
+    }
+    NoSafepointScope no_safepoint;
+    bool check_for_safepoint_now = false;
+    while (!check_for_safepoint_now) {
+      int32_t insn = Load32Aligned(pc);
+      switch (insn & BYTECODE_MASK) {
+        BYTECODE(BREAK)
+        UNREACHABLE();
+        return Bool::False().ptr();
+        BYTECODE(PUSH_CP)
+        if (--backtrack_stack_space < 0) {
+          return Object::null();
+        }
+        *backtrack_sp++ = current;
+        pc += BC_PUSH_CP_LENGTH;
+        break;
+        BYTECODE(PUSH_BT)
+        if (--backtrack_stack_space < 0) {
+          return Object::null();
+        }
+        *backtrack_sp++ = Load32Aligned(pc + 4);
+        pc += BC_PUSH_BT_LENGTH;
+        break;
+        BYTECODE(PUSH_REGISTER)
+        if (--backtrack_stack_space < 0) {
+          return Object::null();
+        }
+        *backtrack_sp++ = registers[insn >> BYTECODE_SHIFT];
+        pc += BC_PUSH_REGISTER_LENGTH;
+        break;
+        BYTECODE(SET_REGISTER)
+        registers[insn >> BYTECODE_SHIFT] = Load32Aligned(pc + 4);
+        pc += BC_SET_REGISTER_LENGTH;
+        break;
+        BYTECODE(ADVANCE_REGISTER)
+        registers[insn >> BYTECODE_SHIFT] += Load32Aligned(pc + 4);
+        pc += BC_ADVANCE_REGISTER_LENGTH;
+        break;
+        BYTECODE(SET_REGISTER_TO_CP)
+        registers[insn >> BYTECODE_SHIFT] = current + Load32Aligned(pc + 4);
+        pc += BC_SET_REGISTER_TO_CP_LENGTH;
+        break;
+        BYTECODE(SET_CP_TO_REGISTER)
+        current = registers[insn >> BYTECODE_SHIFT];
+        pc += BC_SET_CP_TO_REGISTER_LENGTH;
+        break;
+        BYTECODE(SET_REGISTER_TO_SP)
+        registers[insn >> BYTECODE_SHIFT] =
+            static_cast<int>(backtrack_sp - backtrack_stack_base);
+        pc += BC_SET_REGISTER_TO_SP_LENGTH;
+        break;
+        BYTECODE(SET_SP_TO_REGISTER)
+        backtrack_sp = backtrack_stack_base + registers[insn >> BYTECODE_SHIFT];
+        backtrack_stack_space =
+            backtrack_stack.max_size() -
+            static_cast<int>(backtrack_sp - backtrack_stack_base);
+        pc += BC_SET_SP_TO_REGISTER_LENGTH;
+        break;
+        BYTECODE(POP_CP)
         backtrack_stack_space++;
+        --backtrack_sp;
+        current = *backtrack_sp;
+        pc += BC_POP_CP_LENGTH;
+        break;
+        BYTECODE(POP_BT)
+        backtrack_stack_space++;
+        --backtrack_sp;
+        pc = code_base + *backtrack_sp;
+        // This should match check cadence in JIT irregexp implementation.
+        check_for_safepoint_now = true;
+        break;
+        BYTECODE(POP_REGISTER)
+        backtrack_stack_space++;
+        --backtrack_sp;
+        registers[insn >> BYTECODE_SHIFT] = *backtrack_sp;
+        pc += BC_POP_REGISTER_LENGTH;
+        break;
+        BYTECODE(FAIL)
+        return Bool::False().ptr();
+        BYTECODE(SUCCEED)
+        return Bool::True().ptr();
+        BYTECODE(ADVANCE_CP)
+        current += insn >> BYTECODE_SHIFT;
+        pc += BC_ADVANCE_CP_LENGTH;
+        break;
+        BYTECODE(GOTO)
         pc = code_base + Load32Aligned(pc + 4);
-      } else {
-        pc += BC_CHECK_GREEDY_LENGTH;
-      }
-      break;
-      BYTECODE(LOAD_CURRENT_CHAR) {
-        int pos = current + (insn >> BYTECODE_SHIFT);
-        if (pos < 0 || pos >= subject_length) {
+        break;
+        BYTECODE(ADVANCE_CP_AND_GOTO)
+        current += insn >> BYTECODE_SHIFT;
+        pc = code_base + Load32Aligned(pc + 4);
+        break;
+        BYTECODE(CHECK_GREEDY)
+        if (current == backtrack_sp[-1]) {
+          backtrack_sp--;
+          backtrack_stack_space++;
           pc = code_base + Load32Aligned(pc + 4);
         } else {
-          current_char = subject.CharAt(pos);
-          pc += BC_LOAD_CURRENT_CHAR_LENGTH;
+          pc += BC_CHECK_GREEDY_LENGTH;
         }
         break;
-      }
-      BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
-        int pos = current + (insn >> BYTECODE_SHIFT);
-        current_char = subject.CharAt(pos);
-        pc += BC_LOAD_CURRENT_CHAR_UNCHECKED_LENGTH;
-        break;
-      }
-      BYTECODE(LOAD_2_CURRENT_CHARS) {
-        int pos = current + (insn >> BYTECODE_SHIFT);
-        if (pos + 2 > subject_length) {
-          pc = code_base + Load32Aligned(pc + 4);
-        } else {
+        BYTECODE(LOAD_CURRENT_CHAR) {
+          int pos = current + (insn >> BYTECODE_SHIFT);
+          if (pos < 0 || pos >= subject_length) {
+            pc = code_base + Load32Aligned(pc + 4);
+          } else {
+            current_char = subject.CharAt(pos);
+            pc += BC_LOAD_CURRENT_CHAR_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(LOAD_CURRENT_CHAR_UNCHECKED) {
+          int pos = current + (insn >> BYTECODE_SHIFT);
+          current_char = subject.CharAt(pos);
+          pc += BC_LOAD_CURRENT_CHAR_UNCHECKED_LENGTH;
+          break;
+        }
+        BYTECODE(LOAD_2_CURRENT_CHARS) {
+          int pos = current + (insn >> BYTECODE_SHIFT);
+          if (pos + 2 > subject_length) {
+            pc = code_base + Load32Aligned(pc + 4);
+          } else {
+            Char next = subject.CharAt(pos + 1);
+            current_char =
+                subject.CharAt(pos) | (next << (kBitsPerByte * sizeof(Char)));
+            pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
+          int pos = current + (insn >> BYTECODE_SHIFT);
           Char next = subject.CharAt(pos + 1);
           current_char =
               subject.CharAt(pos) | (next << (kBitsPerByte * sizeof(Char)));
-          pc += BC_LOAD_2_CURRENT_CHARS_LENGTH;
+          pc += BC_LOAD_2_CURRENT_CHARS_UNCHECKED_LENGTH;
+          break;
         }
-        break;
-      }
-      BYTECODE(LOAD_2_CURRENT_CHARS_UNCHECKED) {
-        int pos = current + (insn >> BYTECODE_SHIFT);
-        Char next = subject.CharAt(pos + 1);
-        current_char =
-            subject.CharAt(pos) | (next << (kBitsPerByte * sizeof(Char)));
-        pc += BC_LOAD_2_CURRENT_CHARS_UNCHECKED_LENGTH;
-        break;
-      }
-      BYTECODE(LOAD_4_CURRENT_CHARS) {
-        ASSERT(sizeof(Char) == 1);
-        int pos = current + (insn >> BYTECODE_SHIFT);
-        if (pos + 4 > subject_length) {
-          pc = code_base + Load32Aligned(pc + 4);
-        } else {
+        BYTECODE(LOAD_4_CURRENT_CHARS) {
+          ASSERT(sizeof(Char) == 1);
+          int pos = current + (insn >> BYTECODE_SHIFT);
+          if (pos + 4 > subject_length) {
+            pc = code_base + Load32Aligned(pc + 4);
+          } else {
+            Char next1 = subject.CharAt(pos + 1);
+            Char next2 = subject.CharAt(pos + 2);
+            Char next3 = subject.CharAt(pos + 3);
+            current_char = (subject.CharAt(pos) | (next1 << 8) | (next2 << 16) |
+                            (next3 << 24));
+            pc += BC_LOAD_4_CURRENT_CHARS_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
+          ASSERT(sizeof(Char) == 1);
+          int pos = current + (insn >> BYTECODE_SHIFT);
           Char next1 = subject.CharAt(pos + 1);
           Char next2 = subject.CharAt(pos + 2);
           Char next3 = subject.CharAt(pos + 3);
           current_char = (subject.CharAt(pos) | (next1 << 8) | (next2 << 16) |
                           (next3 << 24));
-          pc += BC_LOAD_4_CURRENT_CHARS_LENGTH;
+          pc += BC_LOAD_4_CURRENT_CHARS_UNCHECKED_LENGTH;
+          break;
         }
-        break;
-      }
-      BYTECODE(LOAD_4_CURRENT_CHARS_UNCHECKED) {
-        ASSERT(sizeof(Char) == 1);
-        int pos = current + (insn >> BYTECODE_SHIFT);
-        Char next1 = subject.CharAt(pos + 1);
-        Char next2 = subject.CharAt(pos + 2);
-        Char next3 = subject.CharAt(pos + 3);
-        current_char = (subject.CharAt(pos) | (next1 << 8) | (next2 << 16) |
-                        (next3 << 24));
-        pc += BC_LOAD_4_CURRENT_CHARS_UNCHECKED_LENGTH;
-        break;
-      }
-      BYTECODE(CHECK_4_CHARS) {
-        uint32_t c = Load32Aligned(pc + 4);
-        if (c == current_char) {
+        BYTECODE(CHECK_4_CHARS) {
+          uint32_t c = Load32Aligned(pc + 4);
+          if (c == current_char) {
+            pc = code_base + Load32Aligned(pc + 8);
+          } else {
+            pc += BC_CHECK_4_CHARS_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(CHECK_CHAR) {
+          uint32_t c = (insn >> BYTECODE_SHIFT);
+          if (c == current_char) {
+            pc = code_base + Load32Aligned(pc + 4);
+          } else {
+            pc += BC_CHECK_CHAR_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(CHECK_NOT_4_CHARS) {
+          uint32_t c = Load32Aligned(pc + 4);
+          if (c != current_char) {
+            pc = code_base + Load32Aligned(pc + 8);
+          } else {
+            pc += BC_CHECK_NOT_4_CHARS_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(CHECK_NOT_CHAR) {
+          uint32_t c = (insn >> BYTECODE_SHIFT);
+          if (c != current_char) {
+            pc = code_base + Load32Aligned(pc + 4);
+          } else {
+            pc += BC_CHECK_NOT_CHAR_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(AND_CHECK_4_CHARS) {
+          uint32_t c = Load32Aligned(pc + 4);
+          if (c == (current_char & Load32Aligned(pc + 8))) {
+            pc = code_base + Load32Aligned(pc + 12);
+          } else {
+            pc += BC_AND_CHECK_4_CHARS_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(AND_CHECK_CHAR) {
+          uint32_t c = (insn >> BYTECODE_SHIFT);
+          if (c == (current_char & Load32Aligned(pc + 4))) {
+            pc = code_base + Load32Aligned(pc + 8);
+          } else {
+            pc += BC_AND_CHECK_CHAR_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(AND_CHECK_NOT_4_CHARS) {
+          uint32_t c = Load32Aligned(pc + 4);
+          if (c != (current_char & Load32Aligned(pc + 8))) {
+            pc = code_base + Load32Aligned(pc + 12);
+          } else {
+            pc += BC_AND_CHECK_NOT_4_CHARS_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(AND_CHECK_NOT_CHAR) {
+          uint32_t c = (insn >> BYTECODE_SHIFT);
+          if (c != (current_char & Load32Aligned(pc + 4))) {
+            pc = code_base + Load32Aligned(pc + 8);
+          } else {
+            pc += BC_AND_CHECK_NOT_CHAR_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
+          uint32_t c = (insn >> BYTECODE_SHIFT);
+          uint32_t minus = Load16Aligned(pc + 4);
+          uint32_t mask = Load16Aligned(pc + 6);
+          if (c != ((current_char - minus) & mask)) {
+            pc = code_base + Load32Aligned(pc + 8);
+          } else {
+            pc += BC_MINUS_AND_CHECK_NOT_CHAR_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(CHECK_CHAR_IN_RANGE) {
+          uint32_t from = Load16Aligned(pc + 4);
+          uint32_t to = Load16Aligned(pc + 6);
+          if (from <= current_char && current_char <= to) {
+            pc = code_base + Load32Aligned(pc + 8);
+          } else {
+            pc += BC_CHECK_CHAR_IN_RANGE_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(CHECK_CHAR_NOT_IN_RANGE) {
+          uint32_t from = Load16Aligned(pc + 4);
+          uint32_t to = Load16Aligned(pc + 6);
+          if (from > current_char || current_char > to) {
+            pc = code_base + Load32Aligned(pc + 8);
+          } else {
+            pc += BC_CHECK_CHAR_NOT_IN_RANGE_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(CHECK_BIT_IN_TABLE) {
+          int mask = RegExpMacroAssembler::kTableMask;
+          uint8_t b = pc[8 + ((current_char & mask) >> kBitsPerByteLog2)];
+          int bit = (current_char & (kBitsPerByte - 1));
+          if ((b & (1 << bit)) != 0) {
+            pc = code_base + Load32Aligned(pc + 4);
+          } else {
+            pc += BC_CHECK_BIT_IN_TABLE_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(CHECK_LT) {
+          uint32_t limit = (insn >> BYTECODE_SHIFT);
+          if (current_char < limit) {
+            pc = code_base + Load32Aligned(pc + 4);
+          } else {
+            pc += BC_CHECK_LT_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(CHECK_GT) {
+          uint32_t limit = (insn >> BYTECODE_SHIFT);
+          if (current_char > limit) {
+            pc = code_base + Load32Aligned(pc + 4);
+          } else {
+            pc += BC_CHECK_GT_LENGTH;
+          }
+          break;
+        }
+        BYTECODE(CHECK_REGISTER_LT)
+        if (registers[insn >> BYTECODE_SHIFT] < Load32Aligned(pc + 4)) {
           pc = code_base + Load32Aligned(pc + 8);
         } else {
-          pc += BC_CHECK_4_CHARS_LENGTH;
+          pc += BC_CHECK_REGISTER_LT_LENGTH;
         }
         break;
-      }
-      BYTECODE(CHECK_CHAR) {
-        uint32_t c = (insn >> BYTECODE_SHIFT);
-        if (c == current_char) {
+        BYTECODE(CHECK_REGISTER_GE)
+        if (registers[insn >> BYTECODE_SHIFT] >= Load32Aligned(pc + 4)) {
+          pc = code_base + Load32Aligned(pc + 8);
+        } else {
+          pc += BC_CHECK_REGISTER_GE_LENGTH;
+        }
+        break;
+        BYTECODE(CHECK_REGISTER_EQ_POS)
+        if (registers[insn >> BYTECODE_SHIFT] == current) {
           pc = code_base + Load32Aligned(pc + 4);
         } else {
-          pc += BC_CHECK_CHAR_LENGTH;
+          pc += BC_CHECK_REGISTER_EQ_POS_LENGTH;
         }
         break;
-      }
-      BYTECODE(CHECK_NOT_4_CHARS) {
-        uint32_t c = Load32Aligned(pc + 4);
-        if (c != current_char) {
+        BYTECODE(CHECK_NOT_REGS_EQUAL)
+        if (registers[insn >> BYTECODE_SHIFT] ==
+            registers[Load32Aligned(pc + 4)]) {
+          pc += BC_CHECK_NOT_REGS_EQUAL_LENGTH;
+        } else {
           pc = code_base + Load32Aligned(pc + 8);
-        } else {
-          pc += BC_CHECK_NOT_4_CHARS_LENGTH;
         }
         break;
-      }
-      BYTECODE(CHECK_NOT_CHAR) {
-        uint32_t c = (insn >> BYTECODE_SHIFT);
-        if (c != current_char) {
-          pc = code_base + Load32Aligned(pc + 4);
-        } else {
-          pc += BC_CHECK_NOT_CHAR_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(AND_CHECK_4_CHARS) {
-        uint32_t c = Load32Aligned(pc + 4);
-        if (c == (current_char & Load32Aligned(pc + 8))) {
-          pc = code_base + Load32Aligned(pc + 12);
-        } else {
-          pc += BC_AND_CHECK_4_CHARS_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(AND_CHECK_CHAR) {
-        uint32_t c = (insn >> BYTECODE_SHIFT);
-        if (c == (current_char & Load32Aligned(pc + 4))) {
-          pc = code_base + Load32Aligned(pc + 8);
-        } else {
-          pc += BC_AND_CHECK_CHAR_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(AND_CHECK_NOT_4_CHARS) {
-        uint32_t c = Load32Aligned(pc + 4);
-        if (c != (current_char & Load32Aligned(pc + 8))) {
-          pc = code_base + Load32Aligned(pc + 12);
-        } else {
-          pc += BC_AND_CHECK_NOT_4_CHARS_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(AND_CHECK_NOT_CHAR) {
-        uint32_t c = (insn >> BYTECODE_SHIFT);
-        if (c != (current_char & Load32Aligned(pc + 4))) {
-          pc = code_base + Load32Aligned(pc + 8);
-        } else {
-          pc += BC_AND_CHECK_NOT_CHAR_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(MINUS_AND_CHECK_NOT_CHAR) {
-        uint32_t c = (insn >> BYTECODE_SHIFT);
-        uint32_t minus = Load16Aligned(pc + 4);
-        uint32_t mask = Load16Aligned(pc + 6);
-        if (c != ((current_char - minus) & mask)) {
-          pc = code_base + Load32Aligned(pc + 8);
-        } else {
-          pc += BC_MINUS_AND_CHECK_NOT_CHAR_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(CHECK_CHAR_IN_RANGE) {
-        uint32_t from = Load16Aligned(pc + 4);
-        uint32_t to = Load16Aligned(pc + 6);
-        if (from <= current_char && current_char <= to) {
-          pc = code_base + Load32Aligned(pc + 8);
-        } else {
-          pc += BC_CHECK_CHAR_IN_RANGE_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(CHECK_CHAR_NOT_IN_RANGE) {
-        uint32_t from = Load16Aligned(pc + 4);
-        uint32_t to = Load16Aligned(pc + 6);
-        if (from > current_char || current_char > to) {
-          pc = code_base + Load32Aligned(pc + 8);
-        } else {
-          pc += BC_CHECK_CHAR_NOT_IN_RANGE_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(CHECK_BIT_IN_TABLE) {
-        int mask = RegExpMacroAssembler::kTableMask;
-        uint8_t b = pc[8 + ((current_char & mask) >> kBitsPerByteLog2)];
-        int bit = (current_char & (kBitsPerByte - 1));
-        if ((b & (1 << bit)) != 0) {
-          pc = code_base + Load32Aligned(pc + 4);
-        } else {
-          pc += BC_CHECK_BIT_IN_TABLE_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(CHECK_LT) {
-        uint32_t limit = (insn >> BYTECODE_SHIFT);
-        if (current_char < limit) {
-          pc = code_base + Load32Aligned(pc + 4);
-        } else {
-          pc += BC_CHECK_LT_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(CHECK_GT) {
-        uint32_t limit = (insn >> BYTECODE_SHIFT);
-        if (current_char > limit) {
-          pc = code_base + Load32Aligned(pc + 4);
-        } else {
-          pc += BC_CHECK_GT_LENGTH;
-        }
-        break;
-      }
-      BYTECODE(CHECK_REGISTER_LT)
-      if (registers[insn >> BYTECODE_SHIFT] < Load32Aligned(pc + 4)) {
-        pc = code_base + Load32Aligned(pc + 8);
-      } else {
-        pc += BC_CHECK_REGISTER_LT_LENGTH;
-      }
-      break;
-      BYTECODE(CHECK_REGISTER_GE)
-      if (registers[insn >> BYTECODE_SHIFT] >= Load32Aligned(pc + 4)) {
-        pc = code_base + Load32Aligned(pc + 8);
-      } else {
-        pc += BC_CHECK_REGISTER_GE_LENGTH;
-      }
-      break;
-      BYTECODE(CHECK_REGISTER_EQ_POS)
-      if (registers[insn >> BYTECODE_SHIFT] == current) {
-        pc = code_base + Load32Aligned(pc + 4);
-      } else {
-        pc += BC_CHECK_REGISTER_EQ_POS_LENGTH;
-      }
-      break;
-      BYTECODE(CHECK_NOT_REGS_EQUAL)
-      if (registers[insn >> BYTECODE_SHIFT] ==
-          registers[Load32Aligned(pc + 4)]) {
-        pc += BC_CHECK_NOT_REGS_EQUAL_LENGTH;
-      } else {
-        pc = code_base + Load32Aligned(pc + 8);
-      }
-      break;
-      BYTECODE(CHECK_NOT_BACK_REF) {
-        int from = registers[insn >> BYTECODE_SHIFT];
-        int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
-        if (from < 0 || len <= 0) {
+        BYTECODE(CHECK_NOT_BACK_REF) {
+          int from = registers[insn >> BYTECODE_SHIFT];
+          int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+          if (from < 0 || len <= 0) {
+            pc += BC_CHECK_NOT_BACK_REF_LENGTH;
+            break;
+          }
+          if (current + len > subject_length) {
+            pc = code_base + Load32Aligned(pc + 4);
+            break;
+          } else {
+            int i;
+            for (i = 0; i < len; i++) {
+              if (subject.CharAt(from + i) != subject.CharAt(current + i)) {
+                pc = code_base + Load32Aligned(pc + 4);
+                break;
+              }
+            }
+            if (i < len) break;
+            current += len;
+          }
           pc += BC_CHECK_NOT_BACK_REF_LENGTH;
           break;
         }
-        if (current + len > subject_length) {
-          pc = code_base + Load32Aligned(pc + 4);
-          break;
-        } else {
-          int i;
-          for (i = 0; i < len; i++) {
-            if (subject.CharAt(from + i) != subject.CharAt(current + i)) {
+        BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE)
+        FALL_THROUGH;
+        BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
+          const bool unicode =
+              (insn & BYTECODE_MASK) == BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE;
+          int from = registers[insn >> BYTECODE_SHIFT];
+          int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+          if (from < 0 || len <= 0) {
+            pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
+            break;
+          }
+          if (current + len > subject_length) {
+            pc = code_base + Load32Aligned(pc + 4);
+            break;
+          } else {
+            if (BackRefMatchesNoCase<Char>(&canonicalize, from, current, len,
+                                           subject, unicode)) {
+              current += len;
+              pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
+            } else {
               pc = code_base + Load32Aligned(pc + 4);
-              break;
             }
           }
-          if (i < len) break;
-          current += len;
-        }
-        pc += BC_CHECK_NOT_BACK_REF_LENGTH;
-        break;
-      }
-      BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE)
-      FALL_THROUGH;
-      BYTECODE(CHECK_NOT_BACK_REF_NO_CASE) {
-        const bool unicode =
-            (insn & BYTECODE_MASK) == BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE;
-        int from = registers[insn >> BYTECODE_SHIFT];
-        int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
-        if (from < 0 || len <= 0) {
-          pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
           break;
         }
-        if (current + len > subject_length) {
-          pc = code_base + Load32Aligned(pc + 4);
-          break;
-        } else {
-          if (BackRefMatchesNoCase<Char>(&canonicalize, from, current, len,
-                                         subject, unicode)) {
-            current += len;
-            pc += BC_CHECK_NOT_BACK_REF_NO_CASE_LENGTH;
-          } else {
-            pc = code_base + Load32Aligned(pc + 4);
+        BYTECODE(CHECK_NOT_BACK_REF_BACKWARD) {
+          const int from = registers[insn >> BYTECODE_SHIFT];
+          const int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+          if (from < 0 || len <= 0) {
+            pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
+            break;
           }
-        }
-        break;
-      }
-      BYTECODE(CHECK_NOT_BACK_REF_BACKWARD) {
-        const int from = registers[insn >> BYTECODE_SHIFT];
-        const int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
-        if (from < 0 || len <= 0) {
+          if ((current - len) < 0) {
+            pc = code_base + Load32Aligned(pc + 4);
+            break;
+          } else {
+            // When looking behind, the string to match (if it is there) lies
+            // before the current position, so we will check the [len]
+            // characters before the current position, excluding the current
+            // position itself.
+            const int start = current - len;
+            int i;
+            for (i = 0; i < len; i++) {
+              if (subject.CharAt(from + i) != subject.CharAt(start + i)) {
+                pc = code_base + Load32Aligned(pc + 4);
+                break;
+              }
+            }
+            if (i < len) break;
+            current -= len;
+          }
           pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
           break;
         }
-        if ((current - len) < 0) {
-          pc = code_base + Load32Aligned(pc + 4);
-          break;
-        } else {
-          // When looking behind, the string to match (if it is there) lies
-          // before the current position, so we will check the [len] characters
-          // before the current position, excluding the current position itself.
-          const int start = current - len;
-          int i;
-          for (i = 0; i < len; i++) {
-            if (subject.CharAt(from + i) != subject.CharAt(start + i)) {
+        BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD)
+        FALL_THROUGH;
+        BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD) {
+          bool unicode = (insn & BYTECODE_MASK) ==
+                         BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD;
+          int from = registers[insn >> BYTECODE_SHIFT];
+          int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
+          if (from < 0 || len <= 0) {
+            pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+            break;
+          }
+          if (current < len) {
+            pc = code_base + Load32Aligned(pc + 4);
+            break;
+          } else {
+            if (BackRefMatchesNoCase<Char>(&canonicalize, from, current - len,
+                                           len, subject, unicode)) {
+              current -= len;
+              pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+            } else {
               pc = code_base + Load32Aligned(pc + 4);
-              break;
             }
           }
-          if (i < len) break;
-          current -= len;
-        }
-        pc += BC_CHECK_NOT_BACK_REF_BACKWARD_LENGTH;
-        break;
-      }
-      BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD)
-      FALL_THROUGH;
-      BYTECODE(CHECK_NOT_BACK_REF_NO_CASE_BACKWARD) {
-        bool unicode = (insn & BYTECODE_MASK) ==
-                       BC_CHECK_NOT_BACK_REF_NO_CASE_UNICODE_BACKWARD;
-        int from = registers[insn >> BYTECODE_SHIFT];
-        int len = registers[(insn >> BYTECODE_SHIFT) + 1] - from;
-        if (from < 0 || len <= 0) {
-          pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
           break;
         }
-        if (current < len) {
+        BYTECODE(CHECK_AT_START)
+        if (current == 0) {
           pc = code_base + Load32Aligned(pc + 4);
-          break;
         } else {
-          if (BackRefMatchesNoCase<Char>(&canonicalize, from, current - len,
-                                         len, subject, unicode)) {
-            current -= len;
-            pc += BC_CHECK_NOT_BACK_REF_NO_CASE_BACKWARD_LENGTH;
+          pc += BC_CHECK_AT_START_LENGTH;
+        }
+        break;
+        BYTECODE(CHECK_NOT_AT_START) {
+          const int32_t cp_offset = insn >> BYTECODE_SHIFT;
+          if (current + cp_offset == 0) {
+            pc += BC_CHECK_NOT_AT_START_LENGTH;
           } else {
             pc = code_base + Load32Aligned(pc + 4);
           }
+          break;
         }
-        break;
-      }
-      BYTECODE(CHECK_AT_START)
-      if (current == 0) {
-        pc = code_base + Load32Aligned(pc + 4);
-      } else {
-        pc += BC_CHECK_AT_START_LENGTH;
-      }
-      break;
-      BYTECODE(CHECK_NOT_AT_START) {
-        const int32_t cp_offset = insn >> BYTECODE_SHIFT;
-        if (current + cp_offset == 0) {
-          pc += BC_CHECK_NOT_AT_START_LENGTH;
-        } else {
-          pc = code_base + Load32Aligned(pc + 4);
+        BYTECODE(SET_CURRENT_POSITION_FROM_END) {
+          int by = static_cast<uint32_t>(insn) >> BYTECODE_SHIFT;
+          if (subject_length - current > by) {
+            current = subject_length - by;
+            current_char = subject.CharAt(current - 1);
+          }
+          pc += BC_SET_CURRENT_POSITION_FROM_END_LENGTH;
+          break;
         }
-        break;
+        default:
+          UNREACHABLE();
+          break;
       }
-      BYTECODE(SET_CURRENT_POSITION_FROM_END) {
-        int by = static_cast<uint32_t>(insn) >> BYTECODE_SHIFT;
-        if (subject_length - current > by) {
-          current = subject_length - by;
-          current_char = subject.CharAt(current - 1);
-        }
-        pc += BC_SET_CURRENT_POSITION_FROM_END_LENGTH;
-        break;
-      }
-      default:
-        UNREACHABLE();
-        break;
     }
   }
 }
 
-IrregexpInterpreter::IrregexpResult IrregexpInterpreter::Match(
-    const TypedData& bytecode,
-    const String& subject,
-    int32_t* registers,
-    intptr_t start_position,
-    Zone* zone) {
-  NoSafepointScope no_safepoint;
-  const uint8_t* code_base = reinterpret_cast<uint8_t*>(bytecode.DataAddr(0));
-
+// Returns True if success, False if failure, Null if internal exception,
+// Error if VM error needs to be propagated up the callchain.
+ObjectPtr IrregexpInterpreter::Match(const TypedData& bytecode,
+                                     const String& subject,
+                                     int32_t* registers,
+                                     intptr_t start_position,
+                                     Zone* zone) {
   uint16_t previous_char = '\n';
   if (start_position != 0) {
     previous_char = subject.CharAt(start_position - 1);
   }
 
   if (subject.IsOneByteString() || subject.IsExternalOneByteString()) {
-    return RawMatch<uint8_t>(code_base, subject, registers, start_position,
+    return RawMatch<uint8_t>(bytecode, subject, registers, start_position,
                              previous_char, zone);
   } else if (subject.IsTwoByteString() || subject.IsExternalTwoByteString()) {
-    return RawMatch<uint16_t>(code_base, subject, registers, start_position,
+    return RawMatch<uint16_t>(bytecode, subject, registers, start_position,
                               previous_char, zone);
   } else {
     UNREACHABLE();
-    return IrregexpInterpreter::RE_FAILURE;
+    return Bool::False().ptr();
   }
 }
 
diff --git a/runtime/vm/regexp_interpreter.h b/runtime/vm/regexp_interpreter.h
index 9e4e567..f451a40 100644
--- a/runtime/vm/regexp_interpreter.h
+++ b/runtime/vm/regexp_interpreter.h
@@ -15,13 +15,14 @@
 
 class IrregexpInterpreter : public AllStatic {
  public:
-  enum IrregexpResult { RE_FAILURE = 0, RE_SUCCESS = 1, RE_EXCEPTION = -1 };
-
-  static IrregexpResult Match(const TypedData& bytecode,
-                              const String& subject,
-                              int32_t* captures,
-                              intptr_t start_position,
-                              Zone* zone);
+  // Returns True in case of a success, False in case of a failure,
+  // Null in case of internal exception,
+  // Error in case VM error has to propagated up to the caller.
+  static ObjectPtr Match(const TypedData& bytecode,
+                         const String& subject,
+                         int32_t* captures,
+                         intptr_t start_position,
+                         Zone* zone);
 };
 
 }  // namespace dart
diff --git a/third_party/devtools/README b/third_party/devtools/README
deleted file mode 100644
index d35a323..0000000
--- a/third_party/devtools/README
+++ /dev/null
@@ -1,14 +0,0 @@
-This folder contains a pre-built Dart DevTools instance which can be served
-as a web application, as well as the package:devtools_server and package:devtools_shared
-from the same revision, used to host and launch DevTools from a Dart process.
-
-First, ensure Flutter is installed and on your path (see https://flutter.dev/docs/get-started/install/linux#install-flutter-manually).
-
-With `flutter` on your path, do the following:
-
-- Run ./update.sh <revision> to build DevTools at a given revision and upload it
-  to CIPD. The uploaded CIPD entry will be tagged with `revision:<revision>`
-- Update DEPS to point to the newly updated DevTools by providing "revision:<revision>"
-  as the version entry for "third_party/devtools"
-
-DevTools CIPD packages are located at https://chrome-infra-packages.appspot.com/p/dart/third_party/flutter/devtools/+/.
diff --git a/third_party/devtools/README.md b/third_party/devtools/README.md
new file mode 100644
index 0000000..6011569
--- /dev/null
+++ b/third_party/devtools/README.md
@@ -0,0 +1,13 @@
+This folder contains a pre-built Dart DevTools instance which can be served
+as a web application, as well as the package:devtools_server and package:devtools_shared
+packages from the same revision, used to host and launch DevTools from a Dart process.
+
+To build DevTools and update the CIPD resources, do the following:
+
+- Run ./update.sh <revision> to build DevTools at a given revision and upload it
+  to CIPD. The uploaded CIPD entry will be tagged with `revision:<revision>`
+- Update DEPS to point to the newly updated DevTools by providing "revision:<revision>"
+  as the version entry for "third_party/devtools"
+
+DevTools CIPD packages are located at
+https://chrome-infra-packages.appspot.com/p/dart/third_party/flutter/devtools/+/.
diff --git a/third_party/devtools/update.sh b/third_party/devtools/update.sh
index 90533c5..92d6f2d 100755
--- a/third_party/devtools/update.sh
+++ b/third_party/devtools/update.sh
@@ -24,6 +24,7 @@
 cd devtools
 git checkout -b cipd_release $1
 
+./tool/update_flutter_sdk.sh
 ./tool/build_release.sh
 
 # Copy the build output as well as the devtools packages needed
@@ -31,6 +32,7 @@
 mkdir cipd_package
 cp -R packages/devtools/build/ cipd_package/web
 cp -r packages/devtools_shared cipd_package
+cp -r packages/devtools_server cipd_package
 
 cipd create \
   -name dart/third_party/flutter/devtools \
diff --git a/tools/VERSION b/tools/VERSION
index dfd5a96..66d255d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 38
+PRERELEASE 39
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/generate_package_config.dart b/tools/generate_package_config.dart
index 882c827..066eb2c 100644
--- a/tools/generate_package_config.dart
+++ b/tools/generate_package_config.dart
@@ -57,6 +57,7 @@
     packageDirectory(
         'runtime/observatory_2/tests/service_2/observatory_test_package_2'),
     packageDirectory('sdk/lib/_internal/sdk_library_metadata'),
+    packageDirectory('third_party/devtools/devtools_server'),
     packageDirectory('third_party/devtools/devtools_shared'),
     packageDirectory('third_party/pkg/protobuf/protobuf'),
     packageDirectory('third_party/pkg/webdev/frontend_server_client'),