Fixed layout objects
Shu-yu Guo (Google)
Co-champions: Asumu Takikawa (Igalia), Ron Buckton (Microsoft), Apple?
What's the big idea?
Structs are objects with fixed layout at construction, i.e. "closed" instead of "open"
Attractive for a bunch of things!
This proposal considers (1) and (2) to be requirements and seeks to be a minimal building block for others
Shared memory concurrency
But like, why via scary shared memory?
Let's use more cores!
Why not just SABs and Atomics?
If you want to shared structured data, you need wrappers. And wrappers have issues
Continuation of SAB story
Players have changed! It was game engines back then, now it's mega-apps. Higher-level shared memory concurrency is a power they need for a better product
TC39 drove SABs to be the shared foundation for shared memory between JS and Wasm. We succeeded.
Let's do it again at a higher abstraction level.
WasmGC Interop
Should we care? You betcha
Managed languages are coming via WasmGC!
Shades of interop
Interop here means "works with", not "exactly the same feature set in both WasmGC and JS"
| Wasm -> JS | JS -> Wasm |
Struct instances are usable and explainable | Goal of this proposal | Goal of future extensions |
Type reflection | Non-goal of TC39 | Non-goal of TC39 |
Too early for WasmGC?
WasmGC is in significant flux, so is it too early for this proposal?
No in the scoped sense: this proposal seeks to add common machinery compatible with all possible WasmGC futures, which all have managed memory (i.e. not in linear memory) structs with fixed layout
Yes in the general sense: other proposals needed to flesh out full WasmGC story
Other use cases should not be precluded, but are out of scope
MVP Proposal
Leitmotifs
MVP Proposal
Plain Structs
Shared Structs
Plain Structs
"use strict";
struct class Box {
constructor(x) { this.x = x; }
getX() { return x; }
x;
}
let box = new Box();
// x is declared
box.x = 42;
// Returns 42
box.getX();
// Structs are sealed
assertThrows(() => {
box.y = 8.8;
});
assertThrows(() => {
box.__proto__ = {}
});
Plain Structs
struct class C {
f1;
f2;
}
struct class D extends C {
f3;
f4;
}
// d always has all of f1,f2,f3,f4
// No partial initialization!
let d = new D;
Shared Structs
// main.js
"use strict";
shared struct class SharedBox {
constructor(x) { this.x = x; }
x;
}
let sharedBox = new SharedBox();
// x declared
sharedBox.x = 42;
assertThrows(() => {
// y not declared
sharedBox.y = 84;
});
Like plain structs, but with several restrictions as to be shareable among agents
Shared Structs
// Primitives okay
sharedBox.x = 42.42;
sharedBox.x = undefined;
sharedBox.x = "foo";
// [1,2,3] is a local object
assertThrows(() => {
sharedBox.x = [1,2,3];
});
// Touching [[Prototype]] throws
assertThrows(() => {
sharedBox.y;
});
Shared Structs
Can print any of the following interleavings:
main main
main worker
worker main
worker worker
// main.js
let worker = new Worker('worker.js');
worker.postMessage({ sharedBox });
sharedBox.x = "main";
console.log(sharedBox.x);
// worker.js
onmessage = function(e) {
let sharedBox = e.data.sharedBox;
sharedBox.x = "worker";
console.log(sharedBox.x);
};
Shared Structs
Atomics.store(sharedBox, 'x', 42);
// Returns 42
Atomics.load(sharedBox, 'x');
// Returns 42
Atomics.exchange(sharedBox, 'x', 84);
// Returns 84
Atomics.compareExchange(
sharedBox, 'x', 84, 42);
Aside: what are plain structs for?
But honestly, probably mainly future-proofing for future additions to both shared and plain structs, like sized fields for memory packing
Why don't fields have types?
More complex type system discussions definitely out of scope
Implementation guidance
The hard work for this MVP proposal is infrastructure retrofitting in engines for shared structs
Stuff that's hard: GC
Choosing separate heaps or unified heap
Stuff that's real hard: strings
First of all, it's funny to me that for all the high prestige problems in compilers and PLs around concurrency, the actual really hard thing is strings
Companion proposals needed
Namely, to explore the space of fixed layout objects for the following use cases:
with an eye on extending them in the future as use cases arise
Stage 1?