Skip to content

Commit

Permalink
Version 3.6.0-194.0.dev
Browse files Browse the repository at this point in the history
Merge 8fa0f56 into dev
  • Loading branch information
Dart CI committed Aug 29, 2024
2 parents fed5ce7 + 8fa0f56 commit 0caad79
Show file tree
Hide file tree
Showing 24 changed files with 754 additions and 143 deletions.
3 changes: 3 additions & 0 deletions pkg/dds/lib/src/expression_evaluator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ class ExpressionEvaluator {
if (parameters['scope'].asMapOr({}).isNotEmpty) {
params['scope'] = parameters['scope'].asMap;
}
if (parameters['_idZoneId'].asStringOr('').isNotEmpty) {
params['_idZoneId'] = parameters['_idZoneId'].asString;
}
return (await dds.vmServiceClient.sendRequest(
'_evaluateCompiledExpression',
params,
Expand Down
2 changes: 1 addition & 1 deletion pkg/vm_service/test/get_object_rpc_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ var tests = <IsolateTest>[
// An expired object.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final objectId = 'objects/99999999';
final objectId = 'objects/99999999/0';
try {
await service.getObject(isolateId, objectId);
fail('successfully got object with bad ID');
Expand Down
315 changes: 315 additions & 0 deletions pkg/vm_service/test/id_zones_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,315 @@
// Copyright (c) 2024, 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.

import 'dart:developer';

import 'package:test/test.dart';
import 'package:vm_service/vm_service.dart';

import 'common/service_test_common.dart';
import 'common/test_helper.dart';

// AUTOGENERATED START
//
// Update these constants by running:
//
// dart pkg/vm_service/test/update_line_numbers.dart <test.dart>
//
const LINE_A = 29;
// AUTOGENERATED END

class C {
final int x = 123;
}

void testeeMain() {
// ignore: unused_local_variable
final c = C();
debugger(); // LINE_A
}

final tests = <IsolateTest>[
// TODO(derekxu16): Replace the usages of [callMethod] below with calls to
// dedicated RPC methods once they're available in package:vm_service.
hasStoppedAtBreakpoint,
stoppedAtLine(LINE_A),
// Test the behaviour of an ID Zone with a `backingBufferKind` of `Ring`, an
// `idAssignmentPolicy` of `AlwaysAllocate`, and the default capacity.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final idZone1 = (await service.callMethod(
'_createIdZone',
isolateId: isolateId,
args: {
'backingBufferKind': 'Ring',
'idAssignmentPolicy': 'AlwaysAllocate',
},
))
.json!;
expect(idZone1['type'], '_IdZone');
expect(idZone1['id'], 'zones/1');
expect(idZone1['backingBufferKind'], 'Ring');
expect(idZone1['idAssignmentPolicy'], 'AlwaysAllocate');

final cInstanceRef1 = (await service.callMethod(
'evaluateInFrame',
isolateId: isolateId,
args: {
'frameIndex': 0,
'expression': 'c',
'_idZoneId': idZone1['id'],
},
))
.json!;
expect(cInstanceRef1['type'], '@Instance');
final cObjectId1 = cInstanceRef1['id'];
expect(cObjectId1, 'objects/0/1');

final cInstance1 = await service.getObject(isolateId, cObjectId1);
expect(cInstance1.type, 'Instance');

final cInstanceRef2 = (await service.callMethod(
'evaluateInFrame',
isolateId: isolateId,
args: {
'frameIndex': 0,
'expression': 'c',
'_idZoneId': idZone1['id'],
},
))
.json!;
expect(cInstanceRef2['type'], '@Instance');
final cObjectId2 = cInstanceRef2['id'];
expect(cObjectId2, 'objects/1/1');

final cInstance2 = await service.getObject(isolateId, cObjectId2);
expect(cInstance2.type, 'Instance');

await service.callMethod(
'_invalidateIdZone',
isolateId: isolateId,
args: {
'_idZoneId': idZone1['id'],
},
);

try {
await service.getObject(isolateId, cObjectId1);
fail('successfully retrieved object using expired ID');
} on SentinelException catch (e) {
expect(e.sentinel.kind, startsWith('Expired'));
expect(e.sentinel.valueAsString, equals('<expired>'));
}

// Ensure that the zone can be reused after it was invalidated.
final cInstanceRef3 = (await service.callMethod(
'evaluateInFrame',
isolateId: isolateId,
args: {
'frameIndex': 0,
'expression': 'c',
'_idZoneId': idZone1['id'],
},
))
.json!;
expect(cInstanceRef3['type'], '@Instance');
expect(cInstanceRef3['id'], 'objects/0/1');
},

// Test the behaviour of an ID Zone with a `backingBufferKind` of `Ring`, an
// `idAssignmentPolicy` of `AlwaysAllocate`, and a capacity of 1.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final idZone2 = (await service.callMethod(
'_createIdZone',
isolateId: isolateId,
args: {
'backingBufferKind': 'Ring',
'idAssignmentPolicy': 'AlwaysAllocate',
'capacity': 1,
},
))
.json!;
expect(idZone2['type'], '_IdZone');
expect(idZone2['id'], 'zones/2');
expect(idZone2['backingBufferKind'], 'Ring');
expect(idZone2['idAssignmentPolicy'], 'AlwaysAllocate');

final cInstanceRef1 = (await service.callMethod(
'evaluateInFrame',
isolateId: isolateId,
args: {
'frameIndex': 0,
'expression': 'c',
'_idZoneId': idZone2['id'],
},
))
.json!;
expect(cInstanceRef1['type'], '@Instance');
final cObjectId1 = cInstanceRef1['id'];
expect(cObjectId1, 'objects/0/2');

final cInstance1 = await service.getObject(isolateId, cObjectId1);
expect(cInstance1.type, 'Instance');

final cInstanceRef2 = (await service.callMethod(
'evaluateInFrame',
isolateId: isolateId,
args: {
'frameIndex': 0,
'expression': 'c',
'_idZoneId': idZone2['id'],
},
))
.json!;
expect(cInstanceRef2['type'], '@Instance');
final cObjectId2 = cInstanceRef2['id'];
expect(cObjectId2, 'objects/1/2');

final cInstance2 = await service.getObject(isolateId, cObjectId2);
expect(cInstance2.type, 'Instance');

// [idZone2] only has a capacity of 1, so [cObjectId1] should have been
// evicted when [cObjectId2] was allocated.
try {
await service.getObject(isolateId, cObjectId1);
fail('successfully retrieved object using expired ID');
} on SentinelException catch (e) {
expect(e.sentinel.kind, startsWith('Expired'));
expect(e.sentinel.valueAsString, equals('<expired>'));
}
},

