Shared structs stage 2 feature set
Shu-yu Guo
Ron Buckton
April 2024 TC39
Unshared structs
Unshared structs
struct Box {
// maybe should be named init?
constructor(x) { this.x = x; }
rizz() { }
x;
}
let box = new Box();
box.x = 42; // x is declared
// structs are sealed
assertThrows(() => { box.y = 8.8; });
assertThrows(() => { box.__proto__ = {} });
// methods are non-generic on receiver
assertThrows(() => box.rizz.call({}));
Shared structs
Same restrictions as unshared structs, plus:
Realm-local prototypes
// in main
shared struct SharedPoint extends B {
// realm-local either by default or
<hand-wavy realm-local proto mechanism>
x;
y;
where() {}
}
let p = new SharedPoint;
p.x = 0;
p.y = 1;
Object.getPrototypeOf(p).where =
function() { console.log("in main"); };
p.where(); // in main
worker.postMessage(p);
// in worker
onmessage = (p) => {
// undefined is not a function
assertThrows(() => p.where());
Object.getPrototypeOf(p).where =
function() { console.log("in main"); };
p.where(); // in worker
}
// in main
...
p.where() // still "in main"
The Correlation Problem
// structs.js
shared struct SharedPoint {
<hand-wavy realm-local proto mechanism>
}
SharedPoint.prototype = { foo() {} };
// worker A
import { SharedPoint } from 'structs.js'
workerB.postMessage(new SharedPoint);
// worker B
import { SharedPoint } from 'structs.js'
// Oops, 2 different SharedPoints!
onmessage = (p) => { p.foo(); }
Shared heap
Worker A
Worker B
SharedPoint shape A | |
prototype | TLS key A |
TLS key B | { foo } |
TLS key A | { foo } |
SharedPoint shape B | |
prototype | TLS key B |
The Correlation Problem
Design constraints
Proposal
// structs.js
shared struct SharedPoint {
// strawperson
<hand-wavy correlation mechanism>
<hand-wavy realm-local proto mechanism>
}
SharedPoint.prototype = { foo() {} }
// worker A
import { SharedPoint } from 'structs.js'
workerB.postMessage(new SharedPoint);
// worker B
import { SharedPoint } from 'structs.js'
// works
onmessage = (p) => { p.foo(); }
Shared heap
Worker A
Worker B
SharedPoint shape registered | |
prototype | TLS key |
TLS key | { foo } |
TLS key | { foo } |
Semantics
Communication channel?
This registry is not a communication channel IMO
Bundler guidance
Shared fixed-length arrays
Shared fixed-length arrays
// main.js
let sharedArray = new SharedFixedArray(10);
assert(sharedArray.length === 10);
let worker = new Worker('worker.js');
worker.postMessage({ sharedArray });
sharedArray[0] = "main";
console.log(sharedArray[0]);
// worker.js
onmessage = function(e) {
let sharedArray = e.data.sharedArray;
sharedArray[0] = "worker";
console.log(sharedArray[0]);
};
Mutex
Condition
Memory model
One-way disablement
globalThis.disableSharedMemory() // hand-wavy
Wasm
Will move only as fast as the shared WasmGC proposal