[vm/shared] Perform deeply-immutable initialization runtime check.

When an initial value is assigned into a class tagged as deeply-immutable, perform runtime check of that value. This is needed to support proper initialization of the closures as part of deeply-immutable classes.

BUG=https://github.com/dart-lang/sdk/issues/61962
TEST=run_isolate_group_run_test

Change-Id: I550746c0d22ca06ffb89959e8384cc9e6d28d590
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/468200
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
Alexander Aprelev
2026-01-14 08:42:22 -08:00
committed by Commit Queue
parent fc3ce5a24e
commit eb75c53d95
58 changed files with 2469 additions and 1743 deletions
@@ -141,6 +141,8 @@ class BytecodeGenerator extends RecursiveVisitor {
int maxSourcePosition = 0;
Member? dynModuleEntryPoint;
bool isInDeeplyImmutableClass = false;
BytecodeGenerator(
ast.Component component,
CoreTypes coreTypes,
@@ -196,6 +198,9 @@ class BytecodeGenerator extends RecursiveVisitor {
@override
void visitClass(Class node) {
isInDeeplyImmutableClass =
pragmaParser.parsedPragmas<ParsedVmDeeplyImmutablePragma>(
node.annotations).isNotEmpty;
startMembers();
visitList(node.constructors, this);
visitList(node.procedures, this);
@@ -323,6 +328,11 @@ class BytecodeGenerator extends RecursiveVisitor {
flags |= ClassDeclaration.hasAnnotationsFlag;
if (annotations.hasPragma) {
flags |= ClassDeclaration.hasPragmaFlag;
if (pragmaParser
.parsedPragmas<ParsedVmDeeplyImmutablePragma>(cls.annotations)
.isNotEmpty) {
flags |= ClassDeclaration.isDeeplyImmutableFlag;
}
}
}
@@ -1046,6 +1056,10 @@ class BytecodeGenerator extends RecursiveVisitor {
? ffiLibraryIndex.getTopLevelProcedure('dart:ffi', '_ffiCall')
: null;
late Procedure ensureDeeplyImmutable =
libraryIndex.getTopLevelProcedure('dart:_internal',
'_ensureDeeplyImmutable');
// Selector for implicit dynamic calls 'foo(...)' where
// variable 'foo' has type 'dynamic'.
late final implicitCallName = Name('implicit:call');
@@ -1136,6 +1150,12 @@ class BytecodeGenerator extends RecursiveVisitor {
_generateNode(initializer);
final int cpIndex = cp.addInstanceField(field);
if (isInDeeplyImmutableClass) {
// TODO(dartbug.com/61078): Use static type to avoid runtime check.
_genDirectCall(
ensureDeeplyImmutable, objectTable.getArgDescHandle(1), 1);
}
asm.emitStoreFieldTOS(cpIndex);
initializedFields.add(field);
+4
View File
@@ -100,6 +100,7 @@ class ClassDeclaration extends BytecodeDeclaration {
static const isBaseClassFlag = 1 << 11;
static const isInterfaceFlag = 1 << 12;
static const isFinalFlag = 1 << 13;
static const isDeeplyImmutableFlag = 1 << 14;
ObjectHandle? name;
final int flags;
@@ -200,6 +201,9 @@ class ClassDeclaration extends BytecodeDeclaration {
if ((flags & hasPragmaFlag) != 0) {
sb.write(', has-pragma');
}
if ((flags & isDeeplyImmutableFlag) != 0) {
sb.write(', deeply-immutable');
}
if ((flags & hasSourcePositionsFlag) != 0) {
sb.write(', pos = $position, end-pos = $endPosition');
}