Version 2.12.0-98.0.dev

Merge commit 'd2b5aad64aaca693aafdb9005e3f9b87fc976941' into 'dev'
diff --git a/pkg/dartdev/lib/src/analytics.dart b/pkg/dartdev/lib/src/analytics.dart
index f8e8ffc..14b9fb2 100644
--- a/pkg/dartdev/lib/src/analytics.dart
+++ b/pkg/dartdev/lib/src/analytics.dart
@@ -15,17 +15,21 @@
 const String analyticsNoticeOnFirstRunMessage = '''
   ╔════════════════════════════════════════════════════════════════════════════╗
   ║ The Dart tool uses Google Analytics to anonymously report feature usage    ║
-  ║ statistics, and crash reporting to send basic crash reports. This data is  ║
-  ║ used to help improve the Dart platform and tools over time.                ║
+  ║ statistics and to send basic crash reports. This data is used to help      ║
+  ║ improve the Dart platform and tools over time.                             ║
   ║                                                                            ║
-  ║ To disable reporting of anonymous tool usage statistics in general, run    ║
-  ║ the command: `dart --disable-analytics`.                                   ║
+  ║ To disable reporting of anonymous analytics, run:                          ║
+  ║                                                                            ║
+  ║   dart --disable-analytics                                                 ║
+  ║                                                                            ║
   ╚════════════════════════════════════════════════════════════════════════════╝
 ''';
 const String analyticsDisabledNoticeMessage = '''
   ╔════════════════════════════════════════════════════════════════════════════╗
-  ║ Anonymous analytics disabled. To enable again, run the command:            ║
-  ║ `dart --enable-analytics`                                                  ║
+  ║ Anonymous analytics reporting disabled. In order to enable it, run:        ║
+  ║                                                                            ║
+  ║   dart --enable-analytics                                                  ║
+  ║                                                                            ║
   ╚════════════════════════════════════════════════════════════════════════════╝
 ''';
 const String _appName = 'dartdev';
@@ -34,8 +38,8 @@
 const String _trackingId = 'UA-26406144-37';
 const String _readmeFileName = 'README.txt';
 const String _readmeFileContents = '''
-The present directory contains user-level settings for the
-Dart programming language (https://dart.dev).
+This directory contains user-level settings for the Dart programming language
+(https://dart.dev).
 ''';
 
 const String eventCategory = 'dartdev';
@@ -55,8 +59,10 @@
   if (disableAnalytics) {
     // Dartdev tests pass a hidden 'disable-dartdev-analytics' flag which is
     // handled here.
-    // Also, stdout.hasTerminal is checked, if there is no terminal we infer that
-    // a machine is running dartdev so we return analytics shouldn't be set.
+    //
+    // Also, stdout.hasTerminal is checked; if there is no terminal we infer
+    // that a machine is running dartdev so we return that analytics shouldn't
+    // be set enabled.
     return DisabledAnalytics(_trackingId, _appName);
   }
 
diff --git a/pkg/scrape/lib/scrape.dart b/pkg/scrape/lib/scrape.dart
index 6359494..32ab6715 100644
--- a/pkg/scrape/lib/scrape.dart
+++ b/pkg/scrape/lib/scrape.dart
@@ -50,6 +50,10 @@
   int get scrapedLineCount => _scrapedLineCount;
   int _scrapedLineCount = 0;
 
+  /// The number of files that could not be parsed.
+  int get errorFileCount => _errorFileCount;
+  int _errorFileCount = 0;
+
   final Map<String, Histogram> _histograms = {};
 
   /// Whether we're in the middle of writing the running file count and need a
@@ -151,10 +155,22 @@
       histogram.printCounts(name);
     });
 
+    String count(int n, String unit) {
+      if (n == 1) return '1 $unit';
+      return '$n ${unit}s';
+    }
+
     var elapsed = _formatDuration(watch.elapsed);
-    var lines = _scrapedLineCount != 1 ? '$_scrapedLineCount lines' : '1 line';
-    var files = _scrapedFileCount != 1 ? '$_scrapedFileCount files' : '1 file';
-    print('Took $elapsed to scrape $lines in $files.');
+    var lines = count(_scrapedLineCount, 'line');
+    var files = count(_scrapedFileCount, 'file');
+    var message = 'Took $elapsed to scrape $lines in $files.';
+
+    if (_errorFileCount > 0) {
+      var errors = count(_errorFileCount, 'file');
+      message += ' ($errors could not be parsed.)';
+    }
+
+    print(message);
   }
 
   /// Display [message], clearing the line if necessary.
