Skip to content

Require that captured variables are marked with vm:shared #4282

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 5, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 37 additions & 12 deletions working/333 - shared memory multithreading/proposal.md
Original file line number Diff line number Diff line change
Expand Up @@ -509,17 +509,23 @@ initialization it complete.
In the _shared **everything** multithreading_ shared fields can be allowed to
contain anything - including instances of mutable Dart classes. However,
initially I propose to limit shared fields by allowing only _trivially shareable
types_. These types are those which already can pass through
`SendPort` without copying:

- strings;
- numbers;
- [deeply immutable][] types;
- builtin implementations of `SendPort` and `TypedData`;
- tear-offs of static methods;
- closures which capture variables of trivially shareable types;
types_, which include:

Sharing of these types don't break isolate boundaries.
- Objects which do not contain mutable state and thus can already pass through
`SendPort` without copying:
- strings;
- numbers;
- instances of [deeply immutable][] types;
- instances of internal implementation of `SendPort`;
- tear-offs of static methods;
- compile time constants;
- Objects which contain non-structural (binary) mutable state:
- `TypedData`
- `Struct` instances
- Closures which capture variables which are annotated with `@pragma('vm:shared')`
and are of trivially shareable types;

Sharing of these types does not break isolate boundaries.

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

Expand Down Expand Up @@ -553,6 +559,12 @@ Sharing of these types don't break isolate boundaries.
> Furthermore, shared fields of `int` and `double` types are allowed to exhibit
> _tearing_ on 32-bit platforms.

> [!NOTE]
>
> There is no static type marker for a trivially shareable closure. For convenience
> reasons we should allow writing `@pragma('vm:shared') void Function() foo;` but
> will have to check shareability in runtime when such variable is initialized.

## Shared Isolates

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

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


```dart
// This code is okay because `int` is trivially shareable.
// This code is okay because the variable is annotated and `int` is
// trivially shareable.
@pragma('vm:shared')
int counter = 0;
NativeCallable.shared(() {
counter++;
});

// This code causes a runtime error because `counter` is not not
// annotated with vm:shared pragma.
int counter = 0;
NativeCallable.shared(() {
counter++;
});

// This code is not okay because `List<T>` is not trivially shareable.
@pragma('vm:shared')
List<int> list = [];
NativeCallable.shared(() {
list.add(1);
Expand Down
Loading