Version 2.15.0-116.0.dev

Merge commit 'cafa530277704bb5b5d1384e3fe8018830135f7c' into 'dev'
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 9e2f6f5..c254a6c 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -8,6 +8,7 @@
 import 'package:_fe_analyzer_shared/src/util/link.dart';
 
 import 'package:kernel/ast.dart';
+import 'package:kernel/canonical_name.dart' as kernel;
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
 import 'package:kernel/core_types.dart' show CoreTypes;
 import 'package:kernel/type_algebra.dart';
@@ -875,10 +876,66 @@
     return inferredTypes;
   }
 
+  ObjectAccessTarget _findShownExtensionTypeMember(
+      ExtensionType receiverType, Name name, int fileOffset,
+      {required ObjectAccessTarget defaultTarget,
+      required bool isSetter,
+      required bool isPotentiallyNullable}) {
+    Extension extension = receiverType.extension;
+    ExtensionTypeShowHideClause? showHideClause = extension.showHideClause;
+    if (showHideClause == null) return defaultTarget;
+
+    kernel.Reference? findMember(Name name, List<kernel.Reference> references,
+        List<Supertype> interfaces,
+        {required bool isSetter}) {
+      for (kernel.Reference reference in references) {
+        if (reference.asMember.name == name) {
+          return reference;
+        }
+      }
+      for (Supertype interface in interfaces) {
+        Member? member = classHierarchy
+            .getInterfaceMember(interface.classNode, name, setter: isSetter);
+        if (member != null) {
+          return member.reference;
+        }
+      }
+      return null;
+    }
+
+    List<kernel.Reference> shownReferences = isSetter
+        ? showHideClause.shownSetters
+        : <kernel.Reference>[
+            ...showHideClause.shownGetters,
+            ...showHideClause.shownMethods,
+            ...showHideClause.shownOperators
+          ];
+    List<kernel.Reference> hiddenReferences = isSetter
+        ? showHideClause.hiddenSetters
+        : <kernel.Reference>[
+            ...showHideClause.hiddenGetters,
+            ...showHideClause.hiddenMethods,
+            ...showHideClause.hiddenOperators
+          ];
+
+    kernel.Reference? reference = findMember(
+        name, shownReferences, showHideClause.shownSupertypes,
+        isSetter: isSetter);
+    if (reference != null &&
+        findMember(name, hiddenReferences, showHideClause.hiddenSupertypes,
+                isSetter: isSetter) ==
+            null) {
+      return new ObjectAccessTarget.interfaceMember(reference.asMember,
+          isPotentiallyNullable: isPotentiallyNullable);
+    }
+
+    return defaultTarget;
+  }
+
   /// Returns extension member declared immediately for [receiverType].
   ///
   /// If none is found, [defaultTarget] is returned.