@@ -242,16 +258,18 @@
     var source = file.readAsStringSync();
 
     var errorListener = ErrorListener(this, _printErrors);
+    var featureSet = FeatureSet.latestLanguageVersion();
 
     // Tokenize the source.
     var reader = CharSequenceReader(source);
     var stringSource = StringSource(source, file.path);
     var scanner = Scanner(stringSource, reader, errorListener);
+    scanner.configureFeatures(
+        featureSet: featureSet, featureSetForOverriding: featureSet);
     var startToken = scanner.tokenize();
 
     // Parse it.
-    var parser = Parser(stringSource, errorListener,
-        featureSet: FeatureSet.latestLanguageVersion());
+    var parser = Parser(stringSource, errorListener, featureSet: featureSet);
     parser.enableOptionalNewAndConst = true;
     parser.enableSetLiterals = true;
 
@@ -277,6 +295,12 @@
       return;
     }
 
+    // Don't process files with syntax errors.
+    if (errorListener.hadError) {
+      _errorFileCount++;
+      return;
+    }
+
     var lineInfo = LineInfo(scanner.lineStarts);
 
     _scrapedFileCount++;
diff --git a/pkg/scrape/lib/src/error_listener.dart b/pkg/scrape/lib/src/error_listener.dart
index 69c9118..655959c 100644
--- a/pkg/scrape/lib/src/error_listener.dart
+++ b/pkg/scrape/lib/src/error_listener.dart
@@ -9,11 +9,16 @@
 class ErrorListener implements AnalysisErrorListener {
   final Scrape _scrape;
   final bool _printErrors;
+  bool _hadError = false;
 
   ErrorListener(this._scrape, this._printErrors);
 
+  bool get hadError => _hadError;
+
   @override
   void onError(AnalysisError error) {
+    _hadError = true;
+
     if (_printErrors) {
       _scrape.log(error);
     }
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 1454154..5c69ac5 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1142,8 +1142,8 @@
         field ^= refs.At(i);
         field.set_guarded_cid_unsafe(kDynamicCid);
         field.set_is_nullable_unsafe(true);
-        field.set_guarded_list_length(Field::kNoFixedLength);
-        field.set_guarded_list_length_in_object_offset(
+        field.set_guarded_list_length_unsafe(Field::kNoFixedLength);
+        field.set_guarded_list_length_in_object_offset_unsafe(
             Field::kUnknownLengthOffset);
         field.set_static_type_exactness_state(
             StaticTypeExactnessState::NotTracking());
@@ -1151,7 +1151,7 @@
     } else {
       for (intptr_t i = start_index_; i < stop_index_; i++) {
         field ^= refs.At(i);
-        field.InitializeGuardedListLengthInObjectOffset();
+        field.InitializeGuardedListLengthInObjectOffset(/*unsafe=*/true);
       }
     }
   }
diff --git a/runtime/vm/compiler/ffi/abi.cc b/runtime/vm/compiler/ffi/abi.cc
index f3ea956..1d3bd8b 100644
--- a/runtime/vm/compiler/ffi/abi.cc
+++ b/runtime/vm/compiler/ffi/abi.cc
@@ -51,7 +51,7 @@
 #elif (defined(TARGET_ARCH_IA32) && /* NOLINT(whitespace/parens) */            \
        (defined(TARGET_OS_LINUX) || defined(TARGET_OS_MACOS) ||                \
         defined(TARGET_OS_ANDROID))) ||                                        \
-    (defined(TARGET_ARCH_ARM) && defined(TARGET_OS_IOS))
+    (defined(TARGET_ARCH_ARM) && defined(TARGET_OS_MACOS_IOS))
   return Abi::kWordSize32Align32;
 #elif defined(TARGET_ARCH_IA32) && defined(TARGET_OS_WINDOWS) ||               \
     defined(TARGET_ARCH_ARM)
diff --git a/runtime/vm/cpu_arm.cc b/runtime/vm/cpu_arm.cc
index a541934..f5f806a 100644
--- a/runtime/vm/cpu_arm.cc
+++ b/runtime/vm/cpu_arm.cc
@@ -57,7 +57,7 @@
             "Use integer division instruction if supported");
 
 #if defined(TARGET_HOST_MISMATCH)
