Version 2.14.0-44.0.dev

Merge commit '47eff41aa0353718357007428957510b8bc8a2b3' into 'dev'
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index c6f96a4..497e8c9 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -480,6 +480,7 @@
   FfiCode.MUST_BE_A_SUBTYPE,
   FfiCode.NON_CONSTANT_TYPE_ARGUMENT,
   FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER,
+  FfiCode.NON_POSITIVE_ARRAY_DIMENSION,
   FfiCode.NON_SIZED_TYPE_ARGUMENT,
   FfiCode.PACKED_ANNOTATION,
   FfiCode.PACKED_ANNOTATION_ALIGNMENT,
diff --git a/pkg/analyzer/lib/src/dart/error/ffi_code.dart b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
index c015c40..a9b49b3 100644
--- a/pkg/analyzer/lib/src/dart/error/ffi_code.dart
+++ b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
@@ -197,6 +197,14 @@
       correction: "Try changing the type argument to be a 'NativeFunction'.");
 
   /**
+   * No parameters.
+   */
+  static const FfiCode NON_POSITIVE_ARRAY_DIMENSION = FfiCode(
+    name: 'NON_POSITIVE_INPUT_ON_ARRAY',
+    message: "Array dimensions must be positive numbers.",
+    correction: "Try changing the input to a positive number.");
+
+  /**
    * Parameters:
    * 0: the type of the field
    */
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index f330413..caff222 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -813,6 +813,13 @@
       _errorReporter.reportErrorForNode(
           FfiCode.SIZE_ANNOTATION_DIMENSIONS, annotation);
     }
+    // Check dimensions is positive
+    for (int dimension in dimensions) {
+      if (dimension <= 0) {
+        _errorReporter.reportErrorForNode(
+            FfiCode.NON_POSITIVE_ARRAY_DIMENSION, annotation);
+      }
+    }
   }
 
   /// Validate that the given [typeArgument] has a constant value. Return `true`
