From 67f3e1f4a0dfe57c07192607095892a9d107a9d1 Mon Sep 17 00:00:00 2001 From: Derek Xu Date: Mon, 27 Feb 2023 21:07:41 +0000 Subject: [PATCH] [VM/Service] Add support for class modifiers TEST=CI Fixes https://github.com/dart-lang/sdk/issues/50742 Fixes https://github.com/dart-lang/sdk/issues/50743 Fixes https://github.com/dart-lang/sdk/issues/51296 Fixes https://github.com/dart-lang/sdk/issues/51297 Change-Id: I52de34219883ca8680b1a8968ac9f4183fc5e970 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/285360 Commit-Queue: Derek Xu Reviewed-by: Ben Konyi --- pkg/vm_service/CHANGELOG.md | 7 +- pkg/vm_service/java/version.properties | 2 +- pkg/vm_service/lib/src/vm_service.dart | 32 ++- pkg/vm_service/pubspec.yaml | 2 +- pkg/vm_service/test/get_object_rpc_test.dart | 269 +++++++++++++++--- .../tests/service/get_version_rpc_test.dart | 2 +- .../tests/service_2/get_version_rpc_test.dart | 2 +- .../frontend/kernel_translation_helper.h | 10 + runtime/vm/kernel_loader.cc | 20 +- runtime/vm/object.cc | 25 ++ runtime/vm/object.h | 28 ++ runtime/vm/object_service.cc | 5 + runtime/vm/service.h | 2 +- runtime/vm/service/service.md | 20 +- 14 files changed, 374 insertions(+), 52 deletions(-) diff --git a/pkg/vm_service/CHANGELOG.md b/pkg/vm_service/CHANGELOG.md index 34d109c00ce..bb5697a8657 100644 --- a/pkg/vm_service/CHANGELOG.md +++ b/pkg/vm_service/CHANGELOG.md @@ -1,4 +1,9 @@ -## 11.1.1-dev +## 11.2.1-dev + +## 11.2.0 +- Update to version `4.3` of the spec. +- Add `isSealed`, `isMixinClass`, `isBaseClass`, `isInterfaceClass`, and + `isFinal` properties to `Class`. ## 11.1.0 - Reduce number of type checks in `toJson()` methods. diff --git a/pkg/vm_service/java/version.properties b/pkg/vm_service/java/version.properties index 5aa69a7763c..ca62e2c1035 100644 --- a/pkg/vm_service/java/version.properties +++ b/pkg/vm_service/java/version.properties @@ -1 +1 @@ -version=4.2 +version=4.3 diff --git a/pkg/vm_service/lib/src/vm_service.dart b/pkg/vm_service/lib/src/vm_service.dart index 040be43db13..ee28b109b45 100644 --- a/pkg/vm_service/lib/src/vm_service.dart +++ b/pkg/vm_service/lib/src/vm_service.dart @@ -28,7 +28,7 @@ export 'snapshot_graph.dart' HeapSnapshotObjectNoData, HeapSnapshotObjectNullData; -const String vmServiceVersion = '4.2.0'; +const String vmServiceVersion = '4.3.0'; /// @optional const String optional = 'optional'; @@ -3314,6 +3314,21 @@ class Class extends Obj implements ClassRef { /// Is this a const class? bool? isConst; + /// Is this a sealed class? + bool? isSealed; + + /// Is this a mixin class? + bool? isMixinClass; + + /// Is this a base class? + bool? isBaseClass; + + /// Is this an interface class? + bool? isInterfaceClass; + + /// Is this a final class? + bool? isFinal; + /// Are allocations of this class being traced? bool? traceAllocations; @@ -3353,6 +3368,11 @@ class Class extends Obj implements ClassRef { this.library, this.isAbstract, this.isConst, + this.isSealed, + this.isMixinClass, + this.isBaseClass, + this.isInterfaceClass, + this.isFinal, this.traceAllocations, this.interfaces, this.fields, @@ -3383,6 +3403,11 @@ class Class extends Obj implements ClassRef { error = createServiceObject(json['error'], const ['ErrorRef']) as ErrorRef?; isAbstract = json['abstract'] ?? false; isConst = json['const'] ?? false; + isSealed = json['isSealed'] ?? false; + isMixinClass = json['isMixinClass'] ?? false; + isBaseClass = json['isBaseClass'] ?? false; + isInterfaceClass = json['isInterfaceClass'] ?? false; + isFinal = json['isFinal'] ?? false; traceAllocations = json['traceAllocations'] ?? false; superClass = createServiceObject(json['super'], const ['ClassRef']) as ClassRef?; @@ -3416,6 +3441,11 @@ class Class extends Obj implements ClassRef { 'library': library?.toJson(), 'abstract': isAbstract ?? false, 'const': isConst ?? false, + 'isSealed': isSealed ?? false, + 'isMixinClass': isMixinClass ?? false, + 'isBaseClass': isBaseClass ?? false, + 'isInterfaceClass': isInterfaceClass ?? false, + 'isFinal': isFinal ?? false, 'traceAllocations': traceAllocations ?? false, 'interfaces': interfaces?.map((f) => f.toJson()).toList(), 'fields': fields?.map((f) => f.toJson()).toList(), diff --git a/pkg/vm_service/pubspec.yaml b/pkg/vm_service/pubspec.yaml index 5af118c4a4a..646b8e59ca2 100644 --- a/pkg/vm_service/pubspec.yaml +++ b/pkg/vm_service/pubspec.yaml @@ -1,5 +1,5 @@ name: vm_service -version: 11.1.1-dev +version: 11.2.0 description: >- A library to communicate with a service implementing the Dart VM service protocol. diff --git a/pkg/vm_service/test/get_object_rpc_test.dart b/pkg/vm_service/test/get_object_rpc_test.dart index 1aa7e8f73b6..ec5cf5c1626 100644 --- a/pkg/vm_service/test/get_object_rpc_test.dart +++ b/pkg/vm_service/test/get_object_rpc_test.dart @@ -1,7 +1,7 @@ // 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. -// VMOptions=--enable-experiment=records +// VMOptions=--enable-experiment=records --enable-experiment=class-modifiers --enable-experiment=sealed-class // @dart=3.0 // ignore_for_file: experiment_not_enabled @@ -16,7 +16,7 @@ import 'package:vm_service/vm_service.dart'; import 'common/test_helper.dart'; -abstract class _DummyAbstractBaseClass { +abstract base mixin class _DummyAbstractBaseClass { void dummyFunction(int a, [bool b = false]); } @@ -34,14 +34,16 @@ class _DummyClass extends _DummyAbstractBaseClass { static List foo() => List.filled(20, ''); } -class _DummySubClass extends _DummyClass {} - class _DummyGenericSubClass extends _DummyClass {} +final class _DummyFinalClass extends _DummyClass {} + +sealed class _DummySealedClass {} + +interface class _DummyInterfaceClass extends _DummySealedClass {} + void warmup() { - // Silence analyzer. - _DummySubClass(); - _DummyGenericSubClass(); + // Increase the usage count of these methods. _DummyClass().dummyFunction(0); _DummyClass().dummyGenericFunction(0, param: 0); } @@ -70,9 +72,15 @@ getRecord() => (1, x: 2, 3.0, y: 4.0); @pragma("vm:entry-point") getDummyClass() => _DummyClass(); +@pragma("vm:entry-point") +getDummyFinalClass() => _DummyFinalClass(); + @pragma("vm:entry-point") getDummyGenericSubClass() => _DummyGenericSubClass(); +@pragma("vm:entry-point") +getDummyInterfaceClass() => _DummyInterfaceClass(); + var uint8List = Uint8List.fromList([3, 2, 1]); var uint64List = Uint64List.fromList([3, 2, 1]); @@ -805,68 +813,247 @@ var tests = [ expect(result.length, 3); final fieldsMap = HashMap.fromEntries( result.fields!.map((f) => MapEntry(f.name, f.value))); - print(fieldsMap); expect(fieldsMap.keys.length, result.length); expect(fieldsMap.containsKey('dummyList'), true); expect((fieldsMap['dummyList'] as InstanceRef).kind, InstanceKind.kList); expect(fieldsMap.containsKey('dummyLateVarWithInit'), true); - expect((fieldsMap['dummyLateVarWithInit'] as Sentinel).kind, SentinelKind.kNotInitialized); + expect((fieldsMap['dummyLateVarWithInit'] as Sentinel).kind, + SentinelKind.kNotInitialized); expect(fieldsMap.containsKey('dummyLateVar'), true); - expect((fieldsMap['dummyLateVar'] as Sentinel).kind, SentinelKind.kNotInitialized); + expect((fieldsMap['dummyLateVar'] as Sentinel).kind, + SentinelKind.kNotInitialized); }, - // class + // An abstract base mixin class. (VmService service, IsolateRef isolateRef) async { final isolateId = isolateRef.id!; final isolate = await service.getIsolate(isolateId); - // Call eval to get a class id. - final evalResult = await service.invoke( + // Use invoke to get a reference to an instance of [_DummyClass]. + final invokeResult = await service.invoke( isolateId, isolate.rootLib!.id!, 'getDummyClass', []) as InstanceRef; - final objectId = evalResult.classRef!.id!; - final result = await service.getObject(isolateId, objectId) as Class; + final derivedClass = + await service.getObject(isolateId, invokeResult.classRef!.id!) as Class; + final baseClassRef = derivedClass.superClass!; + final result = + await service.getObject(isolateId, baseClassRef.id!) as Class; expect(result.id, startsWith('classes/')); - expect(result.name, equals('_DummyClass')); - expect(result.isAbstract, equals(false)); - expect(result.isConst, equals(false)); + expect(result.name, '_DummyAbstractBaseClass'); + expect(result.isAbstract, true); + expect(result.isConst, false); + expect(result.isSealed, false); + expect(result.isMixinClass, true); + expect(result.isBaseClass, true); + expect(result.isInterfaceClass, false); + expect(result.isFinal, false); expect(result.typeParameters, isNull); expect(result.library, isNotNull); expect(result.location, isNotNull); + expect(result.error, isNull); + expect(result.traceAllocations!, false); expect(result.superClass, isNotNull); - expect(result.interfaces!.length, isZero); - expect(result.fields!.length, isPositive); - expect(result.functions!.length, isPositive); - expect(result.subclasses!.length, isPositive); + expect(result.superType, isNotNull); + expect(result.interfaces!.length, 0); + expect(result.mixin, isNull); + expect(result.fields!.length, 0); + expect(result.functions!.length, 2); + expect(result.subclasses!.length, 1); final json = result.json!; - expect(json['_vmName'], startsWith('_DummyClass@')); - expect(json['_finalized'], equals(true)); - expect(json['_implemented'], equals(false)); - expect(json['_patch'], equals(false)); + expect(json['_vmName'], startsWith('_DummyAbstractBaseClass@')); + expect(json['_finalized'], true); + expect(json['_implemented'], false); + expect(json['_patch'], false); }, - // generic class + // A class. (VmService service, IsolateRef isolateRef) async { final isolateId = isolateRef.id!; final isolate = await service.getIsolate(isolateId); - // Call eval to get a class id. - final evalResult = await service.invoke( - isolateId, isolate.rootLib!.id!, 'getDummyGenericSubClass', []) - as InstanceRef; - final objectId = evalResult.classRef!.id!; - final result = await service.getObject(isolateId, objectId) as Class; + // Use invoke to get a reference to an instance of [_DummyClass]. + final invokeResult = await service.invoke( + isolateId, isolate.rootLib!.id!, 'getDummyClass', []) as InstanceRef; + final result = + await service.getObject(isolateId, invokeResult.classRef!.id!) as Class; expect(result.id, startsWith('classes/')); - expect(result.name, equals('_DummyGenericSubClass')); - expect(result.isAbstract, equals(false)); - expect(result.isConst, equals(false)); - expect(result.typeParameters!.length, equals(1)); + expect(result.name, '_DummyClass'); + expect(result.isAbstract, false); + expect(result.isConst, false); + expect(result.isSealed, false); + expect(result.isMixinClass, false); + expect(result.isBaseClass, false); + expect(result.isInterfaceClass, false); + expect(result.isFinal, false); + expect(result.typeParameters, isNull); expect(result.library, isNotNull); expect(result.location, isNotNull); + expect(result.error, isNull); + expect(result.traceAllocations!, false); expect(result.superClass, isNotNull); - expect(result.interfaces!.length, isZero); + expect(result.superType, isNotNull); + expect(result.interfaces!.length, 0); + expect(result.mixin, isNull); + expect(result.fields!.length, 5); + expect(result.functions!.length, 10); + expect(result.subclasses!.length, 2); + final json = result.json!; + expect(json['_vmName'], startsWith('_DummyClass@')); + expect(json['_finalized'], true); + expect(json['_implemented'], false); + expect(json['_patch'], false); + }, + + // A generic class. + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final isolate = await service.getIsolate(isolateId); + // Use invoke to get a reference to an instance of [_DummyGenericSubClass]. + final invokeResult = await service.invoke( + isolateId, isolate.rootLib!.id!, 'getDummyGenericSubClass', []) + as InstanceRef; + final result = + await service.getObject(isolateId, invokeResult.classRef!.id!) as Class; + expect(result.id, startsWith('classes/')); + expect(result.name, '_DummyGenericSubClass'); + expect(result.isAbstract, false); + expect(result.isConst, false); + expect(result.isSealed, false); + expect(result.isMixinClass, false); + expect(result.isBaseClass, false); + expect(result.isInterfaceClass, false); + expect(result.isFinal, false); + expect(result.typeParameters!.length, 1); + expect(result.library, isNotNull); + expect(result.location, isNotNull); + expect(result.error, isNull); + expect(result.traceAllocations!, false); + expect(result.superClass, isNotNull); + expect(result.superType, isNotNull); + expect(result.interfaces!.length, 0); + expect(result.mixin, isNull); + expect(result.fields!.length, 0); + expect(result.functions!.length, 1); + expect(result.subclasses!.length, 0); final json = result.json!; expect(json['_vmName'], startsWith('_DummyGenericSubClass@')); - expect(json['_finalized'], equals(true)); - expect(json['_implemented'], equals(false)); - expect(json['_patch'], equals(false)); + expect(json['_finalized'], true); + expect(json['_implemented'], false); + expect(json['_patch'], false); + }, + + // A final class. + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final isolate = await service.getIsolate(isolateId); + // Use invoke to get a reference to an instance of [_DummyFinalClass]. + final invokeResult = await service + .invoke(isolateId, isolate.rootLib!.id!, 'getDummyFinalClass', []) + as InstanceRef; + final result = + await service.getObject(isolateId, invokeResult.classRef!.id!) as Class; + expect(result.id, startsWith('classes/')); + expect(result.name, '_DummyFinalClass'); + expect(result.isAbstract, false); + expect(result.isConst, false); + expect(result.isSealed, false); + expect(result.isMixinClass, false); + expect(result.isBaseClass, false); + expect(result.isInterfaceClass, false); + expect(result.isFinal, true); + expect(result.typeParameters, isNull); + expect(result.library, isNotNull); + expect(result.location, isNotNull); + expect(result.error, isNull); + expect(result.traceAllocations!, false); + expect(result.superClass, isNotNull); + expect(result.superType, isNotNull); + expect(result.interfaces!.length, 0); + expect(result.mixin, isNull); + expect(result.fields!.length, 0); + expect(result.functions!.length, 1); + expect(result.subclasses!.length, 0); + final json = result.json!; + expect(json['_vmName'], startsWith('_DummyFinalClass@')); + expect(json['_finalized'], true); + expect(json['_implemented'], false); + expect(json['_patch'], false); + }, + + // A sealed class. + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final isolate = await service.getIsolate(isolateId); + // Use invoke to get a reference to an instance of [_DummyInterfaceClass]. + final invokeResult = await service.invoke( + isolateId, isolate.rootLib!.id!, 'getDummyInterfaceClass', []) + as InstanceRef; + final derivedClass = + await service.getObject(isolateId, invokeResult.classRef!.id!) as Class; + final baseClassRef = derivedClass.superClass!; + final result = + await service.getObject(isolateId, baseClassRef.id!) as Class; + expect(result.id, startsWith('classes/')); + expect(result.name, '_DummySealedClass'); + expect(result.isAbstract, true); + expect(result.isConst, false); + expect(result.isSealed, true); + expect(result.isMixinClass, false); + expect(result.isBaseClass, false); + expect(result.isInterfaceClass, false); + expect(result.isFinal, false); + expect(result.typeParameters, isNull); + expect(result.library, isNotNull); + expect(result.location, isNotNull); + expect(result.error, isNull); + expect(result.traceAllocations!, false); + expect(result.superClass, isNotNull); + expect(result.superType, isNotNull); + expect(result.interfaces!.length, 0); + expect(result.mixin, isNull); + expect(result.fields!.length, 0); + expect(result.functions!.length, 1); + expect(result.subclasses!.length, 1); + final json = result.json!; + expect(json['_vmName'], startsWith('_DummySealedClass@')); + expect(json['_finalized'], true); + expect(json['_implemented'], false); + expect(json['_patch'], false); + }, + + // An interface class. + (VmService service, IsolateRef isolateRef) async { + final isolateId = isolateRef.id!; + final isolate = await service.getIsolate(isolateId); + // Use invoke to get a reference to an instance of [_DummyInterfaceClass]. + final invokeResult = await service.invoke( + isolateId, isolate.rootLib!.id!, 'getDummyInterfaceClass', []) + as InstanceRef; + final result = + await service.getObject(isolateId, invokeResult.classRef!.id!) as Class; + expect(result.id, startsWith('classes/')); + expect(result.name, '_DummyInterfaceClass'); + expect(result.isAbstract, false); + expect(result.isConst, false); + expect(result.isSealed, false); + expect(result.isMixinClass, false); + expect(result.isBaseClass, false); + expect(result.isInterfaceClass, true); + expect(result.isFinal, false); + expect(result.typeParameters, isNull); + expect(result.library, isNotNull); + expect(result.location, isNotNull); + expect(result.error, isNull); + expect(result.traceAllocations!, false); + expect(result.superClass, isNotNull); + expect(result.superType, isNotNull); + expect(result.interfaces!.length, 0); + expect(result.mixin, isNull); + expect(result.fields!.length, 0); + expect(result.functions!.length, 1); + expect(result.subclasses!.length, 0); + final json = result.json!; + expect(json['_vmName'], startsWith('_DummyInterfaceClass@')); + expect(json['_finalized'], true); + expect(json['_implemented'], false); + expect(json['_patch'], false); }, // invalid class. diff --git a/runtime/observatory/tests/service/get_version_rpc_test.dart b/runtime/observatory/tests/service/get_version_rpc_test.dart index 59d0c3d795f..f6297342bbb 100644 --- a/runtime/observatory/tests/service/get_version_rpc_test.dart +++ b/runtime/observatory/tests/service/get_version_rpc_test.dart @@ -12,7 +12,7 @@ var tests = [ final result = await vm.invokeRpcNoUpgrade('getVersion', {}); expect(result['type'], 'Version'); expect(result['major'], 4); - expect(result['minor'], 2); + expect(result['minor'], 3); expect(result['_privateMajor'], 0); expect(result['_privateMinor'], 0); }, diff --git a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart index d7edbdb9cef..be232920bf7 100644 --- a/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart +++ b/runtime/observatory_2/tests/service_2/get_version_rpc_test.dart @@ -12,7 +12,7 @@ var tests = [ final result = await vm.invokeRpcNoUpgrade('getVersion', {}); expect(result['type'], equals('Version')); expect(result['major'], equals(4)); - expect(result['minor'], equals(2)); + expect(result['minor'], equals(3)); expect(result['_privateMajor'], equals(0)); expect(result['_privateMinor'], equals(0)); }, diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h index 8d682c3383a..dc79b2afd46 100644 --- a/runtime/vm/compiler/frontend/kernel_translation_helper.h +++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h @@ -786,6 +786,16 @@ class ClassHelper { return (flags_ & Flag::kHasConstConstructor) != 0; } + bool is_sealed() const { return (flags_ & Flag::kIsSealed) != 0; } + + bool is_mixin_class() const { return (flags_ & Flag::kIsMixinClass) != 0; } + + bool is_base() const { return (flags_ & Flag::kIsBase) != 0; } + + bool is_interface() const { return (flags_ & Flag::kIsInterface) != 0; } + + bool is_final() const { return (flags_ & Flag::kIsFinal) != 0; } + NameIndex canonical_name_; TokenPosition start_position_ = TokenPosition::kNoSource; TokenPosition position_ = TokenPosition::kNoSource; diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc index c69551520df..6a043044619 100644 --- a/runtime/vm/kernel_loader.cc +++ b/runtime/vm/kernel_loader.cc @@ -1401,14 +1401,30 @@ void KernelLoader::LoadPreliminaryClass(ClassHelper* class_helper, } class_helper->SetJustRead(ClassHelper::kImplementedClasses); - if (class_helper->is_abstract()) klass->set_is_abstract(); - + if (class_helper->is_abstract()) { + klass->set_is_abstract(); + } if (class_helper->is_transformed_mixin_application()) { klass->set_is_transformed_mixin_application(); } if (class_helper->has_const_constructor()) { klass->set_is_const(); } + if (class_helper->is_sealed()) { + klass->set_is_sealed(); + } + if (class_helper->is_mixin_class()) { + klass->set_is_mixin_class(); + } + if (class_helper->is_base()) { + klass->set_is_base_class(); + } + if (class_helper->is_interface()) { + klass->set_is_interface_class(); + } + if (class_helper->is_final()) { + klass->set_is_final(); + } } void KernelLoader::LoadClass(const Library& library, diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 3fca239e95a..f4375f966d9 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -5455,6 +5455,31 @@ void Class::set_is_transformed_mixin_application() const { set_state_bits(TransformedMixinApplicationBit::update(true, state_bits())); } +void Class::set_is_sealed() const { + ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter()); + set_state_bits(SealedBit::update(true, state_bits())); +} + +void Class::set_is_mixin_class() const { + ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter()); + set_state_bits(MixinClassBit::update(true, state_bits())); +} + +void Class::set_is_base_class() const { + ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter()); + set_state_bits(BaseClassBit::update(true, state_bits())); +} + +void Class::set_is_interface_class() const { + ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter()); + set_state_bits(InterfaceClassBit::update(true, state_bits())); +} + +void Class::set_is_final() const { + ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter()); + set_state_bits(FinalBit::update(true, state_bits())); +} + void Class::set_is_fields_marked_nullable() const { ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter()); set_state_bits(FieldsMarkedNullableBit::update(true, state_bits())); diff --git a/runtime/vm/object.h b/runtime/vm/object.h index cbac8eeb63f..c70527afcd8 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h @@ -1643,6 +1643,23 @@ class Class : public Object { } void set_is_transformed_mixin_application() const; + bool is_sealed() const { return SealedBit::decode(state_bits()); } + void set_is_sealed() const; + + bool is_mixin_class() const { return MixinClassBit::decode(state_bits()); } + void set_is_mixin_class() const; + + bool is_base_class() const { return BaseClassBit::decode(state_bits()); } + void set_is_base_class() const; + + bool is_interface_class() const { + return InterfaceClassBit::decode(state_bits()); + } + void set_is_interface_class() const; + + bool is_final() const { return FinalBit::decode(state_bits()); } + void set_is_final() const; + bool is_fields_marked_nullable() const { return FieldsMarkedNullableBit::decode(state_bits()); } @@ -1904,6 +1921,11 @@ class Class : public Object { kIsLoadedBit, kHasPragmaBit, kImplementsFinalizableBit, + kSealedBit, + kMixinClassBit, + kBaseClassBit, + kInterfaceClassBit, + kFinalBit, }; class ConstBit : public BitField {}; class ImplementedBit : public BitField {}; @@ -1928,6 +1950,12 @@ class Class : public Object { class HasPragmaBit : public BitField {}; class ImplementsFinalizableBit : public BitField {}; + class SealedBit : public BitField {}; + class MixinClassBit : public BitField {}; + class BaseClassBit : public BitField {}; + class InterfaceClassBit + : public BitField {}; + class FinalBit : public BitField {}; void set_name(const String& value) const; void set_user_name(const String& value) const; diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc index d750c48854c..085611401f3 100644 --- a/runtime/vm/object_service.cc +++ b/runtime/vm/object_service.cc @@ -127,6 +127,11 @@ void Class::PrintJSONImpl(JSONStream* stream, bool ref) const { } jsobj.AddProperty("abstract", is_abstract()); jsobj.AddProperty("const", is_const()); + jsobj.AddProperty("isSealed", is_sealed()); + jsobj.AddProperty("isMixinClass", is_mixin_class()); + jsobj.AddProperty("isBaseClass", is_base_class()); + jsobj.AddProperty("isInterfaceClass", is_interface_class()); + jsobj.AddProperty("isFinal", is_final()); jsobj.AddProperty("_finalized", is_finalized()); jsobj.AddProperty("_implemented", is_implemented()); jsobj.AddProperty("_patch", false); diff --git a/runtime/vm/service.h b/runtime/vm/service.h index b4496d3b920..cc2baf6fdda 100644 --- a/runtime/vm/service.h +++ b/runtime/vm/service.h @@ -17,7 +17,7 @@ namespace dart { #define SERVICE_PROTOCOL_MAJOR_VERSION 4 -#define SERVICE_PROTOCOL_MINOR_VERSION 2 +#define SERVICE_PROTOCOL_MINOR_VERSION 3 class Array; class EmbedderServiceHandler; diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md index cc81096a02a..74c2f404277 100644 --- a/runtime/vm/service/service.md +++ b/runtime/vm/service/service.md @@ -1,8 +1,8 @@ -# Dart VM Service Protocol 4.2 +# Dart VM Service Protocol 4.3 > Please post feedback to the [observatory-discuss group][discuss-list] -This document describes of _version 4.2_ of the Dart VM Service Protocol. This +This document describes of _version 4.3_ of the Dart VM Service Protocol. This protocol is used to communicate with a running Dart Virtual Machine. To use the Service Protocol, start the VM with the *--observe* flag. @@ -1887,6 +1887,21 @@ class Class extends Object { // Is this a const class? bool const; + // Is this a sealed class? + bool isSealed; + + // Is this a mixin class? + bool isMixinClass; + + // Is this a base class? + bool isBaseClass; + + // Is this an interface class? + bool isInterfaceClass; + + // Is this a final class? + bool isFinal; + // Are allocations of this class being traced? bool traceAllocations; @@ -4491,5 +4506,6 @@ version | comments 4.0 | Added `Record` and `RecordType` `InstanceKind`s, added a deprecation notice to the `decl` property of `BoundField`, added `name` property to `BoundField`, added a deprecation notice to the `parentListIndex` property of `InboundReference`, changed the type of the `parentField` property of `InboundReference` from `@Field` to `@Field\|string\|int`, added a deprecation notice to the `parentListIndex` property of `RetainingObject`, changed the type of the `parentField` property of `RetainingObject` from `string` to `string\|int`, removed the deprecated `timeSpan` property from `CpuSamples`, and removed the deprecated `timeSpan` property from `CpuSamplesEvent`. 4.1 | Added optional `includeSubclasses` and `includeImplementers` parameters to `getInstances`. 4.2 | Added `getInstancesAsList` RPC. +4.3 | Added `isSealed`, `isMixinClass`, `isBaseClass`, `isInterfaceClass`, and `isFinal` properties to `Class`. [discuss-list]: https://groups.google.com/a/dartlang.org/forum/#!forum/observatory-discuss