// Test the behaviour of an ID Zone with a `backingBufferKind` of `Ring`, an
// `idAssignmentPolicy` of `ReuseExisting`, and the default capacity.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final idZone3 = (await service.callMethod(
'_createIdZone',
isolateId: isolateId,
args: {
'backingBufferKind': 'Ring',
'idAssignmentPolicy': 'ReuseExisting',
},
))
.json!;
expect(idZone3['type'], '_IdZone');
expect(idZone3['id'], 'zones/3');
expect(idZone3['backingBufferKind'], 'Ring');
expect(idZone3['idAssignmentPolicy'], 'ReuseExisting');

final cInstanceRef1 = (await service.callMethod(
'evaluateInFrame',
isolateId: isolateId,
args: {
'frameIndex': 0,
'expression': 'c',
'_idZoneId': idZone3['id'],
},
))
.json!;
expect(cInstanceRef1['type'], '@Instance');
final cObjectId1 = cInstanceRef1['id'];
expect(cObjectId1, 'objects/0/3');

final cInstance1 = await service.getObject(isolateId, cObjectId1);
expect(cInstance1.type, 'Instance');

final cInstanceRef2 = (await service.callMethod(
'evaluateInFrame',
isolateId: isolateId,
args: {
'frameIndex': 0,
'expression': 'c',
'_idZoneId': idZone3['id'],
},
))
.json!;
expect(cInstanceRef2['type'], '@Instance');
final cObjectId2 = cInstanceRef2['id'];
expect(cObjectId2, 'objects/0/3');

final cInstance2 = await service.getObject(isolateId, cObjectId2);
expect(cInstance2.type, 'Instance');

await service.callMethod(
'_invalidateIdZone',
isolateId: isolateId,
args: {
'_idZoneId': idZone3['id'],
},
);

try {
await service.getObject(isolateId, cObjectId1);
fail('successfully retrieved object using expired ID');
} on SentinelException catch (e) {
expect(e.sentinel.kind, startsWith('Expired'));
expect(e.sentinel.valueAsString, equals('<expired>'));
}

// Ensure that the zone can be reused after it was invalidated.
final cInstanceRef3 = (await service.callMethod(
'evaluateInFrame',
isolateId: isolateId,
args: {
'frameIndex': 0,
'expression': 'c',
'_idZoneId': idZone3['id'],
},
))
.json!;
expect(cInstanceRef3['type'], '@Instance');
expect(cInstanceRef3['id'], 'objects/0/3');
},

