dart-sdk/tests/ffi_2/finalizer_external_size_accounting_test.dart
Ryan Macnak f4b34ad31b [vm, gc] Add missing promotion of Finalizer external size. Remove race incrementing external size.
When a FinalizerEntry's target gets promoted, the associated external size needs to also get promoted. We were handling the cases where the FinalizerEntry itself was either already old or remained new, but not the case where it was promoted. Failing to promote the external size meant that when the finalizer was collected, external size was subtraced from old space that was still being attributed to new space, so the old space total external size became negative.

TEST=ci
Bug: https://github.com/dart-lang/sdk/issues/50537
Change-Id: Id2fe2d748311de73f04de367c9cd153d87b74ad1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/272350
Reviewed-by: Daco Harkes <dacoharkes@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
2022-11-30 17:14:59 +00:00

51 lines
1.5 KiB
Dart

// Copyright (c) 2022, 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.
// Issue https://github.com/dart-lang/sdk/issues/50537
// @dart=2.9
import "dart:async";
import "dart:ffi";
import "dart:io";
final libc = DynamicLibrary.process();
typedef MallocForeign = Pointer<Void> Function(IntPtr size);
typedef MallocNative = Pointer<Void> Function(int size);
final malloc = libc.lookupFunction<MallocForeign, MallocNative>('malloc');
typedef FreeForeign = Void Function(Pointer<Void>);
final free = libc.lookup<NativeFunction<FreeForeign>>('free');
final freeFinalizer = NativeFinalizer(free);
class Resource implements Finalizable {
Pointer<Void> _target;
Resource() : _target = malloc(8) {
if (_target == nullptr) {
throw OutOfMemoryError();
}
freeFinalizer.attach(this, _target, detach: this, externalSize: 8);
}
}
void main() {
if (Platform.isWindows) {
print("No malloc via self process lookup on Windows");
return;
}
// Split across turns so the internal finalizer cleanup can run.
// Cf. https://github.com/dart-lang/sdk/issues/50570
final sw = Stopwatch()..start();
step() {
if (sw.elapsedMilliseconds < 2000) {
// VM assertion: external size of each generation should always be
// non-negative.
List.generate(1000, (_) => new Resource());
Timer.run(step);
}
}
Timer.run(step);
}