| # Deeply immutable instances and types | 
 |  | 
 | The Dart VM has a concept of deeply immutable instances. | 
 |  | 
 | Deeply immutable instances can be shared across isolates within the same group. | 
 |  | 
 | ## Deeply immutable types | 
 |  | 
 | A deeply immutable type is a type for which all instances that have this type are deeply immutable. | 
 |  | 
 | This is useful for static checks on classes annotated `@pragma('vm:deeply-immutable')`. | 
 | All the instance fields of such classes must have a deeply immutable type. | 
 |  | 
 | A list of immutable types: | 
 |  | 
 | * `bool` | 
 | * `double` | 
 | * `int` | 
 | * `Null` | 
 | * `String` | 
 | * `Float32x4` | 
 | * `Float64x2` | 
 | * `Int32x4` | 
 | * `Pointer` | 
 | * classes annotated with `@pragma('vm:deeply-immutable')` | 
 | * type parameters bound by a deeply immutable type | 
 |  | 
 | ## Deeply immutable instances without a deeply immutable type | 
 |  | 
 | In addition to instances from deeply immutable types, | 
 | instances can also be deeply immutable while their type is not deeply immutable: | 
 |  | 
 | * `SendPort` (implemented externally `package:isolate`, so cannot be `final` https://github.com/dart-lang/sdk/issues/54885#issuecomment-1967329435) | 
 | * `Capability` (has `SendPort` as subtype so cannot be `final`) | 
 | * `RegExp` (can be implemented externally, not `final`) | 
 | * `StackTrace` (can be implemented externally, not `final`) | 
 | * `Type` (can be implemented externally, not `final`) | 
 | * const object (the class can be deeply immutable) | 
 |  | 
 | This means users cannot mark classes with fields typed with these types as `@pragma('vm:deeply-immutable')`. | 
 |  | 
 | ## Shallowly immutable instances | 
 |  | 
 | The VM also has shallow immutability. | 
 |  | 
 | * unmodifiable typed data views (the backing view might not be immutable) | 
 | * closures (the context might not be empty) | 
 |  | 
 | ## Implementation details | 
 |  | 
 | ### Deeply and shallowly immutable instances | 
 |  | 
 | The `UntaggedObject::ImmutableBit` tracks whether an instance is deeply or shallowly immutable at runtime. | 
 | For shallow immutable objects, the VM needs to know the layout and what to check when to check for to check deep immutability at runtime. | 
 |  | 
 | ### Deeply immutable types | 
 |  | 
 | The `Class::is_deeply_immutable` tracks whether all instances of a class are deeply immutable. | 
 |  | 
 | This bit can be set in two ways: | 
 |  | 
 | 1. For recognized classes, in the VM initialization. | 
 | 2. For classes with a Dart source, with the `vm:deeply-immutable` pragma. | 
 |  | 
 | The `vm:deeply-immutable` pragma is added to classes of which their _type_ is deeply immutable. | 
 |  | 
 | This puts the following restrictions on these classes: | 
 |  | 
 | 1. All instance fields must | 
 |    1. have a deeply immutable type, | 
 |    2. be final, and | 
 |    3. be non-late. | 
 | 2. The class must be `final` or `sealed`. | 
 |    This ensures no non-deeply-immutable subtypes are added by external code. | 
 | 3. All subtypes must be deeply immutable. | 
 |    This ensures 1.1. can be trusted. | 
 | 4. The super type must be deeply immutable (except for Object). | 
 |  | 
 | These restructions are enforced by [DeeplyImmutableValidator](../../pkg/vm/lib/transformations/ffi/deeply_immutable.dart). |