// Test deleting an ID Zone.
(VmService service, IsolateRef isolateRef) async {
final isolateId = isolateRef.id!;
final idZone4 = (await service.callMethod(
'_createIdZone',
isolateId: isolateId,
args: {
'backingBufferKind': 'Ring',
'idAssignmentPolicy': 'AlwaysAllocate',
},
))
.json!;
expect(idZone4['type'], '_IdZone');
expect(idZone4['id'], 'zones/4');
expect(idZone4['backingBufferKind'], 'Ring');
expect(idZone4['idAssignmentPolicy'], 'AlwaysAllocate');

await service.callMethod(
'_deleteIdZone',
isolateId: isolateId,
args: {
'_idZoneId': idZone4['id'],
},
);

try {
await service.callMethod(
'evaluateInFrame',
isolateId: isolateId,
args: {
'frameIndex': 0,
'expression': 'c',
'_idZoneId': idZone4['id'],
},
);
fail('successfully used an ID zone that should have been deleted');
} on RPCError catch (e) {
expect(e.code, RPCErrorKind.kInvalidParams.code);
}
},
resumeIsolate,
];

Future<void> main([args = const <String>[]]) => runIsolateTests(
args,
tests,
'id_zones_test.dart',
testeeConcurrent: testeeMain,
);
1 change: 1 addition & 0 deletions runtime/lib/developer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ DEFINE_NATIVE_ENTRY(Developer_getIsolateIdFromSendPort, 0, 1) {
#endif
}

// TODO(derekxu16): Make this function accept an idZoneId.
DEFINE_NATIVE_ENTRY(Developer_getObjectId, 0, 1) {
#if defined(PRODUCT)
return Object::null();
Expand Down
4 changes: 2 additions & 2 deletions runtime/vm/heap/become.cc
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,8 @@ void Become::FollowForwardingPointers(Thread* thread) {
#ifndef PRODUCT
isolate_group->ForEachIsolate(
[&](Isolate* isolate) {
if (isolate->NumServiceIdZones() > 0) {
isolate->EnsureDefaultServiceIdZone().VisitPointers(pointer_visitor);
for (intptr_t i = 0; i < isolate->NumServiceIdZones(); ++i) {
isolate->GetServiceIdZone(i)->VisitPointers(pointer_visitor);
}
},
/*at_safepoint=*/true);
Expand Down
5 changes: 2 additions & 3 deletions runtime/vm/heap/compactor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -509,9 +509,8 @@ void CompactorTask::RunEnteredIsolateGroup() {
TIMELINE_FUNCTION_GC_DURATION(thread, "ForwardObjectIdRing");
isolate_group_->ForEachIsolate(
[&](Isolate* isolate) {
if (isolate->NumServiceIdZones() > 0) {
isolate->EnsureDefaultServiceIdZone().VisitPointers(
*compactor_);
for (intptr_t i = 0; i < isolate->NumServiceIdZones(); ++i) {
isolate->GetServiceIdZone(i)->VisitPointers(*compactor_);
}
},
/*at_safepoint=*/true);
Expand Down
4 changes: 2 additions & 2 deletions runtime/vm/heap/incremental_compactor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -681,8 +681,8 @@ class EpilogueTask : public ThreadPool::Task {
TIMELINE_FUNCTION_GC_DURATION(thread, "IdRing");
isolate_group_->ForEachIsolate(
[&](Isolate* isolate) {
if (isolate->NumServiceIdZones() > 0) {
isolate->EnsureDefaultServiceIdZone().VisitPointers(visitor);
for (intptr_t i = 0; i < isolate->NumServiceIdZones(); ++i) {
isolate->GetServiceIdZone(i)->VisitPointers(visitor);
}
},
/*at_safepoint=*/true);
Expand Down
2 changes: 1 addition & 1 deletion runtime/vm/heap/marker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ void GCMarker::IterateRoots(ObjectPointerVisitor* visitor) {
case kObjectIdRing: {
TIMELINE_FUNCTION_GC_DURATION(Thread::Current(),
"ProcessObjectIdTable");
isolate_group_->VisitPointersInDefaultServiceIdZone(*visitor);
isolate_group_->VisitPointersInAllServiceIdZones(*visitor);
break;
}
}
Expand Down
2 changes: 1 addition & 1 deletion runtime/vm/heap/scavenger.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1244,7 +1244,7 @@ void Scavenger::IterateRememberedCards(
void Scavenger::IterateObjectIdTable(ObjectPointerVisitor* visitor) {
#ifndef PRODUCT
TIMELINE_FUNCTION_GC_DURATION(Thread::Current(), "IterateObjectIdTable");
heap_->isolate_group()->VisitPointersInDefaultServiceIdZone(*visitor);
heap_->isolate_group()->VisitPointersInAllServiceIdZones(*visitor);
#endif // !PRODUCT
}

Expand Down
Loading

0 comments on commit 0caad79

Please sign in to comment.