-  ObjectAccessTarget _findDirectExtensionMember(
+  ObjectAccessTarget _findDirectExtensionTypeMember(
       ExtensionType receiverType, Name name, int fileOffset,
       {required ObjectAccessTarget defaultTarget}) {
     Member? targetMember;
@@ -1175,8 +1232,14 @@
           : const ObjectAccessTarget.callFunction();
     } else if (library.enableExtensionTypesInLibrary &&
         receiverBound is ExtensionType) {
-      target = _findDirectExtensionMember(receiverBound, name, fileOffset,
+      target = _findDirectExtensionTypeMember(receiverBound, name, fileOffset,
           defaultTarget: const ObjectAccessTarget.missing());
+      if (target.kind == ObjectAccessTargetKind.missing) {
+        target = _findShownExtensionTypeMember(receiverBound, name, fileOffset,
+            isSetter: setter,
+            isPotentiallyNullable: isReceiverTypePotentiallyNullable,
+            defaultTarget: const ObjectAccessTarget.missing());
+      }
     } else {
       target = const ObjectAccessTarget.missing();
     }
diff --git a/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart
new file mode 100644
index 0000000..387f28d
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart
@@ -0,0 +1,19 @@
+// 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.
+
+extension E on double show num {}
+
+expectIdentical(dynamic a, dynamic b) {
+  if (!identical(a, b)) {
+    throw "Expected '${a}' and '${b}' to be identical.";
+  }
+}
+
+test(E e, int value) {
+  expectIdentical(e.ceil(), value);
+}
+
+main() {
+  test(3.14, 4);
+}
diff --git a/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.strong.expect b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.strong.expect
new file mode 100644
index 0000000..61492c2
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.strong.expect
@@ -0,0 +1,17 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+extension E on core::double show-types core::num {
+}
+static method expectIdentical(dynamic a, dynamic b) → dynamic {
+  if(!core::identical(a, b)) {
+    throw "Expected '${a}' and '${b}' to be identical.";
+  }
+}
+static method test(self::E e, core::int value) → dynamic {
+  self::expectIdentical(e.{core::num::ceil}(){() → core::int}, value);
+}
+static method main() → dynamic {
+  self::test(3.14, 4);
+}
diff --git a/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.textual_outline.expect b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.textual_outline.expect
new file mode 100644
index 0000000..b972325
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.textual_outline.expect
@@ -0,0 +1,4 @@
+extension E on double show num {}
+expectIdentical(dynamic a, dynamic b) {}
+test(E e, int value) {}
+main() {}
diff --git a/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.weak.expect b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.weak.expect
new file mode 100644
index 0000000..61492c2
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.weak.expect
@@ -0,0 +1,17 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+extension E on core::double show-types core::num {
+}
+static method expectIdentical(dynamic a, dynamic b) → dynamic {
+  if(!core::identical(a, b)) {
+    throw "Expected '${a}' and '${b}' to be identical.";
+  }
+}
+static method test(self::E e, core::int value) → dynamic {
+  self::expectIdentical(e.{core::num::ceil}(){() → core::int}, value);
+}
+static method main() → dynamic {
+  self::test(3.14, 4);
+}
diff --git a/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.weak.outline.expect b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.weak.outline.expect
new file mode 100644
index 0000000..ddfdf1f
--- /dev/null
+++ b/pkg/front_end/testcases/extension_types/show_and_run_ceil.dart.weak.outline.expect
@@ -0,0 +1,12 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+extension E on core::double show-types core::num {
+}
+static method expectIdentical(dynamic a, dynamic b) → dynamic
+  ;
+static method test(self::E e, core::int value) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extension_types/simple_show_hide.dart.strong.expect b/pkg/front_end/testcases/extension_types/simple_show_hide.dart.strong.expect
index 18f6904..a7bbb4c 100644
--- a/pkg/front_end/testcases/extension_types/simple_show_hide.dart.strong.expect
+++ b/pkg/front_end/testcases/extension_types/simple_show_hide.dart.strong.expect
@@ -6,11 +6,6 @@
 //   e2.floor(); // Ok.
 //   ^^
 //
-// pkg/front_end/testcases/extension_types/simple_show_hide.dart:8:6: Error: The method 'ceil' isn't defined for the extension 'E1'.
-// Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
-//   e1.ceil(); // Ok.
-//      ^^^^
-//
 // pkg/front_end/testcases/extension_types/simple_show_hide.dart:10:6: Error: The getter 'isEven' isn't defined for the extension 'E1'.
 // Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
 //   e1.isEven; // Error.
@@ -21,11 +16,6 @@
 //   e2.ceil(); // Error.
 //      ^^^^
 //
-// pkg/front_end/testcases/extension_types/simple_show_hide.dart:17:6: Error: The method 'floor' isn't defined for the extension 'E2'.
-// Try correcting the name to the name of an existing method, or defining a method name 'floor'.
-//   e2.floor(); // Ok.
-//      ^^^^^
-//
 // pkg/front_end/testcases/extension_types/simple_show_hide.dart:18:6: Error: The getter 'isEven' isn't defined for the extension 'E2'.
 // Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
 //   e2.isEven; // Error.
@@ -41,16 +31,6 @@
 //   e3.isEven; // Error.
 //      ^^^^^^
 //
-// pkg/front_end/testcases/extension_types/simple_show_hide.dart:35:5: Error: The getter 'isEven' isn't defined for the extension 'MyInt'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
-//   m.isEven; // OK, a shown instance member.
-//     ^^^^^^
-//
-// pkg/front_end/testcases/extension_types/simple_show_hide.dart:36:5: Error: The method 'ceil' isn't defined for the extension 'MyInt'.
-// Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
-//   m.ceil(); // OK, a shown instance member.
-//     ^^^^
-//
 // pkg/front_end/testcases/extension_types/simple_show_hide.dart:38:5: Error: The method 'floor' isn't defined for the extension 'MyInt'.
 // Try correcting the name to the name of an existing method, or defining a method name 'floor'.
 //   m.floor(); // Error, hidden.
@@ -69,10 +49,7 @@
   get twice = self::MyInt|get#twice;
 }
 static method test1(self::E1 e1) → dynamic {
-  invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:8:6: Error: The method 'ceil' isn't defined for the extension 'E1'.
-Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
-  e1.ceil(); // Ok.
-     ^^^^" in e1{<unresolved>}.ceil();
+  e1.{core::num::ceil}(){() → core::int};
   invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:9:3: Error: Undefined name 'e2'.
   e2.floor(); // Ok.
   ^^"{dynamic}.floor();
@@ -86,10 +63,7 @@
 Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
   e2.ceil(); // Error.
      ^^^^" in e2{<unresolved>}.ceil();
-  invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:17:6: Error: The method 'floor' isn't defined for the extension 'E2'.
-Try correcting the name to the name of an existing method, or defining a method name 'floor'.
-  e2.floor(); // Ok.
-     ^^^^^" in e2{<unresolved>}.floor();
+  e2.{core::num::floor}(){() → core::int};
   invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:18:6: Error: The getter 'isEven' isn't defined for the extension 'E2'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
   e2.isEven; // Error.
@@ -110,14 +84,8 @@
 static method test() → dynamic {
   self::MyInt m = 42;
   self::MyInt|get#twice(m);
-  invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:35:5: Error: The getter 'isEven' isn't defined for the extension 'MyInt'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
-  m.isEven; // OK, a shown instance member.
-    ^^^^^^" in m{<unresolved>}.isEven;
-  invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:36:5: Error: The method 'ceil' isn't defined for the extension 'MyInt'.
-Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
-  m.ceil(); // OK, a shown instance member.
-    ^^^^" in m{<unresolved>}.ceil();
+  m.{core::int::isEven}{core::bool};
+  m.{core::num::ceil}(){() → core::int};
   m.{core::Object::toString}(){() → core::String};
   invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:38:5: Error: The method 'floor' isn't defined for the extension 'MyInt'.
 Try correcting the name to the name of an existing method, or defining a method name 'floor'.
diff --git a/pkg/front_end/testcases/extension_types/simple_show_hide.dart.weak.expect b/pkg/front_end/testcases/extension_types/simple_show_hide.dart.weak.expect
index 18f6904..a7bbb4c 100644
--- a/pkg/front_end/testcases/extension_types/simple_show_hide.dart.weak.expect
+++ b/pkg/front_end/testcases/extension_types/simple_show_hide.dart.weak.expect
@@ -6,11 +6,6 @@
 //   e2.floor(); // Ok.
 //   ^^
 //
-// pkg/front_end/testcases/extension_types/simple_show_hide.dart:8:6: Error: The method 'ceil' isn't defined for the extension 'E1'.
-// Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
-//   e1.ceil(); // Ok.
-//      ^^^^
-//
 // pkg/front_end/testcases/extension_types/simple_show_hide.dart:10:6: Error: The getter 'isEven' isn't defined for the extension 'E1'.
 // Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
 //   e1.isEven; // Error.
@@ -21,11 +16,6 @@
 //   e2.ceil(); // Error.
 //      ^^^^
 //
-// pkg/front_end/testcases/extension_types/simple_show_hide.dart:17:6: Error: The method 'floor' isn't defined for the extension 'E2'.
-// Try correcting the name to the name of an existing method, or defining a method name 'floor'.
-//   e2.floor(); // Ok.
-//      ^^^^^
-//
 // pkg/front_end/testcases/extension_types/simple_show_hide.dart:18:6: Error: The getter 'isEven' isn't defined for the extension 'E2'.
 // Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
 //   e2.isEven; // Error.
@@ -41,16 +31,6 @@
 //   e3.isEven; // Error.
 //      ^^^^^^
 //
-// pkg/front_end/testcases/extension_types/simple_show_hide.dart:35:5: Error: The getter 'isEven' isn't defined for the extension 'MyInt'.
-// Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
-//   m.isEven; // OK, a shown instance member.
-//     ^^^^^^
-//
-// pkg/front_end/testcases/extension_types/simple_show_hide.dart:36:5: Error: The method 'ceil' isn't defined for the extension 'MyInt'.
-// Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
-//   m.ceil(); // OK, a shown instance member.
-//     ^^^^
-//
 // pkg/front_end/testcases/extension_types/simple_show_hide.dart:38:5: Error: The method 'floor' isn't defined for the extension 'MyInt'.
 // Try correcting the name to the name of an existing method, or defining a method name 'floor'.
 //   m.floor(); // Error, hidden.
@@ -69,10 +49,7 @@
   get twice = self::MyInt|get#twice;
 }
 static method test1(self::E1 e1) → dynamic {
-  invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:8:6: Error: The method 'ceil' isn't defined for the extension 'E1'.
-Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
-  e1.ceil(); // Ok.
-     ^^^^" in e1{<unresolved>}.ceil();
+  e1.{core::num::ceil}(){() → core::int};
   invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:9:3: Error: Undefined name 'e2'.
   e2.floor(); // Ok.
   ^^"{dynamic}.floor();
@@ -86,10 +63,7 @@
 Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
   e2.ceil(); // Error.
      ^^^^" in e2{<unresolved>}.ceil();
-  invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:17:6: Error: The method 'floor' isn't defined for the extension 'E2'.
-Try correcting the name to the name of an existing method, or defining a method name 'floor'.
-  e2.floor(); // Ok.
-     ^^^^^" in e2{<unresolved>}.floor();
+  e2.{core::num::floor}(){() → core::int};
   invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:18:6: Error: The getter 'isEven' isn't defined for the extension 'E2'.
 Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
   e2.isEven; // Error.
@@ -110,14 +84,8 @@
 static method test() → dynamic {
   self::MyInt m = 42;
   self::MyInt|get#twice(m);
-  invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:35:5: Error: The getter 'isEven' isn't defined for the extension 'MyInt'.
-Try correcting the name to the name of an existing getter, or defining a getter or field named 'isEven'.
-  m.isEven; // OK, a shown instance member.
-    ^^^^^^" in m{<unresolved>}.isEven;
-  invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:36:5: Error: The method 'ceil' isn't defined for the extension 'MyInt'.
-Try correcting the name to the name of an existing method, or defining a method name 'ceil'.
-  m.ceil(); // OK, a shown instance member.
-    ^^^^" in m{<unresolved>}.ceil();
+  m.{core::int::isEven}{core::bool};
+  m.{core::num::ceil}(){() → core::int};
   m.{core::Object::toString}(){() → core::String};
   invalid-expression "pkg/front_end/testcases/extension_types/simple_show_hide.dart:38:5: Error: The method 'floor' isn't defined for the extension 'MyInt'.
 Try correcting the name to the name of an existing method, or defining a method name 'floor'.
diff --git a/pkg/front_end/testcases/outline.status b/pkg/front_end/testcases/outline.status
index 428a77b..a88beba 100644
--- a/pkg/front_end/testcases/outline.status
+++ b/pkg/front_end/testcases/outline.status
@@ -5,6 +5,7 @@
 const_functions/const_functions_const_factory: VerificationError
 constructor_tearoffs/lowering/invalid_redirect: VerificationError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
+extension_types/show_and_run_ceil: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized
 extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized
 extension_types/simple_method_resolution: ExpectationFileMismatchSerialized
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 47b80dd..90cc78d 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -12,6 +12,7 @@
 constructor_tearoffs/lowering/invalid_redirect: VerificationError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
+extension_types/show_and_run_ceil: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_method_resolution: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 3cd7ca1..c226f31 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -10,6 +10,7 @@
 constructor_tearoffs/lowering/invalid_redirect: VerificationError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
+extension_types/show_and_run_ceil: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_method_resolution: ExpectationFileMismatchSerialized # Expected.
diff --git a/pkg/front_end/testcases/textual_outline.status b/pkg/front_end/testcases/textual_outline.status
index ba00a26..65cb5bc 100644
--- a/pkg/front_end/testcases/textual_outline.status
+++ b/pkg/front_end/testcases/textual_outline.status
@@ -29,6 +29,7 @@
 dart2js/late_statics: FormatterCrash
 extension_types/basic_show: FormatterCrash
 extension_types/keyword_in_show_hide_element: FormatterCrash
+extension_types/show_and_run_ceil: FormatterCrash
 extension_types/show_hide_all_kinds: FormatterCrash
 extension_types/simple_getter_resolution: FormatterCrash
 extension_types/simple_method_resolution: FormatterCrash
diff --git a/pkg/front_end/testcases/weak.status b/pkg/front_end/testcases/weak.status
index 6af034c..84e72b9 100644
--- a/pkg/front_end/testcases/weak.status
+++ b/pkg/front_end/testcases/weak.status
@@ -15,6 +15,7 @@
 constructor_tearoffs/lowering/invalid_redirect: VerificationError
 extension_types/extension_on_nullable: ExpectationFileMismatchSerialized # Expected.
 extension_types/issue45775: ExpectationFileMismatchSerialized # Expected.
+extension_types/show_and_run_ceil: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_getter_resolution: ExpectationFileMismatchSerialized # Expected.
 extension_types/simple_method_resolution: ExpectationFileMismatchSerialized # Expected.
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index c02e4fb..7763cc7 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -327,7 +327,7 @@
 
 static void InvokeEventHandler(ServiceEvent* event) {
   ASSERT(!event->IsPause());  // For pause events, call Pause instead.
-  Service::HandleEvent(event);
+  Service::HandleEvent(event, /*enter_safepoint*/ false);
 }
 
 ErrorPtr Debugger::PauseInterrupted() {
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index e8b7bc9..e62c225 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -1020,7 +1020,7 @@
           if (!Isolate::IsSystemIsolate(isolate)) {
             ServiceEvent event(isolate, ServiceEvent::kGC);
             event.set_gc_stats(&stats_);
-            Service::HandleEvent(&event);
+            Service::HandleEvent(&event, /*enter_safepoint*/ false);
           }
         },
         /*at_safepoint=*/true);
diff --git a/runtime/vm/heap/safepoint.h b/runtime/vm/heap/safepoint.h
index 363b3f5..d002189 100644
--- a/runtime/vm/heap/safepoint.h
+++ b/runtime/vm/heap/safepoint.h
@@ -461,6 +461,37 @@
   DISALLOW_COPY_AND_ASSIGN(TransitionToVM);
 };
 
+// TransitionToNative is used to transition the safepoint state of a
+// thread from "running VM code" to "running native code"
+// and ensures that the state is reverted back to the initial state
+// when exiting the scope/frame.
+class TransitionToNative : public TransitionSafepointState {
+ public:
+  explicit TransitionToNative(Thread* T)
+      : TransitionSafepointState(T), execution_state_(T->execution_state()) {
+    ASSERT(T == Thread::Current());
+    ASSERT((execution_state_ == Thread::kThreadInVM) ||
+           (execution_state_ == Thread::kThreadInNative));
+    if (execution_state_ == Thread::kThreadInVM) {
+      T->set_execution_state(Thread::kThreadInNative);
+      T->EnterSafepoint();
+    }
+    ASSERT(T->execution_state() == Thread::kThreadInNative);
+  }
+
+  ~TransitionToNative() {
+    ASSERT(thread()->execution_state() == Thread::kThreadInNative);
+    if (execution_state_ == Thread::kThreadInVM) {
+      thread()->ExitSafepoint();
+      thread()->set_execution_state(Thread::kThreadInVM);
+    }
+  }
+
+ private:
+  uint32_t execution_state_;
+  DISALLOW_COPY_AND_ASSIGN(TransitionToNative);
+};
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_HEAP_SAFEPOINT_H_
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 46cf7f1..fb7e37c 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2116,7 +2116,7 @@
 #ifndef PRODUCT
   if (!Isolate::IsSystemIsolate(this) && Service::isolate_stream.enabled()) {
     ServiceEvent runnableEvent(this, ServiceEvent::kIsolateRunnable);
-    Service::HandleEvent(&runnableEvent);
+    Service::HandleEvent(&runnableEvent, /* enter_safepoint */ false);
   }
   GetRunnableLatencyMetric()->set_value(UptimeMicros());
 #endif  // !PRODUCT
@@ -2396,21 +2396,25 @@
     head = next;
   }
   head = reversed_head;
+
+  if (Service::profiler_stream.enabled() && !IsSystemIsolate(this)) {
+    SampleBlockListProcessor buffer(head);
+    StackZone zone(thread);
+    HandleScope handle_scope(thread);
+    Profile profile;
+    profile.Build(thread, nullptr, head);
+    ServiceEvent event(this, ServiceEvent::kCpuSamples);
+    event.set_cpu_profile(&profile);
+    Service::HandleEvent(&event);
+  }
+
   while (head != nullptr) {
-    if (Service::profiler_stream.enabled() && !IsSystemIsolate(this)) {
-      StackZone zone(thread);
-      HandleScope handle_scope(thread);
-      Profile profile;
-      profile.Build(thread, nullptr, head);
-      ServiceEvent event(this, ServiceEvent::kCpuSamples);
-      event.set_cpu_profile(&profile);
-      Service::HandleEvent(&event);
-    }
     SampleBlock* next = head->next_free_;
     head->next_free_ = nullptr;
     head->evictable_ = true;
     Profiler::sample_block_buffer()->FreeBlock(head);
     head = next;
+    thread->CheckForSafepoint();
   }
 }
 #endif  // !defined(PRODUCT)
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index f1394f7..aab5dec 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -24,6 +24,7 @@
 #include "vm/signal_handler.h"
 #include "vm/simulator.h"
 #include "vm/stack_frame.h"
