Skip to content

Commit d1e361e

Browse files
authored
Require that captured variables are marked with vm:shared (#4282)
* Require that captured variables are marked with vm:shared * Split the list of trivially shareable types in groups * Reformat examples
1 parent 5df4fc6 commit d1e361e

File tree

1 file changed

+37
-12
lines changed

1 file changed

+37
-12
lines changed

working/333 - shared memory multithreading/proposal.md

+37-12
Original file line numberDiff line numberDiff line change
@@ -509,17 +509,23 @@ initialization it complete.
509509
In the _shared **everything** multithreading_ shared fields can be allowed to
510510
contain anything - including instances of mutable Dart classes. However,
511511
initially I propose to limit shared fields by allowing only _trivially shareable
512-
types_. These types are those which already can pass through
513-
`SendPort` without copying:
514-
515-
- strings;
516-
- numbers;
517-
- [deeply immutable][] types;
518-
- builtin implementations of `SendPort` and `TypedData`;
519-
- tear-offs of static methods;
520-
- closures which capture variables of trivially shareable types;
512+
types_, which include:
521513

522-
Sharing of these types don't break isolate boundaries.
514+
- Objects which do not contain mutable state and thus can already pass through
515+
`SendPort` without copying:
516+
- strings;
517+
- numbers;
518+
- instances of [deeply immutable][] types;
519+
- instances of internal implementation of `SendPort`;
520+
- tear-offs of static methods;
521+
- compile time constants;
522+
- Objects which contain non-structural (binary) mutable state:
523+
- `TypedData`
524+
- `Struct` instances
525+
- Closures which capture variables which are annotated with `@pragma('vm:shared')`
526+
and are of trivially shareable types;
527+
528+
Sharing of these types does not break isolate boundaries.
523529

524530
[deeply immutable]: https://github.com/dart-lang/sdk/blob/bb59b5c72c52369e1b0d21940008c4be7e6d43b3/runtime/docs/deeply_immutable.md
525531

@@ -553,6 +559,12 @@ Sharing of these types don't break isolate boundaries.
553559
> Furthermore, shared fields of `int` and `double` types are allowed to exhibit
554560
> _tearing_ on 32-bit platforms.
555561
562+
> [!NOTE]
563+
>
564+
> There is no static type marker for a trivially shareable closure. For convenience
565+
> reasons we should allow writing `@pragma('vm:shared') void Function() foo;` but
566+
> will have to check shareability in runtime when such variable is initialized.
567+
556568
## Shared Isolates
557569

558570
Lets take another look at the following example:
@@ -678,16 +690,29 @@ associated with that:
678690

679691
In _shared **everything** multithreading_ world `callback` can be allowed to
680692
capture arbitrary state, however in _shared **native memory** multithreading_
681-
this state has to be restricted to trivially shareable types:
693+
this state has to be restricted to trivially shareable types. To make it
694+
completely unambigious we impose an additional requirement that all variables
695+
captured by a closure will need to be annotated with `@pragma('vm:shared')`:
696+
682697

683698
```dart
684-
// This code is okay because `int` is trivially shareable.
699+
// This code is okay because the variable is annotated and `int` is
700+
// trivially shareable.
701+
@pragma('vm:shared')
702+
int counter = 0;
703+
NativeCallable.shared(() {
704+
counter++;
705+
});
706+
707+
// This code causes a runtime error because `counter` is not not
708+
// annotated with vm:shared pragma.
685709
int counter = 0;
686710
NativeCallable.shared(() {
687711
counter++;
688712
});
689713
690714
// This code is not okay because `List<T>` is not trivially shareable.
715+
@pragma('vm:shared')
691716
List<int> list = [];
692717
NativeCallable.shared(() {
693718
list.add(1);

0 commit comments

Comments
 (0)