Skip to content

Commit 28c2491

Browse files
rmacnak-googleCommit Queue
authored and
Commit Queue
committed
[vm, service] Account for weakness in getRetainingPath and getRetainedSize.
We had been treating all references as strong for these RPCs. Now weak references are skipped, but ephemeron references are still treated as strong. TEST=ci Bug: #49155 Change-Id: I6c4f344ce3c0df5bdbeb133a697bb26ff972f372 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/302367 Reviewed-by: Ben Konyi <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent be4e79e commit 28c2491

File tree

4 files changed

+114
-1
lines changed

4 files changed

+114
-1
lines changed

runtime/observatory/tests/service/get_retained_size_rpc_test.dart

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:typed_data';
6+
57
import 'package:observatory/service_io.dart';
68
import 'package:test/test.dart';
79

810
import 'test_helper.dart';
911

12+
const MB = 1 << 20;
13+
1014
class _TestClass {
1115
_TestClass(this.x, this.y);
1216
// Make sure these fields are not removed by the tree shaker.
@@ -25,6 +29,9 @@ invoke1() => myVar = new _TestClass(null, null);
2529
@pragma("vm:entry-point")
2630
invoke2() => myVar = new _TestClass(new _TestClass(null, null), null);
2731

32+
@pragma("vm:entry-point")
33+
invoke3() => myVar = new _TestClass(new WeakReference(new Uint8List(MB)), null);
34+
2835
invoke(Isolate isolate, String selector) async {
2936
Map params = {
3037
'targetId': isolate.rootLibrary.id,
@@ -71,6 +78,17 @@ var tests = <IsolateTest>[
7178
int value3 = int.parse(result['valueAsString']);
7279
expect(value3, isPositive);
7380
expect(value3, equals(value2));
81+
82+
// Target of WeakReference not retained.
83+
evalResult = await invoke(isolate, 'invoke3');
84+
params = {
85+
'targetId': evalResult['id'],
86+
};
87+
result = await isolate.invokeRpcNoUpgrade('_getRetainedSize', params);
88+
expect(result['type'], equals('@Instance'));
89+
expect(result['kind'], equals('Int'));
90+
int value4 = int.parse(result['valueAsString']);
91+
expect(value4, lessThan(MB));
7492
},
7593
];
7694

runtime/observatory/tests/service/get_retaining_path_rpc_test.dart

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ dynamic target3 = new _TestClass();
2222
dynamic target4 = new _TestClass();
2323
dynamic target5 = new _TestClass();
2424
dynamic target6 = new _TestClass();
25+
dynamic target7 = new _TestClass();
26+
dynamic target8 = new _TestClass();
27+
2528
@pragma("vm:entry-point") // Prevent obfuscation
2629
Expando<_TestClass> expando = Expando<_TestClass>();
2730
@pragma("vm:entry-point") // Prevent obfuscation
@@ -32,13 +35,25 @@ dynamic globalList = new List<dynamic>.filled(100, null);
3235
dynamic globalMap1 = new Map();
3336
@pragma("vm:entry-point") // Prevent obfuscation
3437
dynamic globalMap2 = new Map();
38+
@pragma("vm:entry-point") // Prevent obfuscation
39+
dynamic weakReachable = new _TestClass();
40+
@pragma("vm:entry-point") // Prevent obfuscation
41+
dynamic weakUnreachable = new _TestClass();
3542

3643
void warmup() {
3744
globalObject.x = target1;
3845
globalObject.y = target2;
3946
globalList[12] = target3;
4047
globalMap1['key'] = target4;
4148
globalMap2[target5] = 'value';
49+
50+
// The weak reference will be traced first in DFS, but the retaining path
51+
// include the strong reference.
52+
weakReachable.x = new WeakReference<_TestClass>(target7);
53+
weakReachable.y = target7;
54+
55+
weakUnreachable.x = new WeakReference<_TestClass>(target8);
56+
weakUnreachable.y = null;
4257
}
4358

4459
@pragma("vm:entry-point") // Prevent obfuscation
@@ -88,6 +103,20 @@ takeExpandoTarget() {
88103
return tmp2;
89104
}
90105

106+
@pragma("vm:entry-point") // Prevent obfuscation
107+
takeWeakReachableTarget() {
108+
var tmp = target7;
109+
target7 = null;
110+
return tmp;
111+
}
112+
113+
@pragma("vm:entry-point") // Prevent obfuscation
114+
takeWeakUnreachableTarget() {
115+
var tmp = target8;
116+
target8 = null;
117+
return tmp;
118+
}
119+
91120
@pragma("vm:entry-point") // Prevent obfuscation
92121
getTrue() => true;
93122

@@ -220,6 +249,31 @@ var tests = <IsolateTest>[
220249
expect(result['elements'][4]['value']['name'], 'expando');
221250
},
222251

252+
(Isolate isolate) async {
253+
var target7 = await invoke(isolate, 'takeWeakReachableTarget');
254+
var params = {
255+
'targetId': target7['id'],
256+
'limit': 100,
257+
};
258+
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
259+
expect(result['type'], equals('RetainingPath'));
260+
expect(result['gcRootType'], 'user global');
261+
expect(result['elements'].length, equals(3));
262+
expect(result['elements'][1]['parentField'], equals('y'));
263+
expect(result['elements'][2]['value']['name'], equals('weakReachable'));
264+
},
265+
266+
(Isolate isolate) async {
267+
var target8 = await invoke(isolate, 'takeWeakUnreachableTarget');
268+
var params = {
269+
'targetId': target8['id'],
270+
'limit': 100,
271+
};
272+
var result = await isolate.invokeRpcNoUpgrade('getRetainingPath', params);
273+
expect(result['type'], equals('RetainingPath'));
274+
expect(result['elements'].length, equals(0));
275+
},
276+
223277
// object store
224278
(Isolate isolate) async {
225279
var obj = await invoke(isolate, 'getTrue');

runtime/vm/object_graph.cc

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,50 @@ class ObjectGraph::Stack : public ObjectPointerVisitor {
240240
}
241241
if (direction == ObjectGraph::Visitor::kProceed) {
242242
set_gc_root_type(node.gc_root_type);
243-
obj->untag()->VisitPointers(this);
243+
ASSERT(obj->IsHeapObject());
244+
switch (obj->GetClassId()) {
245+
case kWeakArrayCid:
246+
VisitWeakArray(static_cast<WeakArrayPtr>(obj));
247+
break;
248+
case kWeakReferenceCid:
249+
VisitWeakReference(static_cast<WeakReferencePtr>(obj));
250+
break;
251+
case kFinalizerEntryCid:
252+
VisitFinalizerEntry(static_cast<FinalizerEntryPtr>(obj));
253+
break;
254+
default:
255+
obj->untag()->VisitPointers(this);
256+
break;
257+
}
244258
clear_gc_root_type();
245259
}
246260
}
247261
}
248262

263+
void VisitWeakArray(WeakArrayPtr array) {}
264+
265+
void VisitWeakReference(WeakReferencePtr ref) {
266+
#if !defined(DART_COMPRESSED_POINTERS)
267+
VisitPointers(&ref->untag()->type_arguments_,
268+
&ref->untag()->type_arguments_);
269+
#else
270+
VisitCompressedPointers(ref->heap_base(), &ref->untag()->type_arguments_,
271+
&ref->untag()->type_arguments_);
272+
#endif
273+
}
274+
275+
void VisitFinalizerEntry(FinalizerEntryPtr entry) {
276+
#if !defined(DART_COMPRESSED_POINTERS)
277+
VisitPointers(&entry->untag()->token_, &entry->untag()->token_);
278+
VisitPointers(&entry->untag()->next_, &entry->untag()->next_);
279+
#else
280+
VisitCompressedPointers(entry->heap_base(), &entry->untag()->token_,
281+
&entry->untag()->token_);
282+
VisitCompressedPointers(entry->heap_base(), &entry->untag()->next_,
283+
&entry->untag()->next_);
284+
#endif
285+
}
286+
249287
bool visit_weak_persistent_handles() const override {
250288
return visit_weak_persistent_handles_;
251289
}

runtime/vm/raw_object.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3492,6 +3492,7 @@ class UntaggedWeakReference : public UntaggedInstance {
34923492
friend class Scavenger;
34933493
template <bool>
34943494
friend class ScavengerVisitorBase;
3495+
friend class ObjectGraph;
34953496
friend class FastObjectCopy; // For OFFSET_OF
34963497
friend class SlowObjectCopy; // For OFFSET_OF
34973498
};
@@ -3527,6 +3528,7 @@ class UntaggedFinalizerBase : public UntaggedInstance {
35273528
friend class Scavenger;
35283529
template <bool>
35293530
friend class ScavengerVisitorBase;
3531+
friend class ObjectGraph;
35303532
};
35313533

35323534
class UntaggedFinalizer : public UntaggedFinalizerBase {
@@ -3603,6 +3605,7 @@ class UntaggedFinalizerEntry : public UntaggedInstance {
36033605
template <bool>
36043606
friend class ScavengerVisitorBase;
36053607
friend class ScavengerFinalizerVisitor;
3608+
friend class ObjectGraph;
36063609
};
36073610

36083611
// MirrorReferences are used by mirrors to hold reflectees that are VM

0 commit comments

Comments
 (0)