+#include "vm/timeline.h"
 #include "vm/version.h"
 
 namespace dart {
@@ -243,6 +244,23 @@
                      Dart_Timeline_Event_Duration, 0, nullptr, nullptr);
 }
 
+ProcessedSampleBuffer* SampleBlockListProcessor::BuildProcessedSampleBuffer(
+    SampleFilter* filter,
+    ProcessedSampleBuffer* buffer) {
+  ASSERT(filter != NULL);
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+
+  if (buffer == nullptr) {
+    buffer = new (zone) ProcessedSampleBuffer();
+  }
+  while (head_ != nullptr) {
+    head_->BuildProcessedSampleBuffer(filter, buffer);
+    head_ = head_->next_free_;
+  }
+  return buffer;
+}
+
 ProcessedSampleBuffer* SampleBlockBuffer::BuildProcessedSampleBuffer(
     SampleFilter* filter,
     ProcessedSampleBuffer* buffer) {
@@ -1552,13 +1570,17 @@
   // Clear.
   code_objects_.Clear();
 
+  thread->CheckForSafepoint();
   // Add all found Code objects.
   {
+    TimelineBeginEndScope tl(Timeline::GetIsolateStream(),
+                             "CodeLookupTable::Build HeapIterationScope");
     HeapIterationScope iteration(thread);
     CodeLookupTableBuilder cltb(this);
     iteration.IterateVMIsolateObjects(&cltb);
     iteration.IterateOldObjects(&cltb);
   }
+  thread->CheckForSafepoint();
 
   // Sort by entry.
   code_objects_.Sort(CodeDescriptor::Compare);
@@ -1632,6 +1654,7 @@
 
   const intptr_t length = capacity();
   for (intptr_t i = 0; i < length; i++) {
+    thread->CheckForSafepoint();
     Sample* sample = At(i);
     if (sample->ignore_sample()) {
       // Bad sample.
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index 5455e7b..c68c792 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -767,6 +767,7 @@
   SampleBlock* next_free_ = nullptr;
 
  private:
+  friend class SampleBlockListProcessor;
   friend class SampleBlockBuffer;
   friend class Isolate;
 
@@ -873,6 +874,20 @@
   DISALLOW_COPY_AND_ASSIGN(SampleBlockBuffer);
 };
 
+class SampleBlockListProcessor : public ProcessedSampleBufferBuilder {
+ public:
+  explicit SampleBlockListProcessor(SampleBlock* head) : head_(head) {}
+
+  virtual ProcessedSampleBuffer* BuildProcessedSampleBuffer(
+      SampleFilter* filter,
+      ProcessedSampleBuffer* buffer = nullptr);
+
+ private:
+  SampleBlock* head_;
+
+  DISALLOW_COPY_AND_ASSIGN(SampleBlockListProcessor);
+};
+
 class AllocationSampleBuffer : public SampleBuffer {
  public:
   explicit AllocationSampleBuffer(intptr_t capacity = 60000);
diff --git a/runtime/vm/profiler_service.cc b/runtime/vm/profiler_service.cc
index 6836e9d..edaafe7 100644
--- a/runtime/vm/profiler_service.cc
+++ b/runtime/vm/profiler_service.cc
@@ -1013,6 +1013,7 @@
       RegisterLiveProfileCode(new ProfileCode(
           ProfileCode::kDartCode, code.PayloadStart(),
           code.PayloadStart() + code.Size(), code.compile_timestamp(), code));
+      thread_->CheckForSafepoint();
     }
 
     // Iterate over samples.
@@ -1047,6 +1048,7 @@
       }
 
       TickExitFrame(sample->vm_tag(), sample_index, sample);
+      thread_->CheckForSafepoint();
     }
     SanitizeMinMaxTimes();
   }
