Skip to content

Commit 55c93c7

Browse files
author
Dart CI
committed
Version 2.17.0-87.0.dev
Merge commit '72eb59f32af1bc9e74c1e3fe1190214dbf4aaef0' into 'dev'
2 parents 2902fe3 + 72eb59f commit 55c93c7

File tree

7 files changed

+78
-35
lines changed

7 files changed

+78
-35
lines changed

runtime/platform/utils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class Utils {
8484
}
8585

8686
template <typename T>
87-
static inline T RoundDown(T x, intptr_t n) {
87+
static constexpr inline T RoundDown(T x, intptr_t n) {
8888
ASSERT(IsPowerOfTwo(n));
8989
return (x & -n);
9090
}
@@ -95,7 +95,7 @@ class Utils {
9595
}
9696

9797
template <typename T>
98-
static inline T RoundUp(T x, intptr_t n) {
98+
static constexpr inline T RoundUp(T x, intptr_t n) {
9999
return RoundDown(x + n - 1, n);
100100
}
101101

runtime/vm/compiler/write_barrier_elimination.cc

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ class WriteBarrierElimination : public ValueObject {
114114

115115
// Bitvector with all non-Array-allocation instructions set. Used to
116116
// un-mark Array allocations as usable.
117-
BitVector* array_allocations_mask_;
117+
BitVector* large_array_allocations_mask_;
118118

119119
// Bitvectors for each block of which allocations are new or remembered
120120
// at the start (after Phis).
@@ -189,16 +189,29 @@ void WriteBarrierElimination::SaveResults() {
189189
}
190190
}
191191

192+
static bool IsCreateLargeArray(Definition* defn) {
193+
if (auto create_array = defn->AsCreateArray()) {
194+
static_assert(!Array::UseCardMarkingForAllocation(
195+
Array::kMaxLengthForWriteBarrierElimination),
196+
"Invariant restoration code does not handle card marking.");
197+
// Note: IsUsable would reject CreateArray instructions with non-constant
198+
// number of elements.
199+
return create_array->GetConstantNumElements() >
200+
Array::kMaxLengthForWriteBarrierElimination;
201+
}
202+
return false;
203+
}
204+
192205
void WriteBarrierElimination::IndexDefinitions(Zone* zone) {
193-
BitmapBuilder array_allocations;
206+
BitmapBuilder large_array_allocations;
194207

195208
GrowableArray<Definition*> create_array_worklist;
196209

197210
for (intptr_t i = 0; i < block_order_->length(); ++i) {
198211
BlockEntryInstr* const block = block_order_->At(i);
199212
if (auto join_block = block->AsJoinEntry()) {
200213
for (PhiIterator it(join_block); !it.Done(); it.Advance()) {
201-
array_allocations.Set(definition_count_, false);
214+
large_array_allocations.Set(definition_count_, false);
202215
definition_indices_.Insert({it.Current(), definition_count_++});
203216
#if defined(DEBUG)
204217
if (tracing_) {
@@ -211,10 +224,10 @@ void WriteBarrierElimination::IndexDefinitions(Zone* zone) {
211224
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
212225
if (Definition* current = it.Current()->AsDefinition()) {
213226
if (IsUsable(current)) {
214-
const bool is_create_array = current->IsCreateArray();
215-
array_allocations.Set(definition_count_, is_create_array);
227+
const bool is_create_large_array = IsCreateLargeArray(current);
228+
large_array_allocations.Set(definition_count_, is_create_large_array);
216229
definition_indices_.Insert({current, definition_count_++});
217-
if (is_create_array) {
230+
if (is_create_large_array) {
218231
create_array_worklist.Add(current);
219232
}
220233
#if defined(DEBUG)
@@ -234,8 +247,9 @@ void WriteBarrierElimination::IndexDefinitions(Zone* zone) {
234247
it.Advance()) {
235248
if (auto phi_use = it.Current()->instruction()->AsPhi()) {
236249
const intptr_t index = Index(phi_use);
237-
if (!array_allocations.Get(index)) {
238-
array_allocations.Set(index, /*can_be_create_array=*/true);
250+
if (!large_array_allocations.Get(index)) {
251+
large_array_allocations.Set(index,
252+
/*can_be_create_large_array=*/true);
239253
create_array_worklist.Add(phi_use);
240254
}
241255
}
@@ -244,9 +258,9 @@ void WriteBarrierElimination::IndexDefinitions(Zone* zone) {
244258

245259
vector_ = new (zone) BitVector(zone, definition_count_);
246260
vector_->SetAll();
247-
array_allocations_mask_ = new (zone) BitVector(zone, definition_count_);
261+
large_array_allocations_mask_ = new (zone) BitVector(zone, definition_count_);
248262
for (intptr_t i = 0; i < definition_count_; ++i) {
249-
if (!array_allocations.Get(i)) array_allocations_mask_->Add(i);
263+
if (!large_array_allocations.Get(i)) large_array_allocations_mask_->Add(i);
250264
}
251265
}
252266

@@ -388,9 +402,9 @@ void WriteBarrierElimination::UpdateVectorForBlock(BlockEntryInstr* entry,
388402
if (current->CanCallDart()) {
389403
vector_->Clear();
390404
} else if (current->CanTriggerGC()) {
391-
// Clear array allocations. These are not added to the remembered set
392-
// by Thread::RememberLiveTemporaries() after a scavenge.
393-
vector_->Intersect(array_allocations_mask_);
405+
// Clear large array allocations. These are not added to the remembered
406+
// set by Thread::RememberLiveTemporaries() after a scavenge.
407+
vector_->Intersect(large_array_allocations_mask_);
394408
}
395409

396410
if (AllocationInstr* const alloc = current->AsAllocation()) {

runtime/vm/compiler/write_barrier_elimination_test.cc

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,14 @@ ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_AtLeastOnce) {
138138
EXPECT(store->ShouldEmitStoreBarrier() == true);
139139
}
140140

141-
ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Arrays) {
141+
static void TestWBEForArrays(int length) {
142142
DEBUG_ONLY(
143143
SetFlagScope<bool> sfs(&FLAG_trace_write_barrier_elimination, true));
144144
const char* nullable_tag = TestCase::NullableTag();
145145

146-
// Test that array allocations are not considered usable after a
147-
// may-trigger-GC instruction (in this case CheckStackOverflow), unlike
148-
// normal allocations, which are only interruped by a Dart call.
146+
// Test that array allocations are considered usable after a
147+
// may-trigger-GC instruction (in this case CheckStackOverflow) iff they
148+
// are small.
149149
// clang-format off
150150
auto kScript =
151151
Utils::CStringUniquePtr(OS::SCreate(nullptr, R"(
@@ -159,7 +159,8 @@ ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Arrays) {
159159
foo(int x) {
160160
C c = C();
161161
C n = C();
162-
List<C%s> array = List<C%s>.filled(1, null);
162+
List<C%s> array = List<C%s>.filled(%d, null);
163+
array[0] = c;
163164
while (x --> 0) {
164165
c.next = n;
165166
n = c;
@@ -170,10 +171,15 @@ ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Arrays) {
170171
}
171172
172173
main() { foo(10); }
173-
)", TestCase::LateTag(), nullable_tag, nullable_tag), std::free);
174+
)", TestCase::LateTag(), nullable_tag, nullable_tag, length), std::free);
174175
// clang-format on
175176

176-
const auto& root_library = Library::Handle(LoadTestScript(kScript.get()));
177+
// Generate a length dependent test library uri.
178+
char lib_uri[256];
179+
snprintf(lib_uri, sizeof(lib_uri), "%s%d", RESOLVED_USER_TEST_URI, length);
180+
181+
const auto& root_library = Library::Handle(
182+
LoadTestScript(kScript.get(), /*resolver=*/nullptr, lib_uri));
177183

178184
Invoke(root_library, "main");
179185

@@ -185,10 +191,13 @@ ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Arrays) {
185191
EXPECT(entry != nullptr);
186192

187193
StoreInstanceFieldInstr* store_into_c = nullptr;
188-
StoreIndexedInstr* store_into_array = nullptr;
194+
StoreIndexedInstr* store_into_array_before_loop = nullptr;
195+
StoreIndexedInstr* store_into_array_after_loop = nullptr;
189196

190197
ILMatcher cursor(flow_graph, entry);
191198
RELEASE_ASSERT(cursor.TryMatch({
199+
kMoveGlob,
200+
{kMatchAndMoveStoreIndexed, &store_into_array_before_loop},
192201
kMoveGlob,
193202
kMatchAndMoveGoto,
194203
kMoveGlob,
@@ -200,11 +209,19 @@ ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Arrays) {
200209
kMoveGlob,
201210
kMatchAndMoveBranchFalse,
202211
kMoveGlob,
203-
{kMatchAndMoveStoreIndexed, &store_into_array},
212+
{kMatchAndMoveStoreIndexed, &store_into_array_after_loop},
204213
}));
205214

206215
EXPECT(store_into_c->ShouldEmitStoreBarrier() == false);
207-
EXPECT(store_into_array->ShouldEmitStoreBarrier() == true);
216+
EXPECT(store_into_array_before_loop->ShouldEmitStoreBarrier() == false);
217+
EXPECT(store_into_array_after_loop->ShouldEmitStoreBarrier() ==
218+
(length > Array::kMaxLengthForWriteBarrierElimination));
219+
}
220+
221+
ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Arrays) {
222+
TestWBEForArrays(1);
223+
TestWBEForArrays(Array::kMaxLengthForWriteBarrierElimination);
224+
TestWBEForArrays(Array::kMaxLengthForWriteBarrierElimination + 1);
208225
}
209226

210227
ISOLATE_UNIT_TEST_CASE(IRTest_WriteBarrierElimination_Regress43786) {

runtime/vm/object.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -668,7 +668,7 @@ class Object {
668668
Heap::Space space,
669669
bool compressed);
670670

671-
static intptr_t RoundedAllocationSize(intptr_t size) {
671+
static constexpr intptr_t RoundedAllocationSize(intptr_t size) {
672672
return Utils::RoundUp(size, kObjectAlignment);
673673
}
674674

@@ -10228,10 +10228,17 @@ class Bool : public Instance {
1022810228
class Array : public Instance {
1022910229
public:
1023010230
// Returns `true` if we use card marking for arrays of length [array_length].
10231-
static bool UseCardMarkingForAllocation(const intptr_t array_length) {
10231+
static constexpr bool UseCardMarkingForAllocation(
10232+
const intptr_t array_length) {
1023210233
return Array::InstanceSize(array_length) > Heap::kNewAllocatableSize;
1023310234
}
1023410235

10236+
// WB invariant restoration code only applies to arrives which have at most
10237+
// this many elements. Consequently WB elimination code should not eliminate
10238+
// WB on arrays of larger lengths across instructions that can cause GC.
10239+
// Note: we also can't restore WB invariant for arrays which use card marking.
10240+
static constexpr intptr_t kMaxLengthForWriteBarrierElimination = 8;
10241+
1023510242
intptr_t Length() const { return LengthOf(ptr()); }
1023610243
static intptr_t LengthOf(const ArrayPtr array) {
1023710244
return Smi::Value(array->untag()->length());
@@ -10327,7 +10334,7 @@ class Array : public Instance {
1032710334
return OFFSET_OF(UntaggedArray, type_arguments_);
1032810335
}
1032910336

10330-
static bool IsValidLength(intptr_t len) {
10337+
static constexpr bool IsValidLength(intptr_t len) {
1033110338
return 0 <= len && len <= kMaxElements;
1033210339
}
1033310340

@@ -10337,7 +10344,7 @@ class Array : public Instance {
1033710344
return 0;
1033810345
}
1033910346

10340-
static intptr_t InstanceSize(intptr_t len) {
10347+
static constexpr intptr_t InstanceSize(intptr_t len) {
1034110348
// Ensure that variable length data is not adding to the object length.
1034210349
ASSERT(sizeof(UntaggedArray) ==
1034310350
(sizeof(UntaggedInstance) + (2 * kBytesPerElement)));

runtime/vm/thread.cc

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,10 +657,15 @@ class RestoreWriteBarrierInvariantVisitor : public ObjectPointerVisitor {
657657
// Stores into new-space objects don't need a write barrier.
658658
if (obj->IsSmiOrNewObject()) continue;
659659

660-
// To avoid adding too much work into the remembered set, skip
660+
// To avoid adding too much work into the remembered set, skip large
661661
// arrays. Write barrier elimination will not remove the barrier
662662
// if we can trigger GC between array allocation and store.
663-
if (obj->GetClassId() == kArrayCid) continue;
663+
if (obj->GetClassId() == kArrayCid) {
664+
const auto length = Smi::Value(Array::RawCast(obj)->untag()->length());
665+
if (length > Array::kMaxLengthForWriteBarrierElimination) {
666+
continue;
667+
}
668+
}
664669

665670
// Dart code won't store into VM-internal objects except Contexts and
666671
// UnhandledExceptions. This assumption is checked by an assertion in

sdk/lib/_internal/vm/lib/async_patch.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ dynamic Function(Object, StackTrace) _asyncErrorWrapperHelper(
7070
Future _awaitHelper(var object, dynamic Function(dynamic) thenCallback,
7171
dynamic Function(dynamic, StackTrace) errorCallback, Function awaiter) {
7272
late _Future future;
73-
if (object is! Future) {
74-
future = new _Future().._setValue(object);
75-
} else if (object is _Future) {
73+
if (object is _Future) {
7674
future = object;
75+
} else if (object is! Future) {
76+
future = new _Future().._setValue(object);
7777
} else {
7878
return object.then(thenCallback, onError: errorCallback);
7979
}

tools/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,5 @@ CHANNEL dev
2727
MAJOR 2
2828
MINOR 17
2929
PATCH 0
30-
PRERELEASE 86
30+
PRERELEASE 87
3131
PRERELEASE_PATCH 0

0 commit comments

Comments
 (0)