Version 2.10.0-44.0.dev
Merge commit '1cec77f0a60b0c8e3df18085893e6ecfdbceb5b4' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index 84ad8a2..37a656d 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -587,7 +587,7 @@
/// The [path] must be absolute and normalized.
FileResult getFileSync(String path) {
_throwIfNotAbsolutePath(path);
- FileState file = _fileTracker.verifyApiSignature(path);
+ FileState file = _fileTracker.getFile(path);
return FileResultImpl(
_currentSession, path, file.uri, file.lineInfo, file.isPart);
}
@@ -819,7 +819,7 @@
Future<SourceKind> getSourceKind(String path) async {
_throwIfNotAbsolutePath(path);
if (AnalysisEngine.isDartFileName(path)) {
- FileState file = _fileTracker.verifyApiSignature(path);
+ FileState file = _fileTracker.getFile(path);
return file.isPart ? SourceKind.PART : SourceKind.LIBRARY;
}
return null;
@@ -907,7 +907,7 @@
/// resolved unit).
ParsedUnitResult parseFileSync(String path) {
_throwIfNotAbsolutePath(path);
- FileState file = _fileTracker.verifyApiSignature(path);
+ FileState file = _fileTracker.getFile(path);
RecordingErrorListener listener = RecordingErrorListener();
CompilationUnit unit = file.parse(listener);
return ParsedUnitResultImpl(currentSession, file.path, file.uri,
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart b/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
index abd28a5..29fe48e 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_tracker.dart
@@ -139,6 +139,18 @@
_pendingFiles.remove(path);
}
+ /// Return the [FileState] suitable only when the file is used by itself.
+ /// If the file is in the set of changed files, it is refreshed first.
+ /// If the file is not in the set of changed files, it is not refreshed.
+ FileState getFile(String path) {
+ // Read any files that we were told were changed.
+ // But don't read the requested file explicitly.
+ // Read it only if it is in this set of changed files.
+ while (verifyChangedFilesIfNeeded()) {}
+
+ return _fsState.getFileForPath(path);
+ }
+
/// Returns a boolean indicating whether the given [path] points to a file
/// that requires analysis.
bool isFilePending(String path) {
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 2f46907..2522b77 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -1275,6 +1275,43 @@
expect(files, isNot(contains(c)));
}
+ test_getFileSync_changedFile() async {
+ var a = convertPath('/test/lib/a.dart');
+ var b = convertPath('/test/lib/b.dart');
+
+ newFile(a, content: '');
+ newFile(b, content: r'''
+import 'a.dart';
+
+void f(A a) {}
+''');
+
+ // Ensure that [a.dart] library cycle is loaded.
+ // So, `a.dart` is in the library context.
+ await driver.getResult(a);
+
+ // Update the file, changing its API signature.
+ // Note that we don't call `changeFile`.
+ newFile(a, content: 'class A {}\n');
+
+ // Get the file.
+ // We have not called `changeFile(a)`, so we should not read the file.
+ // Moreover, doing this will create a new library cycle [a.dart].
+ // Library cycles are compared by their identity, so we would try to
+ // reload linked summary for [a.dart], and crash.
+ expect(driver.getFileSync(a).lineInfo.lineCount, 1);
+
+ // We have not read `a.dart`, so `A` is still not declared.
+ expect((await driver.getResult(b)).errors, isNotEmpty);
+
+ // Notify the driver that the file was changed.
+ driver.changeFile(a);
+
+ // So, `class A {}` is declared now.
+ expect(driver.getFileSync(a).lineInfo.lineCount, 2);
+ expect((await driver.getResult(b)).errors, isEmpty);
+ }
+
test_getFileSync_library() async {
var path = convertPath('/test/lib/a.dart');
newFile(path);
@@ -1825,6 +1862,43 @@
expect(result1.unit, isNotNull);
}
+ test_getSourceKind_changedFile() async {
+ var a = convertPath('/test/lib/a.dart');
+ var b = convertPath('/test/lib/b.dart');
+
+ newFile(a, content: 'part of lib;');
+ newFile(b, content: r'''
+import 'a.dart';
+
+void f(A a) {}
+''');
+
+ // Ensure that [a.dart] library cycle is loaded.
+ // So, `a.dart` is in the library context.
+ await driver.getResult(a);
+
+ // Update the file, changing its API signature.
+ // Note that we don't call `changeFile`.
+ newFile(a, content: 'class A {}');
+
+ // Get the kind of the file.
+ // We have not called `changeFile(a)`, so we should not read the file.
+ // Moreover, doing this will create a new library cycle [a.dart].
+ // Library cycles are compared by their identity, so we would try to
+ // reload linked summary for [a.dart], and crash.
+ expect(await driver.getSourceKind(a), SourceKind.PART);
+
+ // We have not read `a.dart`, so `A` is still not declared.
+ expect((await driver.getResult(b)).errors, isNotEmpty);
+
+ // Notify the driver that the file was changed.
+ driver.changeFile(a);
+
+ // So, `class A {}` is declared now.
+ expect(await driver.getSourceKind(a), SourceKind.LIBRARY);
+ expect((await driver.getResult(b)).errors, isEmpty);
+ }
+
test_getSourceKind_changeFile() async {
var path = convertPath('/test/lib/test.dart');
expect(await driver.getSourceKind(path), SourceKind.LIBRARY);
@@ -2164,6 +2238,55 @@
expect(error.errorCode, CompileTimeErrorCode.MISSING_DART_LIBRARY);
}
+ test_parseFile_changedFile() async {
+ var a = convertPath('/test/lib/a.dart');
+ var b = convertPath('/test/lib/b.dart');
+
+ newFile(a, content: '');
+ newFile(b, content: r'''
+import 'a.dart';
+
+void f(A a) {}
+''');
+
+ // Ensure that [a.dart] library cycle is loaded.
+ // So, `a.dart` is in the library context.
+ await driver.getResult(a);
+
+ // Update the file, changing its API signature.
+ // Note that we don't call `changeFile`.
+ newFile(a, content: 'class A {}');
+
+ // Parse the file.
+ // We have not called `changeFile(a)`, so we should not read the file.
+ // Moreover, doing this will create a new library cycle [a.dart].
+ // Library cycles are compared by their identity, so we would try to
+ // reload linked summary for [a.dart], and crash.
+ {
+ var parseResult = await driver.parseFile(a);
+ expect(parseResult.unit.declarations, isEmpty);
+ }
+
+ // We have not read `a.dart`, so `A` is still not declared.
+ {
+ var bResult = await driver.getResult(b);
+ expect(bResult.errors, isNotEmpty);
+ }
+
+ // Notify the driver that the file was changed.
+ driver.changeFile(a);
+
+ // So, `class A {}` is declared now.
+ {
+ var parseResult = driver.parseFileSync(a);
+ expect(parseResult.unit.declarations, hasLength(1));
+ }
+ {
+ var bResult = await driver.getResult(b);
+ expect(bResult.errors, isEmpty);
+ }
+ }
+
test_parseFile_notAbsolutePath() async {
expect(() async {
await driver.parseFile('not_absolute.dart');
@@ -2179,21 +2302,53 @@
expect(driver.knownFiles, contains(p));
}
- test_parseFile_shouldRefresh() async {
- var p = convertPath('/test/bin/a.dart');
+ test_parseFileSync_changedFile() async {
+ var a = convertPath('/test/lib/a.dart');
+ var b = convertPath('/test/lib/b.dart');
- newFile(p, content: 'class A {}');
- driver.addFile(p);
+ newFile(a, content: '');
+ newFile(b, content: r'''
+import 'a.dart';
- // Get the result, so force the file reading.
- await driver.getResult(p);
+void f(A a) {}
+''');
- // Update the file.
- newFile(p, content: 'class A2 {}');
+ // Ensure that [a.dart] library cycle is loaded.
+ // So, `a.dart` is in the library context.
+ await driver.getResult(a);
- ParsedUnitResult parseResult = await driver.parseFile(p);
- var clazz = parseResult.unit.declarations[0] as ClassDeclaration;
- expect(clazz.name.name, 'A2');
+ // Update the file, changing its API signature.
+ // Note that we don't call `changeFile`.
+ newFile(a, content: 'class A {}');
+
+ // Parse the file.
+ // We have not called `changeFile(a)`, so we should not read the file.
+ // Moreover, doing this will create a new library cycle [a.dart].
+ // Library cycles are compared by their identity, so we would try to
+ // reload linked summary for [a.dart], and crash.
+ {
+ var parseResult = driver.parseFileSync(a);
+ expect(parseResult.unit.declarations, isEmpty);
+ }
+
+ // We have not read `a.dart`, so `A` is still not declared.
+ {
+ var bResult = await driver.getResult(b);
+ expect(bResult.errors, isNotEmpty);
+ }
+
+ // Notify the driver that the file was changed.
+ driver.changeFile(a);
+
+ // So, `class A {}` is declared now.
+ {
+ var parseResult = driver.parseFileSync(a);
+ expect(parseResult.unit.declarations, hasLength(1));
+ }
+ {
+ var bResult = await driver.getResult(b);
+ expect(bResult.errors, isEmpty);
+ }
}
test_parseFileSync_languageVersion() async {
@@ -2236,23 +2391,6 @@
expect(driver.knownFiles, contains(p));
}
- test_parseFileSync_shouldRefresh() async {
- var p = convertPath('/test/bin/a.dart');
-
- newFile(p, content: 'class A {}');
- driver.addFile(p);
-
- // Get the result, so force the file reading.
- await driver.getResult(p);
-
- // Update the file.
- newFile(p, content: 'class A2 {}');
-
- ParsedUnitResult parseResult = driver.parseFileSync(p);
- var clazz = parseResult.unit.declarations[0] as ClassDeclaration;
- expect(clazz.name.name, 'A2');
- }
-
test_part_getErrors_afterLibrary() async {
var a = convertPath('/test/lib/a.dart');
var b = convertPath('/test/lib/b.dart');
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
index 086d55aa..7afc77e 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_resolution.dart
@@ -1201,18 +1201,23 @@
type = type.withoutNullability;
if (type is InterfaceType) {
return [type.element];
- } else if (type is DynamicType) {
- return [commonElements.objectClass];
+ } else if (type is NeverType ||
+ type is DynamicType ||
+ type is VoidType ||
+ type is AnyType ||
+ type is ErasedType) {
+ // No classes implied.
+ return const [];
} else if (type is FunctionType) {
// TODO(johnniwinther): Include only potential function type subtypes.
return [commonElements.functionClass];
- } else if (type is VoidType) {
- // No classes implied.
} else if (type is FunctionTypeVariable) {
return impliedClasses(type.bound);
} else if (type is FutureOrType) {
- return [commonElements.futureClass]
- ..addAll(impliedClasses(type.typeArgument));
+ return [
+ commonElements.futureClass,
+ ...impliedClasses(type.typeArgument),
+ ];
} else if (type is TypeVariableType) {
// TODO(johnniwinther): Can we do better?
return impliedClasses(
diff --git a/runtime/tests/vm/dart/incompatible_loading_unit_test.dart b/runtime/tests/vm/dart/incompatible_loading_unit_test.dart
index 9adf6e8..73a7a6d 100644
--- a/runtime/tests/vm/dart/incompatible_loading_unit_test.dart
+++ b/runtime/tests/vm/dart/incompatible_loading_unit_test.dart
@@ -36,7 +36,7 @@
var uris = <String>[];
for (var uri in unit['libraries']) {
if (uri.startsWith("dart:")) continue;
- uris.add(Uri.file(uri).pathSegments.last);
+ uris.add(Uri.parse(uri).pathSegments.last);
}
uris.sort((a, b) => a.compareTo(b));
units.add(uris);
diff --git a/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart b/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart
index 9adf6e8..73a7a6d 100644
--- a/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart
+++ b/runtime/tests/vm/dart_2/incompatible_loading_unit_test.dart
@@ -36,7 +36,7 @@
var uris = <String>[];
for (var uri in unit['libraries']) {
if (uri.startsWith("dart:")) continue;
- uris.add(Uri.file(uri).pathSegments.last);
+ uris.add(Uri.parse(uri).pathSegments.last);
}
uris.sort((a, b) => a.compareTo(b));
units.add(uris);
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 6e327e2..95ae9bb 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1426,20 +1426,18 @@
group->RunWithLockedGroup([&]() {
// Ensure no other old space GC tasks are running and "occupy" the old
// space.
+ SafepointOperationScope safepoint_scope(thread);
{
auto old_space = group->heap()->old_space();
MonitorLocker ml(old_space->tasks_lock());
while (old_space->tasks() > 0) {
- ml.WaitWithSafepointCheck(thread);
+ ml.Wait();
}
old_space->set_tasks(1);
}
// Merge the heap from [spawning_group] to [group].
- {
- SafepointOperationScope safepoint_scope(thread);
- group->heap()->MergeFrom(isolate->group()->heap());
- }
+ group->heap()->MergeFrom(isolate->group()->heap());
spawning_group->UnregisterIsolate(isolate);
const bool shutdown_group =
diff --git a/runtime/vm/heap/heap.cc b/runtime/vm/heap/heap.cc
index 7e81415..170f52c 100644
--- a/runtime/vm/heap/heap.cc
+++ b/runtime/vm/heap/heap.cc
@@ -65,8 +65,6 @@
barrier_(),
barrier_done_(),
read_only_(false),
- gc_new_space_in_progress_(false),
- gc_old_space_in_progress_(false),
last_gc_was_old_space_(false),
assume_scavenge_will_fail_(false),
gc_on_nth_allocation_(kNoForcedGarbageCollection) {
@@ -237,6 +235,8 @@
heap_(isolate()->heap()),
old_space_(heap_->old_space()),
writable_(writable) {
+ isolate()->safepoint_handler()->SafepointThreads(thread);
+
{
// It's not safe to iterate over old space when concurrent marking or
// sweeping is in progress, or another thread is iterating the heap, so wait
@@ -255,7 +255,7 @@
ml.Enter();
}
while (old_space_->tasks() > 0) {
- ml.WaitWithSafepointCheck(thread);
+ ml.Wait();
}
}
#if defined(DEBUG)
@@ -265,8 +265,6 @@
old_space_->set_tasks(1);
}
- isolate()->safepoint_handler()->SafepointThreads(thread);
-
if (writable_) {
heap_->WriteProtectCode(false);
}
@@ -277,16 +275,18 @@
heap_->WriteProtectCode(true);
}
- isolate()->safepoint_handler()->ResumeThreads(thread());
-
- MonitorLocker ml(old_space_->tasks_lock());
+ {
+ MonitorLocker ml(old_space_->tasks_lock());
#if defined(DEBUG)
- ASSERT(old_space_->iterating_thread_ == thread());
- old_space_->iterating_thread_ = NULL;
+ ASSERT(old_space_->iterating_thread_ == thread());
+ old_space_->iterating_thread_ = NULL;
#endif
- ASSERT(old_space_->tasks() == 1);
- old_space_->set_tasks(0);
- ml.NotifyAll();
+ ASSERT(old_space_->tasks() == 1);
+ old_space_->set_tasks(0);
+ ml.NotifyAll();
+ }
+
+ isolate()->safepoint_handler()->ResumeThreads(thread());
}
void HeapIterationScope::IterateObjects(ObjectVisitor* visitor) const {
@@ -360,57 +360,14 @@
return raw_obj;
}
-bool Heap::BeginNewSpaceGC(Thread* thread) {
- MonitorLocker ml(&gc_in_progress_monitor_);
- bool start_gc_on_thread = true;
- while (gc_new_space_in_progress_ || gc_old_space_in_progress_) {
- start_gc_on_thread = !gc_new_space_in_progress_;
- ml.WaitWithSafepointCheck(thread);
- }
- if (start_gc_on_thread) {
- gc_new_space_in_progress_ = true;
- return true;
- }
- return false;
-}
-
-void Heap::EndNewSpaceGC() {
- MonitorLocker ml(&gc_in_progress_monitor_);
- ASSERT(gc_new_space_in_progress_);
- gc_new_space_in_progress_ = false;
- last_gc_was_old_space_ = false;
- ml.NotifyAll();
-}
-
-bool Heap::BeginOldSpaceGC(Thread* thread) {
- MonitorLocker ml(&gc_in_progress_monitor_);
- bool start_gc_on_thread = true;
- while (gc_new_space_in_progress_ || gc_old_space_in_progress_) {
- start_gc_on_thread = !gc_old_space_in_progress_;
- ml.WaitWithSafepointCheck(thread);
- }
- if (start_gc_on_thread) {
- gc_old_space_in_progress_ = true;
- return true;
- }
- return false;
-}
-
-void Heap::EndOldSpaceGC() {
- MonitorLocker ml(&gc_in_progress_monitor_);
- ASSERT(gc_old_space_in_progress_);
- gc_old_space_in_progress_ = false;
- last_gc_was_old_space_ = true;
- assume_scavenge_will_fail_ = false;
- ml.NotifyAll();
-}
-
void Heap::HintFreed(intptr_t size) {
old_space_.HintFreed(size);
}
void Heap::NotifyIdle(int64_t deadline) {
Thread* thread = Thread::Current();
+ SafepointOperationScope safepoint_operation(thread);
+
// Check if we want to collect new-space first, because if we want to collect
// both new-space and old-space, the new-space collection should run first
// to shrink the root set (make old-space GC faster) and avoid
@@ -475,7 +432,8 @@
// visiting pointers.
return;
}
- if (BeginNewSpaceGC(thread)) {
+ {
+ SafepointOperationScope safepoint_operation(thread);
RecordBeforeGC(kScavenge, reason);
VMTagScope tagScope(thread, reason == kIdle ? VMTag::kGCIdleTagId
: VMTag::kGCNewSpaceTagId);
@@ -484,7 +442,7 @@
RecordAfterGC(kScavenge);
PrintStats();
NOT_IN_PRODUCT(PrintStatsToTimeline(&tbes, reason));
- EndNewSpaceGC();
+ last_gc_was_old_space_ = false;
}
}
@@ -498,7 +456,8 @@
// visiting pointers.
return;
}
- if (BeginNewSpaceGC(thread)) {
+ {
+ SafepointOperationScope safepoint_operation(thread);
RecordBeforeGC(kScavenge, reason);
{
VMTagScope tagScope(thread, reason == kIdle ? VMTag::kGCIdleTagId
@@ -508,7 +467,7 @@
RecordAfterGC(kScavenge);
PrintStats();
NOT_IN_PRODUCT(PrintStatsToTimeline(&tbes, reason));
- EndNewSpaceGC();
+ last_gc_was_old_space_ = false;
}
if (reason == kNewSpace) {
if (old_space_.ReachedHardThreshold()) {
@@ -537,11 +496,14 @@
// visiting pointers.
return;
}
- if (BeginOldSpaceGC(thread)) {
- thread->isolate_group()->ForEachIsolate([&](Isolate* isolate) {
- // Discard regexp backtracking stacks to further reduce memory usage.
- isolate->CacheRegexpBacktrackStack(nullptr);
- });
+ {
+ SafepointOperationScope safepoint_operation(thread);
+ thread->isolate_group()->ForEachIsolate(
+ [&](Isolate* isolate) {
+ // Discard regexp backtracking stacks to further reduce memory usage.
+ isolate->CacheRegexpBacktrackStack(nullptr);
+ },
+ /*at_safepoint=*/true);
RecordBeforeGC(type, reason);
VMTagScope tagScope(thread, reason == kIdle ? VMTag::kGCIdleTagId
@@ -553,11 +515,14 @@
NOT_IN_PRODUCT(PrintStatsToTimeline(&tbes, reason));
// Some Code objects may have been collected so invalidate handler cache.
- thread->isolate_group()->ForEachIsolate([&](Isolate* isolate) {
- isolate->handler_info_cache()->Clear();
- isolate->catch_entry_moves_cache()->Clear();
- });
- EndOldSpaceGC();
+ thread->isolate_group()->ForEachIsolate(
+ [&](Isolate* isolate) {
+ isolate->handler_info_cache()->Clear();
+ isolate->catch_entry_moves_cache()->Clear();
+ },
+ /*at_safepoint=*/true);
+ last_gc_was_old_space_ = true;
+ assume_scavenge_will_fail_ = false;
}
}
@@ -637,11 +602,8 @@
}
void Heap::StartConcurrentMarking(Thread* thread) {
- if (BeginOldSpaceGC(thread)) {
- TIMELINE_FUNCTION_GC_DURATION_BASIC(thread, "StartConcurrentMarking");
- old_space_.CollectGarbage(/*compact=*/false, /*finalize=*/false);
- EndOldSpaceGC();
- }
+ TIMELINE_FUNCTION_GC_DURATION_BASIC(thread, "StartConcurrentMarking");
+ old_space_.CollectGarbage(/*compact=*/false, /*finalize=*/false);
}
void Heap::CheckFinishConcurrentMarking(Thread* thread) {
@@ -751,8 +713,6 @@
}
void Heap::MergeFrom(Heap* donor) {
- ASSERT(!donor->gc_new_space_in_progress_);
- ASSERT(!donor->gc_old_space_in_progress_);
ASSERT(!donor->read_only_);
ASSERT(donor->old_space()->tasks() == 0);
@@ -1021,9 +981,6 @@
#endif // PRODUCT
void Heap::RecordBeforeGC(GCType type, GCReason reason) {
- ASSERT((type == kScavenge && gc_new_space_in_progress_) ||
- (type == kMarkSweep && gc_old_space_in_progress_) ||
- (type == kMarkCompact && gc_old_space_in_progress_));
stats_.num_++;
stats_.type_ = type;
stats_.reason_ = reason;
@@ -1048,9 +1005,6 @@
}
stats_.after_.new_ = new_space_.GetCurrentUsage();
stats_.after_.old_ = old_space_.GetCurrentUsage();
- ASSERT((type == kScavenge && gc_new_space_in_progress_) ||
- (type == kMarkSweep && gc_old_space_in_progress_) ||
- (type == kMarkCompact && gc_old_space_in_progress_));
#ifndef PRODUCT
// For now we'll emit the same GC events on all isolates.
if (Service::gc_stream.enabled()) {
diff --git a/runtime/vm/heap/heap.h b/runtime/vm/heap/heap.h
index fa9d733..8982ba3 100644
--- a/runtime/vm/heap/heap.h
+++ b/runtime/vm/heap/heap.h
@@ -383,12 +383,6 @@
void PrintStats();
void PrintStatsToTimeline(TimelineEventScope* event, GCReason reason);
- // Updates gc in progress flags.
- bool BeginNewSpaceGC(Thread* thread);
- void EndNewSpaceGC();
- bool BeginOldSpaceGC(Thread* thread);
- void EndOldSpaceGC();
-
void AddRegionsToObjectSet(ObjectSet* set) const;
// Trigger major GC if 'gc_on_nth_allocation_' is set.
@@ -412,10 +406,6 @@
// This heap is in read-only mode: No allocation is allowed.
bool read_only_;
- // GC on the heap is in progress.
- Monitor gc_in_progress_monitor_;
- bool gc_new_space_in_progress_;
- bool gc_old_space_in_progress_;
bool last_gc_was_old_space_;
bool assume_scavenge_will_fail_;
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index c0a2597..e0f10cb 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -1030,9 +1030,10 @@
}
Thread* thread = Thread::Current();
+ const int64_t pre_safe_point = OS::GetCurrentMonotonicMicros();
+ SafepointOperationScope safepoint_scope(thread);
const int64_t pre_wait_for_sweepers = OS::GetCurrentMonotonicMicros();
-
// Wait for pending tasks to complete and then account for the driver task.
Phase waited_for;
{
@@ -1045,15 +1046,15 @@
}
while (tasks() > 0) {
- locker.WaitWithSafepointCheck(thread);
+ locker.Wait();
}
ASSERT(phase() == kAwaitingFinalization || phase() == kDone);
set_tasks(1);
}
- const int64_t pre_safe_point = OS::GetCurrentMonotonicMicros();
if (FLAG_verbose_gc) {
- const int64_t wait = pre_safe_point - pre_wait_for_sweepers;
+ const int64_t wait =
+ OS::GetCurrentMonotonicMicros() - pre_wait_for_sweepers;
if (waited_for == kMarking) {
THR_Print("Waited %" Pd64 " us for concurrent marking to finish.\n",
wait);
@@ -1068,9 +1069,8 @@
// to ensure that if two threads are racing to collect at the same time the
// loser skips collection and goes straight to allocation.
{
- SafepointOperationScope safepoint_scope(thread);
- CollectGarbageAtSafepoint(compact, finalize, pre_wait_for_sweepers,
- pre_safe_point);
+ CollectGarbageHelper(compact, finalize, pre_wait_for_sweepers,
+ pre_safe_point);
}
// Done, reset the task count.
@@ -1081,10 +1081,10 @@
}
}
-void PageSpace::CollectGarbageAtSafepoint(bool compact,
- bool finalize,
- int64_t pre_wait_for_sweepers,
- int64_t pre_safe_point) {
+void PageSpace::CollectGarbageHelper(bool compact,
+ bool finalize,
+ int64_t pre_wait_for_sweepers,
+ int64_t pre_safe_point) {
Thread* thread = Thread::Current();
ASSERT(thread->IsAtSafepoint());
auto isolate_group = heap_->isolate_group();
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index ef5badf..83c5488 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -538,10 +538,10 @@
void FreeLargePage(OldPage* page, OldPage* previous_page);
void FreePages(OldPage* pages);
- void CollectGarbageAtSafepoint(bool compact,
- bool finalize,
- int64_t pre_wait_for_sweepers,
- int64_t pre_safe_point);
+ void CollectGarbageHelper(bool compact,
+ bool finalize,
+ int64_t pre_wait_for_sweepers,
+ int64_t pre_safe_point);
void SweepLarge();
void Sweep();
void ConcurrentSweep(IsolateGroup* isolate_group);
diff --git a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
index 8eaad60..4f182d0 100644
--- a/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/regexp_helper.dart
@@ -208,7 +208,7 @@
return out;
}
- String namedGroup(String name) {
+ String? namedGroup(String name) {
var groups = JS('Object|Null', '#.groups', _match);
if (groups != null) {
var result = JS('String|Null', '#[#]', groups, name);
diff --git a/tests/dart2js/29130_test.dart b/tests/dart2js/29130_test.dart
index 4426f26..6766e0c 100644
--- a/tests/dart2js/29130_test.dart
+++ b/tests/dart2js/29130_test.dart
@@ -20,7 +20,11 @@
// interface scenario: we shouldn't trace B
abstract class B implements A {
- factory B() => null as dynamic;
+ factory B() => DummyB();
+}
+
+class DummyB implements B {
+ call() {}
}
// mixin scenario: we should trace C, but we should trace _C
diff --git a/tools/VERSION b/tools/VERSION
index 339772b..bec7b97 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 43
+PRERELEASE 44
PRERELEASE_PATCH 0
\ No newline at end of file