@@ -1095,18 +1097,21 @@
       ProfileCode* code = live_table->At(i);
       ASSERT(code != NULL);
       code->SetFunctionAndName(function_table);
+      thread_->CheckForSafepoint();
     }
 
     for (intptr_t i = 0; i < dead_table->length(); i++) {
       ProfileCode* code = dead_table->At(i);
       ASSERT(code != NULL);
       code->SetFunctionAndName(function_table);
+      thread_->CheckForSafepoint();
     }
 
     for (intptr_t i = 0; i < tag_table->length(); i++) {
       ProfileCode* code = tag_table->At(i);
       ASSERT(code != NULL);
       code->SetFunctionAndName(function_table);
+      thread_->CheckForSafepoint();
     }
   }
 
@@ -1725,6 +1730,7 @@
 
 void Profile::PrintProfileJSON(JSONObject* obj, bool include_code_samples) {
   ScopeTimer sw("Profile::PrintProfileJSON", FLAG_trace_profiler);
+  Thread* thread = Thread::Current();
   obj->AddProperty("type", "CpuSamples");
   PrintHeaderJSON(obj);
   if (include_code_samples) {
@@ -1733,16 +1739,19 @@
       ProfileCode* code = live_code_->At(i);
       ASSERT(code != NULL);
       code->PrintToJSONArray(&codes);
+      thread->CheckForSafepoint();
     }
     for (intptr_t i = 0; i < dead_code_->length(); i++) {
       ProfileCode* code = dead_code_->At(i);
       ASSERT(code != NULL);
       code->PrintToJSONArray(&codes);
+      thread->CheckForSafepoint();
     }
     for (intptr_t i = 0; i < tag_code_->length(); i++) {
       ProfileCode* code = tag_code_->At(i);
       ASSERT(code != NULL);
       code->PrintToJSONArray(&codes);
+      thread->CheckForSafepoint();
     }
   }
 
