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