diff --git a/pkg/analyzer/test/src/diagnostics/ffi_array_multi_non_positive_input_test.dart b/pkg/analyzer/test/src/diagnostics/ffi_array_multi_non_positive_input_test.dart
new file mode 100644
index 0000000..cf6fd54
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/ffi_array_multi_non_positive_input_test.dart
@@ -0,0 +1,79 @@
+// 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/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FfiArrayMultiNonPositiveInput);
+  });
+}
+
+@reflectiveTest
+class FfiArrayMultiNonPositiveInput extends PubPackageResolutionTest {
+  test_multi() async {
+    await assertErrorsInCode(
+        '''
+import "dart:ffi";
+
+class MyStruct extends Struct {
+  @Array.multi([1, 2, 3, -4, 5, 6])
+  external Array<Array<Array<Array<Array<Array<Uint8>>>>>> a0;
+}
+
+void main() {}
+''', [
+      error(FfiCode.NON_POSITIVE_ARRAY_DIMENSION, 54, 33),
+    ]);
+  }
+
+  test_negative() async {
+    await assertErrorsInCode(
+        '''
+import "dart:ffi";
+
+class MyStruct extends Struct {
+  @Array.multi([-1])
+  external Array<Uint8> a0;
+}
+
+void main() {}
+''', [
+      error(FfiCode.NON_POSITIVE_ARRAY_DIMENSION, 54, 18),
+    ]);
+  }
+
+  test_non_error() async {
+    await assertNoErrorsInCode(
+'''
+import "dart:ffi";
+
+class MyStruct extends Struct {
+  @Array.multi([1])
+  external Array<Uint8> a0;
+}
+
+void main() {}
+''');
+  }
+
+  test_zero() async {
+    await assertErrorsInCode(
+'''
+import "dart:ffi";
+
+class MyStruct extends Struct {
+  @Array.multi([0])
+  external Array<Uint8> a0;
+}
+
+void main() {}
+''', [
+      error(FfiCode.NON_POSITIVE_ARRAY_DIMENSION, 54, 17),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 943c049..b3e249e 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -184,6 +184,8 @@
     as extra_annotation_on_struct_field;
 import 'extra_positional_arguments_test.dart' as extra_positional_arguments;
 import 'extra_size_annotation_carray_test.dart' as extra_size_annotation_carray;
+import 'ffi_array_multi_non_positive_input_test.dart'
+    as ffi_array_multi_non_positive_input_test;
 import 'field_in_struct_with_initializer_test.dart'
     as field_in_struct_with_initializer;
 import 'field_initialized_by_multiple_initializers_test.dart'
@@ -812,6 +814,7 @@
     extra_annotation_on_struct_field.main();
     extra_positional_arguments.main();
     extra_size_annotation_carray.main();
+    ffi_array_multi_non_positive_input_test.main();
     field_in_struct_with_initializer.main();
     field_initialized_by_multiple_initializers.main();
     final_initialized_in_declaration_and_constructor.main();
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 6ea2bbf..a5e9561 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -843,8 +843,16 @@
     if (rhs is FutureOrType) {
       if (typeHierarchy.isSubtype(
           cls.classNode, typeHierarchy.coreTypes.futureClass)) {
+        Type typeArg;
+        if (typeArgs == null) {
+          typeArg = const UnknownType();
+        } else {
+          final interfaceOffset = typeHierarchy.genericInterfaceOffsetFor(
+              cls.classNode, typeHierarchy.coreTypes.futureClass);
+          typeArg = typeArgs[interfaceOffset];
+        }
         final RuntimeType lhs =
-            typeArgs == null ? RuntimeType(DynamicType(), null) : typeArgs[0];
+            typeArg is RuntimeType ? typeArg : RuntimeType(DynamicType(), null);
         return lhs.isSubtypeOfRuntimeType(
             typeHierarchy, runtimeType.typeArgs[0]);
       } else {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart
new file mode 100644
index 0000000..26bfac0
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart
@@ -0,0 +1,21 @@
+// 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.
+
+// Regression test for https://github.com/flutter/flutter/issues/81068.
+// Verifies that TFA doesn't crash when handling a class which
+// implements Future and another generic class and a cast to FutureOr.
+
+import 'dart:async';
+
+class A<T> {}
+
+class B<T> extends A<String> implements Future<T> {
+  noSuchMethod(Invocation i) => throw 'Not implemented';
+}
+
+B createB<T>() => B<T>();
+
+void main() {
+  print(createB<int>() as FutureOr<double>);
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart.expect
new file mode 100644
index 0000000..41a1a34
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_flutter81068.dart.expect
@@ -0,0 +1,30 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+import "dart:async" as asy;
+
+import "dart:async";
+
+abstract class A<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T*>*
+    : super core::Object::•()
+    ;
+}
+class B<T extends core::Object* = dynamic> extends self::A<core::String*> implements asy::Future<self::B::T*> {
+  synthetic constructor •() → self::B<self::B::T*>*
+    : super self::A::•()
+    ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2]  method noSuchMethod(core::Invocation* i) → dynamic
+    return throw "Not implemented";
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3,getterSelectorId:4]  no-such-method-forwarder method then<R extends core::Object* = dynamic>((self::B::T*) →* FutureOr<self::B::then::R*>* onValue, {core::Function* onError = #C1}) → asy::Future<self::B::then::R*>*
+    return [@vm.direct-call.metadata=#lib::B.noSuchMethod] [@vm.inferred-type.metadata=! (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C2, 0, core::List::unmodifiable<core::Type*>([@vm.inferred-type.metadata=dart.core::_GrowableList<dart.core::Type*>] core::_GrowableList::_literal1<core::Type*>(self::B::then::R*)), core::List::unmodifiable<dynamic>([@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] core::_GrowableList::_literal1<dynamic>(onValue)), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C3: onError}))) as{TypeError,ForDynamic} asy::Future<self::B::then::R*>*;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:5,getterSelectorId:6]  no-such-method-forwarder method catchError(core::Function* onError, {[@vm.inferred-type.metadata=dart.core::Null? (value: null)] (core::Object*) →* core::bool* test = #C1}) → asy::Future<self::B::T*>*
+    return [@vm.direct-call.metadata=#lib::B.noSuchMethod] [@vm.inferred-type.metadata=! (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C4, 0, #C5, core::List::unmodifiable<dynamic>([@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] core::_GrowableList::_literal1<dynamic>(onError)), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(<core::Symbol*, dynamic>{#C6: test}))) as{TypeError,ForDynamic} asy::Future<self::B::T*>*;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:7,getterSelectorId:8]  no-such-method-forwarder method whenComplete(() →* FutureOr<void>* action) → asy::Future<self::B::T*>*
+    return [@vm.direct-call.metadata=#lib::B.noSuchMethod] [@vm.inferred-type.metadata=! (skip check)] this.{self::B::noSuchMethod}(new core::_InvocationMirror::_withType(#C7, 0, #C5, core::List::unmodifiable<dynamic>([@vm.inferred-type.metadata=dart.core::_GrowableList<dynamic>] core::_GrowableList::_literal1<dynamic>(action)), [@vm.inferred-type.metadata=dart.collection::UnmodifiableMapView<dart.core::Symbol*, dynamic>] core::Map::unmodifiable<core::Symbol*, dynamic>(#C9))) as{TypeError,ForDynamic} asy::Future<self::B::T*>*;
+}
+static method createB<T extends core::Object* = dynamic>() → self::B<dynamic>*
+  return new self::B::•<self::createB::T*>();
+static method main() → void {
+  core::print([@vm.inferred-type.metadata=#lib::B<?>] self::createB<core::int*>() as FutureOr<core::double*>*);
+}
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 24f7e68..a73d6d9 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -395,23 +395,29 @@
     return ((-0x20000000000000LL <= value) && (value <= 0x20000000000000LL));
   }
 
+  static constexpr uword NBitMaskUnsafe(uint32_t n) {
+    static_assert((sizeof(uword) * kBitsPerByte) == kBitsPerWord,
+                  "Unexpected uword size");
+    return n == kBitsPerWord ? std::numeric_limits<uword>::max()
+                             : (static_cast<uword>(1) << n) - 1;
+  }
+
   // The lowest n bits are 1, the others are 0.
-  template <typename T = uword>
-  static constexpr T NBitMask(size_t n) {
-    static_assert(std::is_integral<T>::value, "Must be integral type");
-    using Unsigned = typename std::make_unsigned<T>::type;
-    assert(n <= sizeof(T) * kBitsPerByte);
-    return n == sizeof(T) * kBitsPerByte
-               ? static_cast<T>(-1)
-               : static_cast<T>((static_cast<Unsigned>(1) << n) - 1);
+  static uword NBitMask(uint32_t n) {
+    ASSERT(n <= kBitsPerWord);
+    return NBitMaskUnsafe(n);
+  }
+
+  static word SignedNBitMask(uint32_t n) {
+    uword mask = NBitMask(n);
+    return bit_cast<word>(mask);
   }
 
   template <typename T = uword>
-  static constexpr T Bit(size_t n) {
-    static_assert(std::is_integral<T>::value, "Must be integral type");
-    using Unsigned = typename std::make_unsigned<T>::type;
-    assert(n < sizeof(T) * kBitsPerByte);
-    return static_cast<T>(static_cast<Unsigned>(1) << n);
+  static T Bit(uint32_t n) {
+    ASSERT(n < sizeof(T) * kBitsPerByte);
+    T bit = 1;
+    return bit << n;
   }
 
   template <typename T>
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index 50f2ec5..dd8bc1d 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -54,8 +54,8 @@
         UntaggedPcDescriptors::KindAndMetadata::Encode(kind, try_index,
                                                        yield_index);
 
-    encoded_data_.Write(kind_and_metadata);
-    encoded_data_.Write(pc_offset - prev_pc_offset);
+    encoded_data_.WriteSLEB128(kind_and_metadata);
+    encoded_data_.WriteSLEB128(pc_offset - prev_pc_offset);
     prev_pc_offset = pc_offset;
 
     if (!FLAG_precompiled_mode) {
@@ -80,8 +80,8 @@
         }
       }
       const int32_t encoded_pos = token_pos.Serialize();
-      encoded_data_.Write(deopt_id - prev_deopt_id);
-      encoded_data_.Write(
+      encoded_data_.WriteSLEB128(deopt_id - prev_deopt_id);
+      encoded_data_.WriteSLEB128(
           Utils::SubWithWrapAround(encoded_pos, prev_token_pos));
       prev_deopt_id = deopt_id;
       prev_token_pos = encoded_pos;
@@ -106,9 +106,9 @@
   const uword pc_delta = pc_offset - last_pc_offset_;
   const uword non_spill_slot_bit_count =
       bitmap->Length() - spill_slot_bit_count;
-  encoded_bytes_.WriteUnsigned(pc_delta);
-  encoded_bytes_.WriteUnsigned(spill_slot_bit_count);
-  encoded_bytes_.WriteUnsigned(non_spill_slot_bit_count);
+  encoded_bytes_.WriteLEB128(pc_delta);
+  encoded_bytes_.WriteLEB128(spill_slot_bit_count);
+  encoded_bytes_.WriteLEB128(non_spill_slot_bit_count);
   bitmap->AppendAsBytesTo(&encoded_bytes_);
   last_pc_offset_ = pc_offset;
 }
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index adf53b0..0d15c38 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -209,7 +209,7 @@
   using ArgField = BitField<int32_t, int32_t, OpField::kNextBit>;
 
   static constexpr int32_t kMaxArgValue =
-      Utils::NBitMask(ArgField::bitsize() - 1);
+      Utils::NBitMaskUnsafe(ArgField::bitsize() - 1);
   static constexpr int32_t kMinArgValue = ~kMaxArgValue;
   static constexpr int32_t kSignBits = static_cast<uint32_t>(kMinArgValue) << 1;
 };
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 8782aec..70f7fb0 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -778,8 +778,8 @@
   const intptr_t kCpuRegistersToPreserve =
       kDartAvailableCpuRegs & ~kNonChangeableInputRegs;
   const intptr_t kFpuRegistersToPreserve =
-      Utils::NBitMask<word>(kNumberOfFpuRegisters) &
-      ~(Utils::NBitMask<word>(kAbiPreservedFpuRegCount)
+      Utils::SignedNBitMask(kNumberOfFpuRegisters) &
+      ~(Utils::SignedNBitMask(kAbiPreservedFpuRegCount)
         << kAbiFirstPreservedFpuReg) &
       ~(1 << FpuTMP);
 
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index e79bfbc..d375c59 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -689,7 +689,7 @@
   const intptr_t kCpuRegistersToPreserve =
       kDartAvailableCpuRegs & ~kNonChangeableInputRegs;
   const intptr_t kFpuRegistersToPreserve =
-      Utils::NBitMask<word>(kNumberOfFpuRegisters) & ~Utils::Bit(FpuTMP);
+      Utils::SignedNBitMask(kNumberOfFpuRegisters) & ~(1l << FpuTMP);
 
   const intptr_t kNumTemps = (Utils::CountOneBits64(kCpuRegistersToPreserve) +
                               Utils::CountOneBits64(kFpuRegistersToPreserve));
diff --git a/runtime/vm/datastream.cc b/runtime/vm/datastream.cc
index 397f9c7..6d398fe 100644
--- a/runtime/vm/datastream.cc
+++ b/runtime/vm/datastream.cc
@@ -4,126 +4,11 @@
 
 #include "vm/datastream.h"
 
-#include "platform/text_buffer.h"
 #include "vm/compiler/runtime_api.h"
-#include "vm/os.h"
 #include "vm/zone.h"
 
 namespace dart {
 
-// Setting up needed variables for the unrolled loop sections below.
-#define UNROLLED_INIT()                                                        \
-  using Unsigned = typename std::make_unsigned<T>::type;                       \
-  Unsigned b = ReadByte();                                                     \
-  if ((b & C::kMoreDataMask) == 0) {                                           \
-    if ((b & C::kSignMask) != 0) {                                             \
-      b |= ~Utils::NBitMask<Unsigned>(C::kDataBitsPerByte);                    \
-    }                                                                          \
-    return static_cast<T>(b);                                                  \
-  }                                                                            \
-  T r = static_cast<T>(b & C::kDataByteMask);
-
-// Part of the unrolled loop where the loop may stop, having read the last part,
-// or continue reading.
-#define UNROLLED_BODY(bit_start)                                               \
-  static_assert(bit_start % C::kDataBitsPerByte == 0,                          \
-                "Bit start must be a multiple of the data bits per byte");     \
-  static_assert(bit_start >= 0 && bit_start < kBitsPerByte * sizeof(T),        \
-                "Starting unrolled body at invalid bit position");             \
-  static_assert(bit_start + C::kDataBitsPerByte < kBitsPerByte * sizeof(T),    \
-                "Unrolled body should not contain final bits in value");       \
-  b = ReadByte();                                                              \
-  r |= static_cast<Unsigned>(b & C::kDataByteMask) << bit_start;               \
-  if ((b & C::kMoreDataMask) == 0) {                                           \
-    if ((b & C::kSignMask) != 0) {                                             \
-      r |= ~Utils::NBitMask<T>(bit_start + C::kDataBitsPerByte);               \
-    }                                                                          \
-    return r;                                                                  \
-  }
-
-// The end of the unrolled loop. Does not need to handle sign extension, as the
-// last bits fill the rest of the bitspace.
-#define UNROLLED_END(bit_start)                                                \
-  static_assert(bit_start % C::kDataBitsPerByte == 0,                          \
-                "Bit start must be a multiple of the data bits per byte");     \
-  static_assert(bit_start >= 0 && bit_start < kBitsPerByte * sizeof(T),        \
-                "Starting unrolled end at invalid bit position");              \
-  static_assert(bit_start + C::kDataBitsPerByte >= kBitsPerByte * sizeof(T),   \
-                "Unrolled end does not contain final bits in value");          \
-  b = ReadByte();                                                              \
-  ASSERT_EQUAL((b & C::kMoreDataMask), 0);                                     \
-  r |= static_cast<Unsigned>(b & C::kDataByteMask) << bit_start;               \
-  return r;
-
-uint16_t ReadStream::Read16() {
-  using T = uint16_t;
-  UNROLLED_INIT();
-  UNROLLED_BODY(7);
-  UNROLLED_END(14);
-}
-
-uint32_t ReadStream::Read32() {
-  using T = uint32_t;
-  UNROLLED_INIT();
-  UNROLLED_BODY(7);
-  UNROLLED_BODY(14);
-  UNROLLED_BODY(21);
-  UNROLLED_END(28);
-}
-
-uint64_t ReadStream::Read64() {
-  using T = uint64_t;
-  UNROLLED_INIT();
-  UNROLLED_BODY(7);
-  UNROLLED_BODY(14);
-  UNROLLED_BODY(21);
-  UNROLLED_BODY(28);
-  UNROLLED_BODY(35);
-  UNROLLED_BODY(42);
-  UNROLLED_BODY(49);
-  UNROLLED_BODY(56);
-  UNROLLED_END(63);
-}
-#undef UNROLLED_INIT
-#undef UNROLLED_BODY
-#undef UNROLLED_END
-
-static constexpr intptr_t kRowSize = 16;
-
-void ReadStream::WriteWindow(BaseTextBuffer* buffer,
-                             intptr_t start,
-                             intptr_t window_size) {
-  const intptr_t buffer_size = end_ - buffer_;
-  ASSERT(0 <= start && start <= buffer_size);
-  intptr_t window_start = start - (window_size / 2);
-  intptr_t window_end = start + (window_size / 2);
-  if (window_start < 0) window_start = 0;
-  if (buffer_size < window_start + window_end) window_end = buffer_size;
-  for (intptr_t i = window_start - (window_start % kRowSize); i < window_end;
-       i += kRowSize) {
-    buffer->Printf("%016" Px " ", i);
-    intptr_t j = i;
-    if (j < window_start) {
-      while (j < window_start) {
-        buffer->AddString("    ");
-        ++j;
-      }
-    }
-    for (; j < Utils::Minimum(window_end, i + kRowSize); j++) {
-      buffer->AddChar(j == start ? '|' : ' ');
-      buffer->Printf("%02x", static_cast<uint8_t>(buffer_[j] % kMaxUint8));
-      buffer->AddChar(j == start ? '|' : ' ');
-    }
-    buffer->AddChar('\n');
-  }
-}
-
-void ReadStream::PrintWindow(intptr_t start, intptr_t window_size) {
-  TextBuffer buffer(1024);
-  WriteWindow(&buffer, start, window_size);
-  OS::Print("%s", buffer.buffer());
-}
-
 void BaseWriteStream::WriteTargetWord(word value) {
   ASSERT(compiler::target::kBitsPerWord == kBitsPerWord ||
          Utils::IsAbsoluteUint(compiler::target::kBitsPerWord, value));
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index fd343cd..7da4532 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -15,7 +15,14 @@
 
 namespace dart {
 
-class BaseTextBuffer;
+static const int8_t kDataBitsPerByte = 7;
+static const int8_t kByteMask = (1 << kDataBitsPerByte) - 1;
+static const int8_t kMaxUnsignedDataPerByte = kByteMask;
+static const int8_t kMinDataPerByte = -(1 << (kDataBitsPerByte - 1));
+static const int8_t kMaxDataPerByte = (~kMinDataPerByte & kByteMask);  // NOLINT
+static const uint8_t kEndByteMarker = (255 - kMaxDataPerByte);
+static const uint8_t kEndUnsignedByteMarker = (255 - kMaxUnsignedDataPerByte);
+
 struct LEB128Constants : AllStatic {
   // Convenience template for ensuring non-signed types trigger SFINAE.
   template <typename T, typename S>
@@ -28,13 +35,12 @@
       typename std::enable_if<std::is_unsigned<T>::value, S>::type;
 
   // (S)LEB128 encodes 7 bits of data per byte (hence 128).
-  static constexpr size_t kDataBitsPerByte = 7;
-  static constexpr auto kDataByteMask =
-      Utils::NBitMask<uint8_t>(kDataBitsPerByte);
+  static constexpr uint8_t kDataBitsPerByte = 7;
+  static constexpr uint8_t kDataByteMask = (1 << kDataBitsPerByte) - 1;
   // If more data follows a given data byte, the high bit is set.
-  static constexpr auto kMoreDataMask = Utils::Bit<uint8_t>(kDataBitsPerByte);
+  static constexpr uint8_t kMoreDataMask = (1 << kDataBitsPerByte);
   // For SLEB128, the high bit in the data of the last byte is the sign bit.
-  static constexpr auto kSignMask = Utils::Bit<uint8_t>(kDataBitsPerByte - 1);
+  static constexpr uint8_t kSignMask = (1 << (kDataBitsPerByte - 1));
 };
 
 class NonStreamingWriteStream;
@@ -87,6 +93,11 @@
     current_ += len;
   }
 
+  template <typename T = intptr_t>
+  T ReadUnsigned() {
+    return Read<T>(kEndUnsignedByteMarker);
+  }
+
   intptr_t Position() const { return current_ - buffer_; }
   void SetPosition(intptr_t value) {
     ASSERT((end_ - buffer_) >= value);
@@ -111,6 +122,11 @@
     return (end_ - current_);
   }
 
+  template <typename T>
+  T Read() {
+    return Read<T>(kEndByteMarker);
+  }
+
   uword ReadWordWith32BitReads() {
     constexpr intptr_t kNumRead32PerWord = kBitsPerWord / kBitsPerInt32;
 
@@ -127,7 +143,7 @@
 
  public:
   template <typename T = uintptr_t>
-  C::only_if_unsigned<T, T> ReadUnsigned() {
+  C::only_if_unsigned<T, T> ReadLEB128() {
     constexpr intptr_t kBitsPerT = kBitsPerByte * sizeof(T);
     T r = 0;
     uint8_t s = 0;
@@ -143,12 +159,12 @@
   }
 
   template <typename T>
-  C::only_if_signed<T, T> ReadUnsigned() {
-    return bit_cast<T>(ReadUnsigned<typename std::make_unsigned<T>::type>());
+  C::only_if_signed<T, T> ReadLEB128() {
+    return bit_cast<T>(ReadLEB128<typename std::make_unsigned<T>::type>());
   }
 
   template <typename T>
-  C::only_if_unsigned<T, T> Read() {
+  C::only_if_unsigned<T, T> ReadSLEB128() {
     constexpr intptr_t kBitsPerT = kBitsPerByte * sizeof(T);
     T r = 0;
     uint8_t s = 0;
@@ -164,33 +180,114 @@
     // value. If the value is negative and the count of data bits is less than
     // the size of the value, then we need to extend the sign by setting the
     // remaining (unset) most significant bits (MSBs).
+    T sign_bits = 0;
     if ((b & C::kSignMask) != 0 && s < kBitsPerT) {
       // Create a bitmask for the current data bits and invert it.
-      r |= ~Utils::NBitMask<T>(s);
+      sign_bits = ~((static_cast<T>(1) << s) - 1);
     }
-    return r;
+    return r | sign_bits;
   }
 
   template <typename T = intptr_t>
-  C::only_if_signed<T, T> Read() {
-    return bit_cast<T>(Read<typename std::make_unsigned<T>::type>());
+  C::only_if_signed<T, T> ReadSLEB128() {
+    return bit_cast<T>(ReadSLEB128<typename std::make_unsigned<T>::type>());
   }
 
  private:
-  uint16_t Read16();
-  uint32_t Read32();
-  uint64_t Read64();
+  uint16_t Read16() { return Read16(kEndByteMarker); }
+
+  uint32_t Read32() { return Read32(kEndByteMarker); }
+
+  uint64_t Read64() { return Read64(kEndByteMarker); }
+
+  template <typename T>
+  T Read(uint8_t end_byte_marker) {
+    using Unsigned = typename std::make_unsigned<T>::type;
+    Unsigned b = ReadByte();
+    if (b > kMaxUnsignedDataPerByte) {
+      return b - end_byte_marker;
+    }
+    T r = 0;
+    uint8_t s = 0;
+    do {
+      r |= static_cast<Unsigned>(b) << s;
+      s += kDataBitsPerByte;
+      b = ReadByte();
+    } while (b <= kMaxUnsignedDataPerByte);
+    return r | (static_cast<Unsigned>(b - end_byte_marker) << s);
+  }
+
+// Setting up needed variables for the unrolled loop sections below.
+#define UNROLLED_INIT()                                                        \
+  using Unsigned = typename std::make_unsigned<T>::type;                       \
+  Unsigned b = ReadByte();                                                     \
+  if (b > kMaxUnsignedDataPerByte) {                                           \
+    return b - end_byte_marker;                                                \
+  }                                                                            \
+  T r = b;
+
+// Part of the unrolled loop where the loop may stop, having read the last part,
+// or continue reading.
+#define UNROLLED_BODY(bit_start)                                               \
+  static_assert(bit_start % kDataBitsPerByte == 0,                             \
+                "Bit start must be a multiple of the data bits per byte");     \
+  static_assert(bit_start >= 0 && bit_start < kBitsPerByte * sizeof(T),        \
+                "Starting unrolled body at invalid bit position");             \
+  static_assert(bit_start + kDataBitsPerByte < kBitsPerByte * sizeof(T),       \
+                "Unrolled body should not contain final bits in value");       \
+  b = ReadByte();                                                              \
+  if (b > kMaxUnsignedDataPerByte) {                                           \
+    return r | (static_cast<T>(b - end_byte_marker) << bit_start);             \
+  }                                                                            \
+  r |= b << bit_start;
+
+// The end of the unrolled loop.
+#define UNROLLED_END(bit_start)                                                \
+  static_assert(bit_start % kDataBitsPerByte == 0,                             \
+                "Bit start must be a multiple of the data bits per byte");     \
+  static_assert(bit_start >= 0 && bit_start < kBitsPerByte * sizeof(T),        \
+                "Starting unrolled end at invalid bit position");              \
+  static_assert(bit_start + kDataBitsPerByte >= kBitsPerByte * sizeof(T),      \
+                "Unrolled end does not contain final bits in value");          \
+  b = ReadByte();                                                              \
+  ASSERT(b > kMaxUnsignedDataPerByte);                                         \
+  return r | (static_cast<T>(b - end_byte_marker) << bit_start);
+
+  uint16_t Read16(uint8_t end_byte_marker) {
+    using T = uint16_t;
+    UNROLLED_INIT();
+    UNROLLED_BODY(7);
+    UNROLLED_END(14);
+  }
+
+  uint32_t Read32(uint8_t end_byte_marker) {
+    using T = uint32_t;
+    UNROLLED_INIT();
+    UNROLLED_BODY(7);
+    UNROLLED_BODY(14);
+    UNROLLED_BODY(21);
+    UNROLLED_END(28);
+  }
+
+  uint64_t Read64(uint8_t end_byte_marker) {
+    using T = uint64_t;
+    UNROLLED_INIT();
+    UNROLLED_BODY(7);
+    UNROLLED_BODY(14);
+    UNROLLED_BODY(21);
+    UNROLLED_BODY(28);
+    UNROLLED_BODY(35);
+    UNROLLED_BODY(42);
+    UNROLLED_BODY(49);
+    UNROLLED_BODY(56);
+    UNROLLED_END(63);
+  }
 
   DART_FORCE_INLINE uint8_t ReadByte() {
     ASSERT(current_ < end_);
     return *current_++;
   }
 
-  void WriteWindow(BaseTextBuffer* buffer,
-                   intptr_t start,
-                   intptr_t window_size = 64);
-  void PrintWindow(intptr_t start, intptr_t window_size = 64);
-
  private:
   const uint8_t* buffer_;
   const uint8_t* current_;
@@ -267,6 +364,16 @@
     }
   }
 
+  template <typename T>
+  void WriteUnsigned(T value) {
+    ASSERT(value >= 0);
+    while (value > kMaxUnsignedDataPerByte) {
+      WriteByte(static_cast<uint8_t>(value & kByteMask));
+      value = value >> kDataBitsPerByte;
+    }
+    WriteByte(static_cast<uint8_t>(value + kEndUnsignedByteMarker));
+  }
+
   void WriteBytes(const void* addr, intptr_t len) {
     if (len != 0) {
       EnsureSpace(len);
@@ -306,6 +413,16 @@
   }
 
   template <typename T>
+  void Write(T value) {
+    T v = value;
+    while (v < kMinDataPerByte || v > kMaxDataPerByte) {
+      WriteByte(static_cast<uint8_t>(v & kByteMask));
+      v = v >> kDataBitsPerByte;
+    }
+    WriteByte(static_cast<uint8_t>(v + kEndByteMarker));
+  }
+
+  template <typename T>
   void WriteFixed(T value) {
     WriteBytes(&value, sizeof(value));
   }
@@ -322,7 +439,7 @@
 
  public:
   template <typename T>
-  C::only_if_unsigned<T, void> WriteUnsigned(T value) {
+  C::only_if_unsigned<T, void> WriteLEB128(T value) {
     T remainder = value;
     bool is_last_part;
     do {
@@ -339,15 +456,15 @@
   }
 
   template <typename T>
-  C::only_if_signed<T, void> WriteUnsigned(T value) {
+  C::only_if_signed<T, void> WriteLEB128(T value) {
     // If we're trying to LEB128 encode a negative value, chances are we should
     // be using SLEB128 instead.
     ASSERT(value >= 0);
-    return WriteUnsigned(bit_cast<typename std::make_unsigned<T>::type>(value));
+    return WriteLEB128(bit_cast<typename std::make_unsigned<T>::type>(value));
   }
 
   template <typename T>
-  C::only_if_signed<T, void> Write(T value) {
+  C::only_if_signed<T, void> WriteSLEB128(T value) {
     constexpr intptr_t kBitsPerT = kBitsPerByte * sizeof(T);
     using Unsigned = typename std::make_unsigned<T>::type;
     // Record whether the original value was negative.
@@ -392,8 +509,8 @@
   }
 
   template <typename T>
-  C::only_if_unsigned<T, void> Write(T value) {
-    return Write(bit_cast<typename std::make_signed<T>::type>(value));
+  C::only_if_unsigned<T, void> WriteSLEB128(T value) {
+    return WriteSLEB128(bit_cast<typename std::make_signed<T>::type>(value));
   }
 
  protected:
diff --git a/runtime/vm/datastream_test.cc b/runtime/vm/datastream_test.cc
index ec8eb5b..0b9ba6c 100644
--- a/runtime/vm/datastream_test.cc
+++ b/runtime/vm/datastream_test.cc
@@ -126,4 +126,60 @@
   TestRaw<int64_t>();
 }
 
+TEST_CASE(BaseWriteStream_WriteLEB128) {
+  MallocWriteStream writer(1 * KB);
+  for (uintptr_t i = 0; i < kUnsignedEnd; i++) {
+    writer.WriteLEB128(i);
+  }
+  DEFINE_LARGE_CONSTANTS(uintptr_t);
+  writer.WriteLEB128(all_ones);
+  writer.WriteLEB128(min);
+  writer.WriteLEB128(max);
+  writer.WriteLEB128(half_min);
+  writer.WriteLEB128(half_max);
+  ReadStream reader(writer.buffer(), writer.bytes_written());
+  for (uintptr_t i = 0; i < kUnsignedEnd; i++) {
+    const uintptr_t r = reader.ReadLEB128();
+    EXPECT_EQ(i, r);
+  }
+  const uintptr_t read_all_ones = reader.ReadLEB128();
+  EXPECT_EQ(all_ones, read_all_ones);
+  const uintptr_t read_min = reader.ReadLEB128();
+  EXPECT_EQ(min, read_min);
+  const uintptr_t read_max = reader.ReadLEB128();
+  EXPECT_EQ(max, read_max);
+  const uintptr_t read_half_min = reader.ReadLEB128();
+  EXPECT_EQ(half_min, read_half_min);
+  const uintptr_t read_half_max = reader.ReadLEB128();
+  EXPECT_EQ(half_max, read_half_max);
+}
+
+TEST_CASE(BaseWriteStream_WriteSLEB128) {
+  MallocWriteStream writer(1 * KB);
+  for (intptr_t i = kSignedStart; i < kSignedEnd; i++) {
+    writer.WriteSLEB128(i);
+  }
+  DEFINE_LARGE_CONSTANTS(intptr_t);
+  writer.WriteSLEB128(all_ones);
+  writer.WriteSLEB128(min);
+  writer.WriteSLEB128(max);
+  writer.WriteSLEB128(half_min);
+  writer.WriteSLEB128(half_max);
+  ReadStream reader(writer.buffer(), writer.bytes_written());
+  for (intptr_t i = kSignedStart; i < kSignedEnd; i++) {
+    const intptr_t r = reader.ReadSLEB128();
+    EXPECT_EQ(i, r);
+  }
+  const intptr_t read_all_ones = reader.ReadSLEB128();
+  EXPECT_EQ(all_ones, read_all_ones);
+  const intptr_t read_min = reader.ReadSLEB128();
+  EXPECT_EQ(min, read_min);
+  const intptr_t read_max = reader.ReadSLEB128();
+  EXPECT_EQ(max, read_max);
+  const intptr_t read_half_min = reader.ReadSLEB128();
+  EXPECT_EQ(half_min, read_half_min);
+  const intptr_t read_half_max = reader.ReadSLEB128();
+  EXPECT_EQ(half_max, read_half_max);
+}
+
 }  // namespace dart
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index dd11e4d..7f17df5 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -1106,8 +1106,8 @@
         stream_(ASSERT_NOTNULL(stream)),
         table_(table) {}
 
-  void sleb128(intptr_t value) { stream_->Write(value); }
-  void uleb128(uintptr_t value) { stream_->WriteUnsigned(value); }
+  void sleb128(intptr_t value) { stream_->WriteSLEB128(value); }
+  void uleb128(uintptr_t value) { stream_->WriteLEB128(value); }
   void u1(uint8_t value) { stream_->WriteByte(value); }
   void u2(uint16_t value) { stream_->WriteFixed(value); }
   void u4(uint32_t value) { stream_->WriteFixed(value); }
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index c14919a..38ca8fa 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -309,14 +309,14 @@
 
   intptr_t ReadSLEB128() {
     ReadStream stream(this->buffer(), size_, offset_);
-    const intptr_t result = stream.Read();
+    const intptr_t result = stream.ReadSLEB128();
     offset_ = stream.Position();
     return result;
   }
 
   int64_t ReadSLEB128AsInt64() {
     ReadStream stream(this->buffer(), size_, offset_);
-    const int64_t result = stream.Read<int64_t>();
+    const int64_t result = stream.ReadSLEB128<int64_t>();
     offset_ = stream.Position();
     return result;
   }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 4a9f094..e163b57 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -14667,7 +14667,7 @@
   NoSafepointScope scope;
   ReadStream stream(maps_.untag()->data(), maps_.payload_size(), next_offset_);
 
-  auto const pc_delta = stream.ReadUnsigned();
+  auto const pc_delta = stream.ReadLEB128();
   ASSERT(pc_delta <= (kMaxUint32 - current_pc_offset_));
   current_pc_offset_ += pc_delta;
 
@@ -14675,7 +14675,7 @@
   // the post-delta part of inlined entries has the same information as
   // global table entries.
   if (maps_.UsesGlobalTable()) {
-    current_global_table_offset_ = stream.ReadUnsigned();
+    current_global_table_offset_ = stream.ReadLEB128();
     ASSERT(current_global_table_offset_ < bits_container_.payload_size());
 
     // Since generally we only use entries in the GC and the GC only needs
@@ -14688,10 +14688,10 @@
 
     next_offset_ = stream.Position();
   } else {
-    current_spill_slot_bit_count_ = stream.ReadUnsigned();
+    current_spill_slot_bit_count_ = stream.ReadLEB128();
     ASSERT(current_spill_slot_bit_count_ >= 0);
 
-    current_non_spill_slot_bit_count_ = stream.ReadUnsigned();
+    current_non_spill_slot_bit_count_ = stream.ReadLEB128();
     ASSERT(current_non_spill_slot_bit_count_ >= 0);
 
     const auto stackmap_bits =
@@ -14737,10 +14737,10 @@
                     bits_container_.payload_size(),
                     current_global_table_offset_);
 
-  current_spill_slot_bit_count_ = stream.ReadUnsigned();
+  current_spill_slot_bit_count_ = stream.ReadLEB128();
   ASSERT(current_spill_slot_bit_count_ >= 0);
 
-  current_non_spill_slot_bit_count_ = stream.ReadUnsigned();
+  current_non_spill_slot_bit_count_ = stream.ReadLEB128();
   ASSERT(current_non_spill_slot_bit_count_ >= 0);
 
   const auto stackmap_bits = Length();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index a03be0a..9ddb727 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -5641,7 +5641,7 @@
                         byte_index_);
       // Moves to record that matches kind_mask_.
       while (byte_index_ < descriptors_.Length()) {
-        const int32_t kind_and_metadata = stream.Read<int32_t>();
+        const int32_t kind_and_metadata = stream.ReadSLEB128<int32_t>();
         cur_kind_ = UntaggedPcDescriptors::KindAndMetadata::DecodeKind(
             kind_and_metadata);
         cur_try_index_ = UntaggedPcDescriptors::KindAndMetadata::DecodeTryIndex(
@@ -5650,12 +5650,12 @@
             UntaggedPcDescriptors::KindAndMetadata::DecodeYieldIndex(
                 kind_and_metadata);
 
-        cur_pc_offset_ += stream.Read();
+        cur_pc_offset_ += stream.ReadSLEB128();
 
         if (!FLAG_precompiled_mode) {
-          cur_deopt_id_ += stream.Read();
-          cur_token_pos_ =
-              Utils::AddWithWrapAround(cur_token_pos_, stream.Read<int32_t>());
+          cur_deopt_id_ += stream.ReadSLEB128();
+          cur_token_pos_ = Utils::AddWithWrapAround(
+              cur_token_pos_, stream.ReadSLEB128<int32_t>());
         }
         byte_index_ = stream.Position();
 
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index e90c8ad..4bb663a 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -502,8 +502,8 @@
   // initial offset of the entry in the array.
   intptr_t EncodeTo(NonStreamingWriteStream* stream) {
     auto const current_offset = stream->Position();
-    stream->WriteUnsigned(spill_slot_bit_count_);
-    stream->WriteUnsigned(non_spill_slot_bit_count_);
+    stream->WriteLEB128(spill_slot_bit_count_);
+    stream->WriteLEB128(non_spill_slot_bit_count_);
     {
       NoSafepointScope scope;
       stream->WriteBytes(PayloadData(), PayloadLength());
@@ -711,8 +711,8 @@
         StackMapEntry entry(zone_, it);
         const intptr_t entry_offset = entry_offsets_.LookupValue(&entry);
         const intptr_t pc_delta = it.pc_offset() - last_offset;
-        new_payload.WriteUnsigned(pc_delta);
-        new_payload.WriteUnsigned(entry_offset);
+        new_payload.WriteLEB128(pc_delta);
+        new_payload.WriteLEB128(entry_offset);
         last_offset = it.pc_offset();
       }
       return CompressedStackMaps::NewUsingTable(new_payload.buffer(),
diff --git a/runtime/vm/v8_snapshot_writer.h b/runtime/vm/v8_snapshot_writer.h
index 99ba832..ea0a0e7 100644
--- a/runtime/vm/v8_snapshot_writer.h
+++ b/runtime/vm/v8_snapshot_writer.h
@@ -58,7 +58,7 @@
    private:
     static constexpr size_t kIdSpaceBits =
         Utils::BitLength(static_cast<int64_t>(IdSpace::kArtificial));
-    static constexpr int64_t kIdSpaceMask = Utils::NBitMask(kIdSpaceBits);
+    static constexpr int64_t kIdSpaceMask = Utils::NBitMaskUnsafe(kIdSpaceBits);
     static const char* IdSpaceToCString(IdSpace space);
 
     int64_t encoded_;
diff --git a/tools/VERSION b/tools/VERSION
index dd4adca..0364727 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 43
+PRERELEASE 44
 PRERELEASE_PATCH 0
\ No newline at end of file