@@ -1752,9 +1761,11 @@
       ProfileFunction* function = functions_->At(i);
       ASSERT(function != NULL);
       function->PrintToJSONArray(&functions);
+      thread->CheckForSafepoint();
     }
   }
   PrintSamplesJSON(obj, include_code_samples);
+  thread->CheckForSafepoint();
 }
 
 void ProfilerService::PrintJSONImpl(Thread* thread,
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 9c5acd8..1cc5a5c 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1106,7 +1106,7 @@
   }
 }
 
-void Service::HandleEvent(ServiceEvent* event) {
+void Service::HandleEvent(ServiceEvent* event, bool enter_safepoint) {
   if (event->stream_info() != NULL && !event->stream_info()->enabled()) {
     if (FLAG_warn_on_pause_with_no_debugger && event->IsPause()) {
       // If we are about to pause a running program which has no
@@ -1133,7 +1133,8 @@
     params.AddProperty("streamId", stream_id);
     params.AddProperty("event", event);
   }
-  PostEvent(event->isolate(), stream_id, event->KindAsCString(), &js);
+  PostEvent(event->isolate(), stream_id, event->KindAsCString(), &js,
+            enter_safepoint);
 
   // Post event to the native Service Stream handlers if set.
   if (event->stream_info() != nullptr &&
@@ -1147,13 +1148,28 @@
 void Service::PostEvent(Isolate* isolate,
                         const char* stream_id,
                         const char* kind,
-                        JSONStream* event) {
-  ASSERT(stream_id != NULL);
-  ASSERT(kind != NULL);
-  ASSERT(event != NULL);
+                        JSONStream* event,
+                        bool enter_safepoint) {
+  if (enter_safepoint) {
+    // Enter a safepoint so we don't block the mutator while processing
+    // large events.
+    TransitionToNative transition(Thread::Current());
+    PostEventImpl(isolate, stream_id, kind, event);
+    return;
+  }
+  PostEventImpl(isolate, stream_id, kind, event);
+}
+
+void Service::PostEventImpl(Isolate* isolate,
+                            const char* stream_id,
+                            const char* kind,
+                            JSONStream* event) {
+  ASSERT(stream_id != nullptr);
+  ASSERT(kind != nullptr);
+  ASSERT(event != nullptr);
 
   if (FLAG_trace_service) {
-    if (isolate != NULL) {
+    if (isolate != nullptr) {
       OS::PrintErr(
           "vm-service: Pushing ServiceEvent(isolate='%s', "
           "isolateId='" ISOLATE_SERVICE_ID_FORMAT_STRING
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index 38583b1..6d32257 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -98,7 +98,7 @@
   // Handles a message which is directed to a particular isolate.
   static ErrorPtr HandleIsolateMessage(Isolate* isolate, const Array& message);
 
-  static void HandleEvent(ServiceEvent* event);
+  static void HandleEvent(ServiceEvent* event, bool enter_safepoint = true);
 
   static void RegisterIsolateEmbedderCallback(
       const char* name,
@@ -231,7 +231,13 @@
   static void PostEvent(Isolate* isolate,
                         const char* stream_id,
                         const char* kind,
-                        JSONStream* event);
+                        JSONStream* event,
+                        bool enter_safepoint);
+
+  static void PostEventImpl(Isolate* isolate,
+                            const char* stream_id,
+                            const char* kind,
+                            JSONStream* event);
 
   static ErrorPtr MaybePause(Isolate* isolate, const Error& error);
 
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index 7b0ed2c..ab0d62a 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -1514,7 +1514,7 @@
   if (Service::timeline_stream.enabled()) {
     ServiceEvent service_event(ServiceEvent::kTimelineEvents);
     service_event.set_timeline_event_block(this);
-    Service::HandleEvent(&service_event);
+    Service::HandleEvent(&service_event, /* enter_safepoint */ false);
   }
 #endif
 }
diff --git a/tools/VERSION b/tools/VERSION
index b5587e5..7671f3f 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 115
+PRERELEASE 116
 PRERELEASE_PATCH 0
\ No newline at end of file