Version 2.12.0-264.0.dev

Merge commit '64a8d2a8b8b85a6e3221ebbc80f36a7746045b4e' into 'dev'
diff --git a/DEPS b/DEPS
index 00cb7f7..5761840 100644
--- a/DEPS
+++ b/DEPS
@@ -111,7 +111,7 @@
   "http_multi_server_rev" : "e8c8be7f15b4fb50757ff5bf29766721fbe24fe4",
   "http_parser_rev": "5dd4d16693242049dfb43b5efa429fedbf932e98",
   "http_retry_tag": "0.1.1",
-  "http_rev": "3845753a54624b070828cb3eff7a6c2a4e046cfb",
+  "http_rev": "d5c678cd63c3e9c1d779a09acfa95b7e3af84665",
   "http_throttle_tag" : "1.0.2",
   "icu_rev" : "79326efe26e5440f530963704c3c0ff965b3a4ac",
   "idl_parser_rev": "5fb1ebf49d235b5a70c9f49047e83b0654031eb7",
diff --git a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
index 52da455..50f73a3 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
@@ -95,6 +95,7 @@
 
   Future<void> test_createChange_add() async {
     await indexTestUnit('''
+/// Documentation for [new A]
 class A {
   A() {} // marker
   factory A._() = A;
@@ -114,6 +115,7 @@
     // validate change
     refactoring.newName = 'newName';
     return assertSuccessfulRefactoring('''
+/// Documentation for [new A.newName]
 class A {
   A.newName() {} // marker
   factory A._() = A.newName;
@@ -129,6 +131,7 @@
 
   Future<void> test_createChange_add_toSynthetic() async {
     await indexTestUnit('''
+/// Documentation for [new A]
 class A {
 }
 class B extends A {
@@ -146,6 +149,7 @@
     // validate change
     refactoring.newName = 'newName';
     return assertSuccessfulRefactoring('''
+/// Documentation for [new A.newName]
 class A {
   A.newName();
 }
@@ -160,6 +164,7 @@
 
   Future<void> test_createChange_change() async {
     await indexTestUnit('''
+/// Documentation for [A.test] and [new A.test]
 class A {
   A.test() {} // marker
   factory A._() = A.test;
@@ -179,6 +184,7 @@
     // validate change
     refactoring.newName = 'newName';
     return assertSuccessfulRefactoring('''
+/// Documentation for [A.newName] and [new A.newName]
 class A {
   A.newName() {} // marker
   factory A._() = A.newName;
@@ -194,6 +200,7 @@
 
   Future<void> test_createChange_remove() async {
     await indexTestUnit('''
+/// Documentation for [A.test] and [new A.test]
 class A {
   A.test() {} // marker
   factory A._() = A.test;
@@ -213,6 +220,7 @@
     // validate change
     refactoring.newName = '';
     return assertSuccessfulRefactoring('''
+/// Documentation for [A] and [new A]
 class A {
   A() {} // marker
   factory A._() = A;
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index c664f80..1df5522 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -584,6 +584,28 @@
   }
 
   @override
+  visitCommentReference(CommentReference node) {
+    var identifier = node.identifier;
+    var element = identifier.staticElement;
+    if (element is ConstructorElement) {
+      if (identifier is PrefixedIdentifier) {
+        var offset = identifier.prefix.end;
+        var length = identifier.end - offset;
+        recordRelationOffset(
+            element, IndexRelationKind.IS_REFERENCED_BY, offset, length, true);
+        return;
+      } else {
+        var offset = identifier.end;
+        recordRelationOffset(
+            element, IndexRelationKind.IS_REFERENCED_BY, offset, 0, true);
+        return;
+      }
+    }
+
+    return super.visitCommentReference(node);
+  }
+
+  @override
   void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
     SimpleIdentifier fieldName = node.fieldName;
     if (fieldName != null) {
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index 21fcfc4..1f5499e 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -602,33 +602,39 @@
 
   test_isReferencedBy_ConstructorElement() async {
     await _indexTestUnit('''
+/// [new A.foo] 1
+/// [A.foo] 2
+/// [new A] 3
 class A implements B {
   A() {}
   A.foo() {}
 }
 class B extends A {
-  B() : super(); // 1
-  B.foo() : super.foo(); // 2
-  factory B.bar() = A.foo; // 3
+  B() : super(); // 4
+  B.foo() : super.foo(); // 5
+  factory B.bar() = A.foo; // 6
 }
 main() {
-  new A(); // 4
-  new A.foo(); // 5
+  new A(); // 7
+  new A.foo(); // 8
 }
 ''');
     var constA = findElement.unnamedConstructor('A');
     var constA_foo = findElement.constructor('foo', of: 'A');
     // A()
     assertThat(constA)
-      ..hasRelationCount(2)
-      ..isReferencedAt('(); // 1', true, length: 0)
-      ..isReferencedAt('(); // 4', true, length: 0);
+      ..hasRelationCount(3)
+      ..isReferencedAt('] 3', true, length: 0)
+      ..isReferencedAt('(); // 4', true, length: 0)
+      ..isReferencedAt('(); // 7', true, length: 0);
     // A.foo()
     assertThat(constA_foo)
-      ..hasRelationCount(3)
-      ..isReferencedAt('.foo(); // 2', true, length: 4)
-      ..isReferencedAt('.foo; // 3', true, length: 4)
-      ..isReferencedAt('.foo(); // 5', true, length: 4);
+      ..hasRelationCount(5)
+      ..isReferencedAt('.foo] 1', true, length: 4)
+      ..isReferencedAt('.foo] 2', true, length: 4)
+      ..isReferencedAt('.foo(); // 5', true, length: 4)
+      ..isReferencedAt('.foo; // 6', true, length: 4)
+      ..isReferencedAt('.foo(); // 8', true, length: 4);
   }
 
   test_isReferencedBy_ConstructorElement_classTypeAlias() async {
diff --git a/pkg/dart2native/bin/dart2native.dart b/pkg/dart2native/bin/dart2native.dart
index 7f407416..ed18daf 100644
--- a/pkg/dart2native/bin/dart2native.dart
+++ b/pkg/dart2native/bin/dart2native.dart
@@ -66,6 +66,8 @@
         defaultsTo: '', valueHelp: 'feature', hide: true, help: '''
 Comma separated list of experimental features.
 ''')
+    ..addFlag('sound-null-safety',
+        help: 'Respect the nullability of types at runtime.', defaultsTo: null)
     ..addFlag('verbose',
         abbr: 'v', negatable: false, help: 'Show verbose output.')
     ..addOption(
@@ -116,6 +118,7 @@
         defines: parsedArgs['define'],
         enableExperiment: parsedArgs['enable-experiment'],
         enableAsserts: parsedArgs['enable-asserts'],
+        soundNullSafety: parsedArgs['sound-null-safety'],
         verbose: parsedArgs['verbose'],
         verbosity: parsedArgs['verbosity'],
         extraOptions: parsedArgs['extra-gen-snapshot-options']);
diff --git a/pkg/dart2native/lib/generate.dart b/pkg/dart2native/lib/generate.dart
index 6bc3abd..3df6176 100644
--- a/pkg/dart2native/lib/generate.dart
+++ b/pkg/dart2native/lib/generate.dart
@@ -26,6 +26,7 @@
   List<String> defines,
   String enableExperiment = '',
   bool enableAsserts = false,
+  bool soundNullSafety,
   bool verbose = false,
   String verbosity = 'all',
   List<String> extraOptions = const [],
@@ -61,7 +62,9 @@
         enableExperiment: enableExperiment,
         extraGenKernelOptions: [
           '--invocation-modes=compile',
-          '--verbosity=$verbosity'
+          '--verbosity=$verbosity',
+          if (soundNullSafety != null)
+            '--${soundNullSafety ? '' : 'no-'}sound-null-safety',
         ]);
     if (kernelResult.exitCode != 0) {
       // We pipe both stdout and stderr to stderr because the CFE doesn't print
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 021db07..affa10d 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -258,6 +258,9 @@
               '''Get package locations from the specified file instead of .packages.
 <path> can be relative or absolute.
 For example: dart compile $commandName --packages=/tmp/pkgs main.dart''')
+      ..addFlag('sound-null-safety',
+          help: 'Respect the nullability of types at runtime.',
+          defaultsTo: null)
       ..addOption('save-debugging-info', abbr: 'S', valueHelp: 'path', help: '''
 Remove debugging information from the output and save it separately to the specified file.
 <path> can be relative or absolute.''');
@@ -294,6 +297,7 @@
         packages: argResults['packages'],
         enableAsserts: argResults['enable-asserts'],
         enableExperiment: argResults.enabledExperiments.join(','),
+        soundNullSafety: argResults['sound-null-safety'],
         debugFile: argResults['save-debugging-info'],
         verbose: verbose,
         verbosity: argResults['verbosity'],
diff --git a/pkg/dartdev/test/commands/compile_test.dart b/pkg/dartdev/test/commands/compile_test.dart
index 61ebc76..458fb39 100644
--- a/pkg/dartdev/test/commands/compile_test.dart
+++ b/pkg/dartdev/test/commands/compile_test.dart
@@ -310,6 +310,74 @@
         reason: 'File not found: $outFile');
   });
 
+  test('Compile and run exe with --sound-null-safety', () {
+    final p = project(mainSrc: '''void main() {
+      print((<int?>[] is List<int>) ? 'oh no' : 'sound');
+    }''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'exe',
+        '--sound-null-safety',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, contains(soundNullSafetyMessage));
+    expect(result.exitCode, 0);
+    expect(File(outFile).existsSync(), true,
+        reason: 'File not found: $outFile');
+
+    result = Process.runSync(
+      outFile,
+      [],
+    );
+
+    expect(result.stdout, contains('sound'));
+    expect(result.stderr, isEmpty);
+    expect(result.exitCode, 0);
+  });
+
+  test('Compile and run exe with --no-sound-null-safety', () {
+    final p = project(mainSrc: '''void main() {
+      print((<int?>[] is List<int>) ? 'unsound' : 'oh no');
+    }''');
+    final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
+    final outFile = path.canonicalize(path.join(p.dirPath, 'myexe'));
+
+    var result = p.runSync(
+      [
+        'compile',
+        'exe',
+        '--no-sound-null-safety',
+        '-o',
+        outFile,
+        inFile,
+      ],
+    );
+
+    expect(result.stderr, isEmpty);
+    expect(result.stdout, contains(unsoundNullSafetyMessage));
+    expect(result.exitCode, 0);
+    expect(File(outFile).existsSync(), true,
+        reason: 'File not found: $outFile');
+
+    result = Process.runSync(
+      outFile,
+      [],
+    );
+
+    expect(result.stdout, contains('unsound'));
+    expect(result.stderr, isEmpty);
+    expect(result.exitCode, 0);
+  });
+
   test('Compile exe without info', () {
     final p = project(mainSrc: '''void main() {}''');
     final inFile = path.canonicalize(path.join(p.dirPath, p.relativeFilePath));
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
index 25d68b1..c75bd34 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
@@ -65,12 +65,16 @@
 /// with legacy types.
 DartType demoteTypeInLibrary(DartType type, Library library) {
   if (library.isNonNullableByDefault) {
-    return type.accept(const _DemotionNullabilityNormalization(
-            demoteTypeVariables: true, forNonNullableByDefault: true)) ??
+    return type.accept1(
+            const _DemotionNullabilityNormalization(
+                demoteTypeVariables: true, forNonNullableByDefault: true),
+            Variance.covariant) ??
         type;
   } else {
-    return type.accept(const _DemotionNullabilityNormalization(
-            demoteTypeVariables: true, forNonNullableByDefault: false)) ??
+    return type.accept1(
+            const _DemotionNullabilityNormalization(
+                demoteTypeVariables: true, forNonNullableByDefault: false),
+            Variance.covariant) ??
         type;
   }
 }
@@ -85,8 +89,10 @@
   if (library.isNonNullableByDefault) {
     return type;
   } else {
-    return type.accept(const _DemotionNullabilityNormalization(
-            demoteTypeVariables: false, forNonNullableByDefault: false)) ??
+    return type.accept1(
+            const _DemotionNullabilityNormalization(
+                demoteTypeVariables: false, forNonNullableByDefault: false),
+            Variance.covariant) ??
         type;
   }
 }
@@ -119,7 +125,7 @@
   }
 
   @override
-  DartType visitTypeParameterType(TypeParameterType node) {
+  DartType visitTypeParameterType(TypeParameterType node, int variance) {
     Nullability newNullability = visitNullability(node);
     if (demoteTypeVariables && node.promotedBound != null) {
       return new TypeParameterType(
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
index f07e42a..d65acf4 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_elimination.dart
@@ -53,17 +53,11 @@
   final DartType topType;
   final DartType bottomType;
 
-  bool isLeastClosure;
-
-  _TypeSchemaEliminationVisitor(
-      this.isLeastClosure, this.topType, this.bottomType);
-
-  void changeVariance() {
-    isLeastClosure = !isLeastClosure;
-  }
+  _TypeSchemaEliminationVisitor(this.topType, this.bottomType);
 
   @override
-  DartType defaultDartType(DartType node) {
+  DartType defaultDartType(DartType node, int variance) {
+    bool isLeastClosure = variance == Variance.covariant;
     if (node is UnknownType) {
       return isLeastClosure ? bottomType : topType;
     }
@@ -84,9 +78,9 @@
     assert(bottomType == const NeverType(Nullability.nonNullable) ||
         bottomType is NullType);
     _TypeSchemaEliminationVisitor visitor =
-        new _TypeSchemaEliminationVisitor(isLeastClosure, topType, bottomType);
-    DartType result = schema.accept(visitor);
-    assert(visitor.isLeastClosure == isLeastClosure);
+        new _TypeSchemaEliminationVisitor(topType, bottomType);
+    DartType result = schema.accept1(
+        visitor, isLeastClosure ? Variance.covariant : Variance.contravariant);
     return result ?? schema;
   }
 }
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 9b60eea..f92c75c 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -878,6 +878,7 @@
 discover
 discovered
 discovery
+discrepancy
 disk
 dispatch
 dispatches
@@ -1604,6 +1605,7 @@
 inversion
 invert
 inverted
+inverter
 investigate
 invisible
 invocation
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index 3862cf5..dcbb5d9 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -4,6 +4,8 @@
 
 // @dart = 2.9
 
+import 'package:kernel/src/replacement_visitor.dart';
+
 import '../ast.dart'
     show
         BottomType,
@@ -501,195 +503,172 @@
 DartType convertSuperBoundedToRegularBounded(
     Library clientLibrary, TypeEnvironment typeEnvironment, DartType type,
     {int variance = Variance.covariant}) {
-  bool flipTop;
-  bool flipBottom;
-  DartType topType;
-  DartType bottomType;
-  bool isTop;
-  bool isBottom;
-  if (clientLibrary.isNonNullableByDefault) {
-    flipTop = variance != Variance.contravariant;
-    flipBottom = variance == Variance.contravariant;
-    topType = typeEnvironment.coreTypes.objectNullableRawType;
-    bottomType = const NeverType(Nullability.nonNullable);
-    isTop = typeEnvironment.coreTypes.isTop(type);
-    isBottom = typeEnvironment.coreTypes.isBottom(type);
-  } else {
-    flipTop = variance == Variance.covariant;
-    flipBottom = variance != Variance.covariant;
-    topType = const DynamicType();
-    bottomType = const NullType();
-    isTop = type is DynamicType ||
-        type is VoidType ||
-        type is InterfaceType &&
-            type.classNode == typeEnvironment.coreTypes.objectClass;
-    isBottom = type is NullType || type is BottomType;
+  return type.accept1(
+      new _SuperBoundedTypeInverter(typeEnvironment,
+          isNonNullableByDefault: clientLibrary.isNonNullableByDefault),
+      variance);
+}
+
+class _SuperBoundedTypeInverter extends ReplacementVisitor {
+  final TypeEnvironment typeEnvironment;
+  final bool isNonNullableByDefault;
+
+  _SuperBoundedTypeInverter(this.typeEnvironment, {this.isNonNullableByDefault})
+      : assert(typeEnvironment != null),
+        assert(isNonNullableByDefault != null);
+
+  bool flipTop(int variance) {
+    return isNonNullableByDefault
+        ? variance != Variance.contravariant
+        : variance == Variance.covariant;
   }
 
-  if (isTop && flipTop) {
-    return bottomType;
-  } else if (isBottom && flipBottom) {
-    return topType;
-  } else if (type is InterfaceType &&
-      type.classNode.typeParameters.isNotEmpty) {
-    assert(type.classNode.typeParameters.length == type.typeArguments.length);
+  bool flipBottom(int variance) {
+    return isNonNullableByDefault
+        ? variance == Variance.contravariant
+        : variance != Variance.covariant;
+  }
 
-    List<DartType> convertedTypeArguments = null;
-    for (int i = 0; i < type.typeArguments.length; ++i) {
-      DartType convertedTypeArgument = convertSuperBoundedToRegularBounded(
-          clientLibrary, typeEnvironment, type.typeArguments[i],
-          variance: variance);
-      if (convertedTypeArgument != null) {
-        convertedTypeArguments ??= new List<DartType>.of(type.typeArguments);
-        convertedTypeArguments[i] = convertedTypeArgument;
-      }
+  DartType get topType {
+    return isNonNullableByDefault
+        ? typeEnvironment.coreTypes.objectNullableRawType
+        : const DynamicType();
+  }
+
+  DartType get bottomType {
+    return isNonNullableByDefault
+        ? const NeverType(Nullability.nonNullable)
+        : const NullType();
+  }
+
+  bool isTop(DartType node) {
+    if (isNonNullableByDefault) {
+      return typeEnvironment.coreTypes.isTop(node);
+    } else {
+      return node is DynamicType ||
+          node is VoidType ||
+          node is InterfaceType &&
+              node.classNode == typeEnvironment.coreTypes.objectClass;
     }
-    if (convertedTypeArguments == null) return null;
-    return new InterfaceType(
-        type.classNode, type.nullability, convertedTypeArguments);
-  } else if (type is TypedefType &&
-      type.typedefNode.typeParameters.isNotEmpty) {
-    assert(type.typedefNode.typeParameters.length == type.typeArguments.length);
+  }
 
-    List<DartType> convertedTypeArguments = null;
-    for (int i = 0; i < type.typeArguments.length; i++) {
+  bool isBottom(DartType node) {
+    if (isNonNullableByDefault) {
+      return typeEnvironment.coreTypes.isBottom(node);
+    } else {
+      return node is NullType || node is BottomType;
+    }
+  }
+
+  @override
+  DartType visitDynamicType(DynamicType node, int variance) {
+    // dynamic is always a top type.
+    assert(isTop(node));
+    if (flipTop(variance)) {
+      return bottomType;
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  DartType visitVoidType(VoidType node, int variance) {
+    // void is always a top type.
+    assert(isTop(node));
+    if (flipTop(variance)) {
+      return bottomType;
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  DartType visitInterfaceType(InterfaceType node, int variance) {
+    // Check for Object-based top types.
+    if (isTop(node) && flipTop(variance)) {
+      return bottomType;
+    } else {
+      return super.visitInterfaceType(node, variance);
+    }
+  }
+
+  @override
+  DartType visitFutureOrType(FutureOrType node, int variance) {
+    // Check FutureOr-based top types.
+    if (isTop(node) && flipTop(variance)) {
+      return bottomType;
+    } else {
+      return super.visitFutureOrType(node, variance);
+    }
+  }
+
+  @override
+  DartType visitNullType(NullType node, int variance) {
+    // Null isn't a bottom type in NNBD.
+    if (isBottom(node) && flipBottom(variance)) {
+      return topType;
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  DartType visitNeverType(NeverType node, int variance) {
+    // Depending on the variance, Never may not be a bottom type.
+    if (isBottom(node) && flipBottom(variance)) {
+      return topType;
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  DartType visitTypeParameterType(TypeParameterType node, int variance) {
+    // Types such as X extends Never are bottom types.
+    if (isBottom(node) && flipBottom(variance)) {
+      return topType;
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  DartType visitBottomType(BottomType node, int variance) {
+    // Bottom is always a bottom type.
+    assert(isBottom(node));
+    if (flipBottom(variance)) {
+      return topType;
+    } else {
+      return null;
+    }
+  }
+
+  // TypedefTypes receive special treatment because the variance of their
+  // arguments' positions depend on the opt-in status of the library.
+  // TODO(dmitryas): Remove the method when the discrepancy between the NNBD
+  // modes is resolved.
+  @override
+  DartType visitTypedefType(TypedefType node, int variance) {
+    Nullability newNullability = visitNullability(node);
+    List<DartType> newTypeArguments = null;
+    for (int i = 0; i < node.typeArguments.length; i++) {
       // The implementation of instantiate-to-bound in legacy mode ignored the
       // variance of type parameters of the typedef.  This behavior is preserved
       // here in passing the 'variance' parameter unchanged in for legacy
       // libraries.
-      DartType convertedTypeArgument = convertSuperBoundedToRegularBounded(
-          clientLibrary, typeEnvironment, type.typeArguments[i],
-          variance: clientLibrary.isNonNullableByDefault
+      DartType newTypeArgument = node.typeArguments[i].accept1(
+          this,
+          isNonNullableByDefault
               ? Variance.combine(
-                  variance, type.typedefNode.typeParameters[i].variance)
+                  variance, node.typedefNode.typeParameters[i].variance)
               : variance);
-      if (convertedTypeArgument != null) {
-        convertedTypeArguments ??= new List<DartType>.of(type.typeArguments);
-        convertedTypeArguments[i] = convertedTypeArgument;
+      if (newTypeArgument != null) {
+        newTypeArguments ??= new List<DartType>.of(node.typeArguments);
+        newTypeArguments[i] = newTypeArgument;
       }
     }
-    if (convertedTypeArguments == null) return null;
-    return new TypedefType(
-        type.typedefNode, type.nullability, convertedTypeArguments);
-  } else if (type is FunctionType) {
-    if (clientLibrary.isNonNullableByDefault && type.typedefType != null) {
-      return convertSuperBoundedToRegularBounded(
-          clientLibrary, typeEnvironment, type.typedefType,
-          variance: variance);
-    }
-
-    DartType convertedReturnType = convertSuperBoundedToRegularBounded(
-        clientLibrary, typeEnvironment, type.returnType,
-        variance: variance);
-
-    List<DartType> convertedPositionalParameters = null;
-    for (int i = 0; i < type.positionalParameters.length; i++) {
-      DartType convertedPositionalParameter =
-          convertSuperBoundedToRegularBounded(
-              clientLibrary, typeEnvironment, type.positionalParameters[i],
-              variance: Variance.combine(variance, Variance.contravariant));
-      if (convertedPositionalParameter != null) {
-        convertedPositionalParameters ??=
-            new List<DartType>.of(type.positionalParameters);
-        convertedPositionalParameters[i] = convertedPositionalParameter;
-      }
-    }
-
-    List<NamedType> convertedNamedParameters = null;
-    for (int i = 0; i < type.namedParameters.length; i++) {
-      NamedType convertedNamedParameter = new NamedType(
-          type.namedParameters[i].name,
-          convertSuperBoundedToRegularBounded(
-              clientLibrary, typeEnvironment, type.namedParameters[i].type,
-              variance: Variance.combine(variance, Variance.contravariant)),
-          isRequired: type.namedParameters[i].isRequired);
-      if (convertedNamedParameter != null) {
-        convertedNamedParameters ??=
-            new List<NamedType>.of(type.namedParameters);
-        convertedNamedParameters[i] = convertedNamedParameter;
-      }
-    }
-
-    List<TypeParameter> convertedTypeParameters = null;
-    if (clientLibrary.isNonNullableByDefault &&
-        type.typeParameters.isNotEmpty) {
-      for (int i = 0; i < type.typeParameters.length; ++i) {
-        DartType convertedBound = convertSuperBoundedToRegularBounded(
-            clientLibrary, typeEnvironment, type.typeParameters[i].bound,
-            variance: Variance.combine(variance, Variance.invariant));
-        if (convertedBound != null) {
-          if (convertedTypeParameters == null) {
-            convertedTypeParameters = <TypeParameter>[];
-            for (TypeParameter parameter in type.typeParameters) {
-              convertedTypeParameters.add(new TypeParameter(parameter.name));
-            }
-          }
-          convertedTypeParameters[i].bound = convertedBound;
-        }
-      }
-
-      Map<TypeParameter, DartType> substitutionMap =
-          <TypeParameter, DartType>{};
-      for (int i = 0; i < type.typeParameters.length; ++i) {
-        substitutionMap[type.typeParameters[i]] =
-            new TypeParameterType.forAlphaRenaming(
-                type.typeParameters[i], convertedTypeParameters[i]);
-      }
-      for (TypeParameter parameter in convertedTypeParameters) {
-        parameter.bound = substitute(parameter.bound, substitutionMap);
-      }
-      List<DartType> defaultTypes = calculateBounds(convertedTypeParameters,
-          typeEnvironment.coreTypes.objectClass, clientLibrary);
-      for (int i = 0; i < convertedTypeParameters.length; ++i) {
-        convertedTypeParameters[i].defaultType = defaultTypes[i];
-      }
-
-      if (convertedReturnType != null) {
-        convertedReturnType = substitute(convertedReturnType, substitutionMap);
-      }
-      if (convertedPositionalParameters != null) {
-        for (int i = 0; i < convertedPositionalParameters.length; ++i) {
-          convertedPositionalParameters[i] =
-              substitute(convertedPositionalParameters[i], substitutionMap);
-        }
-      }
-      if (convertedNamedParameters != null) {
-        for (int i = 0; i < convertedNamedParameters.length; ++i) {
-          convertedNamedParameters[i] = new NamedType(
-              convertedNamedParameters[i].name,
-              substitute(convertedNamedParameters[i].type, substitutionMap),
-              isRequired: convertedNamedParameters[i].isRequired);
-        }
-      }
-    }
-
-    if (convertedReturnType == null &&
-        convertedPositionalParameters == null &&
-        convertedNamedParameters == null &&
-        convertedTypeParameters == null) {
-      return null;
-    }
-
-    convertedReturnType ??= type.returnType;
-    convertedPositionalParameters ??= type.positionalParameters;
-    convertedNamedParameters ??= type.namedParameters;
-    convertedTypeParameters ??= type.typeParameters;
-
-    return new FunctionType(
-        convertedPositionalParameters, convertedReturnType, type.nullability,
-        namedParameters: convertedNamedParameters,
-        typeParameters: type.typeParameters,
-        requiredParameterCount: type.requiredParameterCount,
-        typedefType: type.typedefType);
-  } else if (type is FutureOrType) {
-    DartType convertedTypeArgument = convertSuperBoundedToRegularBounded(
-        clientLibrary, typeEnvironment, type.typeArgument,
-        variance: variance);
-    if (convertedTypeArgument == null) return null;
-    return new FutureOrType(convertedTypeArgument, type.declaredNullability);
+    return createTypedef(node, newNullability, newTypeArguments);
   }
-
-  return null;
 }
 
 int computeVariance(TypeParameter typeParameter, DartType type,
diff --git a/pkg/kernel/lib/src/legacy_erasure.dart b/pkg/kernel/lib/src/legacy_erasure.dart
index 3a386bd..7a36398 100644
--- a/pkg/kernel/lib/src/legacy_erasure.dart
+++ b/pkg/kernel/lib/src/legacy_erasure.dart
@@ -21,7 +21,7 @@
 ///
 /// Returns `null` if the type wasn't changed.
 DartType rawLegacyErasure(DartType type) {
-  return type.accept(const _LegacyErasure());
+  return type.accept1(const _LegacyErasure(), Variance.covariant);
 }
 
 /// Returns legacy erasure of [supertype], that is, the type in which all nnbd
@@ -34,7 +34,8 @@
   List<DartType> newTypeArguments;
   for (int i = 0; i < supertype.typeArguments.length; i++) {
     DartType typeArgument = supertype.typeArguments[i];
-    DartType newTypeArgument = typeArgument.accept(const _LegacyErasure());
+    DartType newTypeArgument =
+        typeArgument.accept1(const _LegacyErasure(), Variance.covariant);
     if (newTypeArgument != null) {
       newTypeArguments ??= supertype.typeArguments.toList(growable: false);
       newTypeArguments[i] = newTypeArgument;
@@ -69,7 +70,7 @@
   }
 
   @override
-  DartType visitNeverType(NeverType node) => const NullType();
+  DartType visitNeverType(NeverType node, int variance) => const NullType();
 }
 
 /// Returns `true` if a member declared in [declaringClass] inherited or
diff --git a/pkg/kernel/lib/src/norm.dart b/pkg/kernel/lib/src/norm.dart
index 1b92f42..aa49ef7 100644
--- a/pkg/kernel/lib/src/norm.dart
+++ b/pkg/kernel/lib/src/norm.dart
@@ -12,7 +12,7 @@
 
 /// Returns normalization of [type].
 DartType norm(CoreTypes coreTypes, DartType type) {
-  return type.accept(new _Norm(coreTypes)) ?? type;
+  return type.accept1(new _Norm(coreTypes), Variance.covariant) ?? type;
 }
 
 /// Returns normalization of [supertype].
@@ -21,7 +21,8 @@
   _Norm normVisitor = new _Norm(coreTypes);
   List<DartType> typeArguments = null;
   for (int i = 0; i < supertype.typeArguments.length; ++i) {
-    DartType typeArgument = supertype.typeArguments[i].accept(normVisitor);
+    DartType typeArgument =
+        supertype.typeArguments[i].accept1(normVisitor, Variance.covariant);
     if (typeArgument != null) {
       typeArguments ??= supertype.typeArguments.toList();
       typeArguments[i] = typeArgument;
@@ -42,16 +43,16 @@
   _Norm(this.coreTypes);
 
   @override
-  DartType visitInterfaceType(InterfaceType node) {
+  DartType visitInterfaceType(InterfaceType node, int variance) {
     return super
-        .visitInterfaceType(node)
+        .visitInterfaceType(node, variance)
         ?.withDeclaredNullability(node.nullability);
   }
 
   @override
-  DartType visitFutureOrType(FutureOrType node) {
+  DartType visitFutureOrType(FutureOrType node, int variance) {
     DartType typeArgument = node.typeArgument;
-    typeArgument = typeArgument.accept(this) ?? typeArgument;
+    typeArgument = typeArgument.accept1(this, variance) ?? typeArgument;
     if (coreTypes.isTop(typeArgument)) {
       assert(typeArgument.nullability == Nullability.nullable ||
           typeArgument.nullability == Nullability.legacy);
@@ -90,20 +91,20 @@
   }
 
   @override
-  DartType visitTypeParameterType(TypeParameterType node) {
+  DartType visitTypeParameterType(TypeParameterType node, int variance) {
     if (node.promotedBound == null) {
       DartType bound = node.parameter.bound;
       if (normalizesToNever(bound)) {
         DartType result = new NeverType(Nullability.nonNullable)
             .withDeclaredNullability(node.nullability);
-        return result.accept(this) ?? result;
+        return result.accept1(this, variance) ?? result;
       }
       assert(!coreTypes.isBottom(bound));
       // If the bound isn't Never, the type is already normalized.
       return null;
     } else {
       DartType bound = node.promotedBound;
-      bound = bound.accept(this) ?? bound;
+      bound = bound.accept1(this, variance) ?? bound;
       if (bound is NeverType && bound.nullability == Nullability.nonNullable) {
         return bound;
       } else if (coreTypes.isTop(bound)) {
@@ -133,7 +134,7 @@
   }
 
   @override
-  DartType visitNeverType(NeverType node) {
+  DartType visitNeverType(NeverType node, int variance) {
     if (node.nullability == Nullability.nullable) return const NullType();
     return null;
   }
diff --git a/pkg/kernel/lib/src/replacement_visitor.dart b/pkg/kernel/lib/src/replacement_visitor.dart
index e260919..b7cbd3b 100644
--- a/pkg/kernel/lib/src/replacement_visitor.dart
+++ b/pkg/kernel/lib/src/replacement_visitor.dart
@@ -9,15 +9,13 @@
 
 /// Helper visitor that clones a type if a nested type is replaced, and
 /// otherwise returns `null`.
-class ReplacementVisitor implements DartTypeVisitor<DartType> {
+class ReplacementVisitor implements DartTypeVisitor1<DartType, int> {
   const ReplacementVisitor();
 
-  void changeVariance() {}
-
   Nullability visitNullability(DartType node) => null;
 
   @override
-  DartType visitFunctionType(FunctionType node) {
+  DartType visitFunctionType(FunctionType node, int variance) {
     Nullability newNullability = visitNullability(node);
 
     List<TypeParameter> newTypeParameters;
@@ -27,8 +25,10 @@
       // cyclic typedefs. Currently
       //   instantiate_to_bound/non_simple_class_parametrized_typedef_cycle
       // fails with this.
-      DartType newBound = typeParameter.bound?.accept(this);
-      DartType newDefaultType = typeParameter.defaultType?.accept(this);
+      DartType newBound = typeParameter.bound
+          ?.accept1(this, Variance.combine(variance, Variance.invariant));
+      DartType newDefaultType = typeParameter.defaultType
+          ?.accept1(this, Variance.combine(variance, Variance.invariant));
       if (newBound != null || newDefaultType != null) {
         newTypeParameters ??= node.typeParameters.toList(growable: false);
         newTypeParameters[i] = new TypeParameter(
@@ -54,20 +54,20 @@
       }
     }
 
-    DartType visitType(DartType type) {
+    DartType visitType(DartType type, int variance) {
       if (type == null) return null;
-      DartType result = type.accept(this);
+      DartType result = type.accept1(this, variance);
       if (substitution != null) {
         result = substitution.substituteType(result ?? type);
       }
       return result;
     }
 
-    DartType newReturnType = visitType(node.returnType);
-    changeVariance();
+    DartType newReturnType = visitType(node.returnType, variance);
     List<DartType> newPositionalParameters = null;
     for (int i = 0; i < node.positionalParameters.length; i++) {
-      DartType newType = visitType(node.positionalParameters[i]);
+      DartType newType = visitType(node.positionalParameters[i],
+          Variance.combine(variance, Variance.contravariant));
       if (newType != null) {
         newPositionalParameters ??=
             node.positionalParameters.toList(growable: false);
@@ -76,7 +76,8 @@
     }
     List<NamedType> newNamedParameters = null;
     for (int i = 0; i < node.namedParameters.length; i++) {
-      DartType newType = visitType(node.namedParameters[i].type);
+      DartType newType = visitType(node.namedParameters[i].type,
+          Variance.combine(variance, Variance.contravariant));
       NamedType newNamedType =
           createNamedType(node.namedParameters[i], newType);
       if (newNamedType != null) {
@@ -84,8 +85,7 @@
         newNamedParameters[i] = newNamedType;
       }
     }
-    changeVariance();
-    DartType newTypedefType = visitType(node.typedefType);
+    DartType newTypedefType = visitType(node.typedefType, variance);
 
     return createFunctionType(
         node,
@@ -133,11 +133,11 @@
   }
 
   @override
-  DartType visitInterfaceType(InterfaceType node) {
+  DartType visitInterfaceType(InterfaceType node, int variance) {
     Nullability newNullability = visitNullability(node);
     List<DartType> newTypeArguments = null;
     for (int i = 0; i < node.typeArguments.length; i++) {
-      DartType substitution = node.typeArguments[i].accept(this);
+      DartType substitution = node.typeArguments[i].accept1(this, variance);
       if (substitution != null) {
         newTypeArguments ??= node.typeArguments.toList(growable: false);
         newTypeArguments[i] = substitution;
@@ -160,9 +160,9 @@
   }
 
   @override
-  DartType visitFutureOrType(FutureOrType node) {
+  DartType visitFutureOrType(FutureOrType node, int variance) {
     Nullability newNullability = visitNullability(node);
-    DartType newTypeArgument = node.typeArgument.accept(this);
+    DartType newTypeArgument = node.typeArgument.accept1(this, variance);
     return createFutureOrType(node, newNullability, newTypeArgument);
   }
 
@@ -178,10 +178,10 @@
   }
 
   @override
-  DartType visitDynamicType(DynamicType node) => null;
+  DartType visitDynamicType(DynamicType node, int variance) => null;
 
   @override
-  DartType visitNeverType(NeverType node) {
+  DartType visitNeverType(NeverType node, int variance) {
     Nullability newNullability = visitNullability(node);
     return createNeverType(node, newNullability);
   }
@@ -196,22 +196,22 @@
   }
 
   @override
-  DartType visitNullType(NullType node) => null;
+  DartType visitNullType(NullType node, int variance) => null;
 
   @override
-  DartType visitInvalidType(InvalidType node) => null;
+  DartType visitInvalidType(InvalidType node, int variance) => null;
 
   @override
-  DartType visitBottomType(BottomType node) => null;
+  DartType visitBottomType(BottomType node, int variance) => null;
 
   @override
-  DartType visitVoidType(VoidType node) => null;
+  DartType visitVoidType(VoidType node, int variance) => null;
 
   @override
-  DartType visitTypeParameterType(TypeParameterType node) {
+  DartType visitTypeParameterType(TypeParameterType node, int variance) {
     Nullability newNullability = visitNullability(node);
     if (node.promotedBound != null) {
-      DartType newPromotedBound = node.promotedBound.accept(this);
+      DartType newPromotedBound = node.promotedBound.accept1(this, variance);
       return createPromotedTypeParameterType(
           node, newNullability, newPromotedBound);
     }
@@ -242,11 +242,14 @@
   }
 
   @override
-  DartType visitTypedefType(TypedefType node) {
+  DartType visitTypedefType(TypedefType node, int variance) {
     Nullability newNullability = visitNullability(node);
     List<DartType> newTypeArguments = null;
     for (int i = 0; i < node.typeArguments.length; i++) {
-      DartType substitution = node.typeArguments[i].accept(this);
+      DartType substitution = node.typeArguments[i].accept1(
+          this,
+          Variance.combine(
+              variance, node.typedefNode.typeParameters[i].variance));
       if (substitution != null) {
         newTypeArguments ??= node.typeArguments.toList(growable: false);
         newTypeArguments[i] = substitution;
@@ -269,5 +272,5 @@
   }
 
   @override
-  DartType defaultDartType(DartType node) => null;
+  DartType defaultDartType(DartType node, int variance) => null;
 }
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 03707fb..96d0aef 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -1001,7 +1001,6 @@
   final DartType topFunctionType;
   final Set<TypeParameter> eliminationTargets;
   bool isLeastClosure;
-  bool isCovariant = true;
   bool Function(DartType type, bool Function(DartType type) recursor)
       unhandledTypeHandler; // Can be null.
 
@@ -1018,37 +1017,32 @@
 
   /// Returns a subtype of [type] for all values of [eliminationTargets].
   DartType eliminateToLeast(DartType type) {
-    isCovariant = true;
     isLeastClosure = true;
-    return type.accept(this) ?? type;
+    return type.accept1(this, Variance.covariant) ?? type;
   }
 
   /// Returns a supertype of [type] for all values of [eliminationTargets].
   DartType eliminateToGreatest(DartType type) {
-    isCovariant = true;
     isLeastClosure = false;
-    return type.accept(this) ?? type;
+    return type.accept1(this, Variance.covariant) ?? type;
   }
 
-  DartType get typeParameterReplacement {
+  DartType getTypeParameterReplacement(int variance) {
+    bool isCovariant = variance == Variance.covariant;
     return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
         ? bottomType
         : topType;
   }
 
-  DartType get functionReplacement {
+  DartType getFunctionReplacement(int variance) {
+    bool isCovariant = variance == Variance.covariant;
     return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
         ? bottomType
         : topFunctionType;
   }
 
   @override
-  void changeVariance() {
-    isCovariant = !isCovariant;
-  }
-
-  @override
-  DartType visitFunctionType(FunctionType node) {
+  DartType visitFunctionType(FunctionType node, int variance) {
     // - if `S` is
     //   `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
     //       [Tn+1 xn+1, ..., Tm xm])`
@@ -1061,19 +1055,19 @@
       for (TypeParameter typeParameter in node.typeParameters) {
         if (containsTypeVariable(typeParameter.bound, eliminationTargets,
             unhandledTypeHandler: unhandledTypeHandler)) {
-          return functionReplacement;
+          return getFunctionReplacement(variance);
         }
       }
     }
-    return super.visitFunctionType(node);
+    return super.visitFunctionType(node, variance);
   }
 
   @override
-  DartType visitTypeParameterType(TypeParameterType node) {
+  DartType visitTypeParameterType(TypeParameterType node, int variance) {
     if (eliminationTargets.contains(node.parameter)) {
-      return typeParameterReplacement;
+      return getTypeParameterReplacement(variance);
     }
-    return super.visitTypeParameterType(node);
+    return super.visitTypeParameterType(node, variance);
   }
 }
 
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 103983e..a90d4de 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -266,8 +266,8 @@
   return unit.IssueLoad();
 }
 
-DEFINE_NATIVE_ENTRY(Internal_inquireIs64Bit, 0, 0) {
-#if defined(ARCH_IS_64_BIT)
+DEFINE_NATIVE_ENTRY(Internal_has63BitSmis, 0, 0) {
+#if defined(ARCH_IS_64_BIT) && !defined(DART_COMPRESSED_POINTERS)
   return Bool::True().ptr();
 #else
   return Bool::False().ptr();
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 6750bf9..000452a 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -337,7 +337,7 @@
   V(Internal_collectAllGarbage, 0)                                             \
   V(Internal_makeListFixedLength, 1)                                           \
   V(Internal_makeFixedListUnmodifiable, 1)                                     \
-  V(Internal_inquireIs64Bit, 0)                                                \
+  V(Internal_has63BitSmis, 0)                                                  \
   V(Internal_extractTypeArguments, 2)                                          \
   V(Internal_prependTypeArguments, 4)                                          \
   V(Internal_boundsCheckForPartialInstantiation, 2)                            \
diff --git a/runtime/vm/compiler/asm_intrinsifier_arm64.cc b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
index 80d2290..8b3fbd2 100644
--- a/runtime/vm/compiler/asm_intrinsifier_arm64.cc
+++ b/runtime/vm/compiler/asm_intrinsifier_arm64.cc
@@ -1356,7 +1356,7 @@
   __ fcmpd(V0, V0);
   __ b(normal_ir_body, VS);
 
-  __ fcvtzds(R0, V0);
+  __ fcvtzdsx(R0, V0);
   // Overflow is signaled with minint.
   // Check for overflow and that it fits into Smi.
   __ CompareImmediate(R0, 0xC000000000000000);
@@ -1380,7 +1380,7 @@
 
   // Convert double value to signed 64-bit int in R0 and back to a
   // double value in V1.
-  __ fcvtzds(R0, V0);
+  __ fcvtzdsx(R0, V0);
   __ scvtfdx(V1, R0);
 
   // Tag the int as a Smi, making sure that it fits; this checks for
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 86a8b3d..dec46f3 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1213,12 +1213,18 @@
     const Register crn = ConcreteRegister(rn);
     EmitFPIntCvtOp(SCVTFD, static_cast<Register>(vd), crn, kFourBytes);
   }
-  void fcvtzds(Register rd, VRegister vn) {
+  void fcvtzdsx(Register rd, VRegister vn) {
     ASSERT(rd != R31);
     ASSERT(rd != CSP);
     const Register crd = ConcreteRegister(rd);
     EmitFPIntCvtOp(FCVTZDS, crd, static_cast<Register>(vn));
   }
+  void fcvtzdsw(Register rd, VRegister vn) {
+    ASSERT(rd != R31);
+    ASSERT(rd != CSP);
+    const Register crd = ConcreteRegister(rd);
+    EmitFPIntCvtOp(FCVTZDS, crd, static_cast<Register>(vn), kFourBytes);
+  }
   void fmovdd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FMOVDD, vd, vn); }
   void fabsd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FABSD, vd, vn); }
   void fnegd(VRegister vd, VRegister vn) { EmitFPOneSourceOp(FNEGD, vd, vn); }
diff --git a/runtime/vm/compiler/assembler/assembler_arm64_test.cc b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
index c6d8847..29ed087 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
@@ -3089,17 +3089,73 @@
   EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(DoubleReturn, test->entry()));
 }
 
-ASSEMBLER_TEST_GENERATE(Fcvtzds, assembler) {
+ASSEMBLER_TEST_GENERATE(Fcvtzdsx, assembler) {
   __ LoadDImmediate(V0, 42.0);
-  __ fcvtzds(R0, V0);
+  __ fcvtzdsx(R0, V0);
   __ ret();
 }
 
-ASSEMBLER_TEST_RUN(Fcvtzds, test) {
+ASSEMBLER_TEST_RUN(Fcvtzdsx, test) {
   typedef int64_t (*Int64Return)() DART_UNUSED;
   EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
 }
 
+ASSEMBLER_TEST_GENERATE(Fcvtzdsw, assembler) {
+  __ LoadDImmediate(V0, 42.0);
+  __ fcvtzdsw(R0, V0);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsw, test) {
+  typedef int64_t (*Int64Return)() DART_UNUSED;
+  EXPECT_EQ(42, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsx_overflow, assembler) {
+  __ LoadDImmediate(V0, 1e20);
+  __ fcvtzdsx(R0, V0);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsx_overflow, test) {
+  typedef int64_t (*Int64Return)() DART_UNUSED;
+  EXPECT_EQ(kMaxInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsx_overflow_negative, assembler) {
+  __ LoadDImmediate(V0, -1e20);
+  __ fcvtzdsx(R0, V0);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsx_overflow_negative, test) {
+  typedef int64_t (*Int64Return)() DART_UNUSED;
+  EXPECT_EQ(kMinInt64, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsw_overflow, assembler) {
+  __ LoadDImmediate(V0, 1e10);
+  __ fcvtzdsw(R0, V0);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsw_overflow, test) {
+  typedef int64_t (*Int64Return)() DART_UNUSED;
+  EXPECT_EQ(kMaxInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
+ASSEMBLER_TEST_GENERATE(Fcvtzdsw_overflow_negative, assembler) {
+  __ LoadDImmediate(V0, -1e10);
+  __ fcvtzdsw(R0, V0);
+  __ sxtw(R0, R0);
+  __ ret();
+}
+
+ASSEMBLER_TEST_RUN(Fcvtzdsw_overflow_negative, test) {
+  typedef int64_t (*Int64Return)() DART_UNUSED;
+  EXPECT_EQ(kMinInt32, EXECUTE_TEST_CODE_INT64(Int64Return, test->entry()));
+}
+
 ASSEMBLER_TEST_GENERATE(Scvtfdx, assembler) {
   __ LoadImmediate(R0, 42);
   __ scvtfdx(V0, R0);
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 26ea233..0d89c3f 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -5140,7 +5140,7 @@
   __ fcmpd(VTMP, VTMP);
   __ b(&do_call, VS);
 
-  __ fcvtzds(result, VTMP);
+  __ fcvtzdsx(result, VTMP);
   // Overflow is signaled with minint.
 
   // Check for overflow and that it fits into Smi.
@@ -5188,7 +5188,7 @@
   __ fcmpd(value, value);
   __ b(deopt, VS);
 
-  __ fcvtzds(result, value);
+  __ fcvtzdsx(result, value);
   // Check for overflow and that it fits into Smi.
   __ CompareImmediate(result, 0xC000000000000000);
   __ b(deopt, MI);
diff --git a/runtime/vm/instructions_arm64.cc b/runtime/vm/instructions_arm64.cc
index 210fca3..e7a0d24 100644
--- a/runtime/vm/instructions_arm64.cc
+++ b/runtime/vm/instructions_arm64.cc
@@ -20,8 +20,8 @@
     : object_pool_(ObjectPool::Handle(code.GetObjectPool())),
       target_code_pool_index_(-1) {
   ASSERT(code.ContainsInstructionAt(pc));
-  // Last instruction: blr ip0.
-  ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f0200);
+  // Last instruction: blr lr.
+  ASSERT(*(reinterpret_cast<uint32_t*>(pc) - 1) == 0xd63f03c0);
 
   Register reg;
   InstructionPattern::DecodeLoadWordFromPool(pc - 2 * Instr::kInstrSize, &reg,
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index 1c78f20..e5eb2d0 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -3360,13 +3360,21 @@
       set_vregisterd(vd, 1, 0);
     } else if (instr->Bits(16, 5) == 24) {
       // Format(instr, "fcvtzds'sf 'rd, 'vn");
+      const intptr_t max = instr->Bit(31) == 1 ? INT64_MAX : INT32_MAX;
+      const intptr_t min = instr->Bit(31) == 1 ? INT64_MIN : INT32_MIN;
       const double vn_val = bit_cast<double, int64_t>(get_vregisterd(vn, 0));
-      if (vn_val >= static_cast<double>(INT64_MAX)) {
-        set_register(instr, rd, INT64_MAX, instr->RdMode());
-      } else if (vn_val <= static_cast<double>(INT64_MIN)) {
-        set_register(instr, rd, INT64_MIN, instr->RdMode());
+      int64_t result;
+      if (vn_val >= static_cast<double>(max)) {
+        result = max;
+      } else if (vn_val <= static_cast<double>(min)) {
+        result = min;
       } else {
-        set_register(instr, rd, static_cast<int64_t>(vn_val), instr->RdMode());
+        result = static_cast<int64_t>(vn_val);
+      }
+      if (instr->Bit(31) == 1) {
+        set_register(instr, rd, result, instr->RdMode());
+      } else {
+        set_register(instr, rd, result & 0xffffffffll, instr->RdMode());
       }
     } else {
       UnimplementedInstruction(instr);
diff --git a/sdk/lib/_internal/vm/lib/compact_hash.dart b/sdk/lib/_internal/vm/lib/compact_hash.dart
index 39c353f..b491dd6 100644
--- a/sdk/lib/_internal/vm/lib/compact_hash.dart
+++ b/sdk/lib/_internal/vm/lib/compact_hash.dart
@@ -109,7 +109,7 @@
   // as unsigned words.
   static int _indexSizeToHashMask(int indexSize) {
     int indexBits = indexSize.bitLength - 2;
-    return internal.is64Bit
+    return internal.has63BitSmis
         ? (1 << (32 - indexBits)) - 1
         : (1 << (30 - indexBits)) - 1;
   }
diff --git a/sdk/lib/_internal/vm/lib/core_patch.dart b/sdk/lib/_internal/vm/lib/core_patch.dart
index 34b26f3..6ffdce8 100644
--- a/sdk/lib/_internal/vm/lib/core_patch.dart
+++ b/sdk/lib/_internal/vm/lib/core_patch.dart
@@ -24,7 +24,7 @@
         POWERS_OF_TEN,
         SubListIterable,
         UnmodifiableListBase,
-        is64Bit,
+        has63BitSmis,
         makeFixedListUnmodifiable,
         makeListFixedLength,
         patch,
diff --git a/sdk/lib/_internal/vm/lib/integers_patch.dart b/sdk/lib/_internal/vm/lib/integers_patch.dart
index 4831353..fa9cf80 100644
--- a/sdk/lib/_internal/vm/lib/integers_patch.dart
+++ b/sdk/lib/_internal/vm/lib/integers_patch.dart
@@ -31,7 +31,7 @@
         return null; // Empty.
       }
     }
-    var smiLimit = is64Bit ? 18 : 9;
+    var smiLimit = has63BitSmis ? 18 : 9;
     if ((last - ix) >= smiLimit) {
       return null; // May not fit into a Smi.
     }
@@ -133,7 +133,7 @@
 
   static int _parseRadix(String source, int radix, int start, int end, int sign,
       bool allowU64, onError) {
-    int tableIndex = (radix - 2) * 4 + (is64Bit ? 2 : 0);
+    int tableIndex = (radix - 2) * 4 + (has63BitSmis ? 2 : 0);
     int blockSize = _PARSE_LIMITS[tableIndex];
     int length = end - start;
     if (length <= blockSize) {
@@ -180,7 +180,7 @@
           // Although the unsigned overflow limits do not depend on the
           // platform, the multiplier and block size, which are used to
           // compute it, do.
-          int X = is64Bit ? 1 : 0;
+          int X = has63BitSmis ? 1 : 0;
           if (allowU64 &&
               !(result >= _int64UnsignedOverflowLimits[X] &&
                   (result > _int64UnsignedOverflowLimits[X] ||
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index f1d22c9..c434ec9 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -102,9 +102,9 @@
   }
 }
 
-final bool is64Bit = _inquireIs64Bit();
+final bool has63BitSmis = _has63BitSmis();
 
-bool _inquireIs64Bit() native "Internal_inquireIs64Bit";
+bool _has63BitSmis() native "Internal_has63BitSmis";
 
 @pragma("vm:recognized", "other")
 @pragma("vm:entry-point", "call")
diff --git a/tools/VERSION b/tools/VERSION
index dacee7e..b8d079b 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 263
+PRERELEASE 264
 PRERELEASE_PATCH 0
\ No newline at end of file