-#if defined(TARGET_OS_ANDROID) || defined(TARGET_OS_IOS)
+#if defined(TARGET_OS_ANDROID) || defined(TARGET_OS_MACOS_IOS)
 DEFINE_FLAG(bool, sim_use_hardfp, false, "Use the hardfp ABI.");
 #else
 DEFINE_FLAG(bool, sim_use_hardfp, true, "Use the hardfp ABI.");
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 88ec7dc..1c7d1224 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -10130,12 +10130,13 @@
 #endif  // !defined(PRODUCT)
   result.set_guarded_cid_unsafe(use_guarded_cid ? kIllegalCid : kDynamicCid);
   result.set_is_nullable_unsafe(use_guarded_cid ? false : true);
-  result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
+  result.set_guarded_list_length_in_object_offset_unsafe(
+      Field::kUnknownLengthOffset);
   // Presently, we only attempt to remember the list length for final fields.
   if (is_final && use_guarded_cid) {
-    result.set_guarded_list_length(Field::kUnknownFixedLength);
+    result.set_guarded_list_length_unsafe(Field::kUnknownFixedLength);
   } else {
-    result.set_guarded_list_length(Field::kNoFixedLength);
+    result.set_guarded_list_length_unsafe(Field::kNoFixedLength);
   }
 }
 
@@ -10219,7 +10220,7 @@
   return Smi::Value(raw_ptr()->guarded_list_length_);
 }
 
-void Field::set_guarded_list_length(intptr_t list_length) const {
+void Field::set_guarded_list_length_unsafe(intptr_t list_length) const {
   ASSERT(Thread::Current()->IsMutatorThread());
   ASSERT(IsOriginal());
   StoreSmi(&raw_ptr()->guarded_list_length_, Smi::New(list_length));
@@ -10229,7 +10230,7 @@
   return raw_ptr()->guarded_list_length_in_object_offset_ + kHeapObjectTag;
 }
 
-void Field::set_guarded_list_length_in_object_offset(
+void Field::set_guarded_list_length_in_object_offset_unsafe(
     intptr_t list_length_offset) const {
   ASSERT(Thread::Current()->IsMutatorThread());
   ASSERT(IsOriginal());
@@ -10610,15 +10611,17 @@
                              class_name, exactness);
 }
 
-void Field::InitializeGuardedListLengthInObjectOffset() const {
+void Field::InitializeGuardedListLengthInObjectOffset(bool unsafe) const {
+  auto setter = unsafe ? &Field::set_guarded_list_length_in_object_offset_unsafe
+                       : &Field::set_guarded_list_length_in_object_offset;
   ASSERT(IsOriginal());
   if (needs_length_check() &&
       (guarded_list_length() != Field::kUnknownFixedLength)) {
     const intptr_t offset = GetListLengthOffset(guarded_cid());
-    set_guarded_list_length_in_object_offset(offset);
+    (this->*setter)(offset);
     ASSERT(offset != Field::kUnknownLengthOffset);
   } else {
-    set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
+    (this->*setter)(Field::kUnknownLengthOffset);
   }
 }
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index df9585d..2529322 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4188,12 +4188,22 @@
   // been determined. If length is kNoFixedLength this field has multiple
   // list lengths associated with it and cannot be predicted.
   intptr_t guarded_list_length() const;
-  void set_guarded_list_length(intptr_t list_length) const;
+  void set_guarded_list_length_unsafe(intptr_t list_length) const;
+  void set_guarded_list_length(intptr_t list_length) const {
+    DEBUG_ASSERT(
+        IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
+    set_guarded_list_length_unsafe(list_length);
+  }
   static intptr_t guarded_list_length_offset() {
     return OFFSET_OF(FieldLayout, guarded_list_length_);
   }
   intptr_t guarded_list_length_in_object_offset() const;
-  void set_guarded_list_length_in_object_offset(intptr_t offset) const;
+  void set_guarded_list_length_in_object_offset_unsafe(intptr_t offset) const;
+  void set_guarded_list_length_in_object_offset(intptr_t offset) const {
+    DEBUG_ASSERT(
+        IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
+    set_guarded_list_length_in_object_offset_unsafe(offset);
+  }
   static intptr_t guarded_list_length_in_object_offset_offset() {
     return OFFSET_OF(FieldLayout, guarded_list_length_in_object_offset_);
   }
@@ -4273,7 +4283,7 @@
   // deoptimization of dependent optimized code.
   void RecordStore(const Object& value) const;
 
-  void InitializeGuardedListLengthInObjectOffset() const;
+  void InitializeGuardedListLengthInObjectOffset(bool unsafe = false) const;
 
   // Return the list of optimized code objects that were optimized under
   // assumptions about guarded class id and nullability of this field.
diff --git a/tools/VERSION b/tools/VERSION
index 3555982..66b843c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 97
+PRERELEASE 98
 PRERELEASE_PATCH 0
\ No newline at end of file