Skip to content

Commit

Permalink
Merge pull request #7444 from Agoric/markm-state-proto-2
Browse files Browse the repository at this point in the history
refactor: stateShape causes accessor sharing
  • Loading branch information
mergify[bot] authored Apr 18, 2023
2 parents c966474 + f264d43 commit 52d161b
Showing 1 changed file with 62 additions and 33 deletions.
95 changes: 62 additions & 33 deletions packages/swingset-liveslots/src/virtualObjectManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,15 @@ export const makeVirtualObjectManager = (
} = options;

let facetNames; // undefined or a list of strings
const statePrototype = {}; // Not frozen yet
const stateToBaseRefMap = new WeakMap();

const getBaseRef = state => {
const baseRef = stateToBaseRefMap.get(state);
baseRef !== undefined ||
Fail`state accessors can only be applied to state`;
return baseRef;
};

// 'multifaceted' tells us which API was used: define[Durable]Kind
// vs define[Durable]KindMulti. This function checks whether
Expand Down Expand Up @@ -818,9 +827,9 @@ export const makeVirtualObjectManager = (
}

/** @type {(prop: string) => void} */
let checkStateProperty = _prop => undefined;
let checkStateProperty = _prop => {};
/** @type {(value: any, prop: string) => void} */
let checkStatePropertyValue = (_value, _prop) => undefined;
let checkStatePropertyValue = (_value, _prop) => {};
if (stateShape) {
checkStateProperty = prop => {
hasOwn(stateShape, prop) ||
Expand Down Expand Up @@ -856,39 +865,59 @@ export const makeVirtualObjectManager = (
// * when state.prop is written, invoking the setter
// This will cause a syscall.vatstoreGet only once per crank.

const makeState = baseRef => {
const state = {};
for (const prop of getOwnPropertyNames(dataCache.get(baseRef).capdatas)) {
checkStateProperty(prop);
defineProperty(state, prop, {
get: () => {
const { valueMap, capdatas } = dataCache.get(baseRef);
if (!valueMap.has(prop)) {
const value = harden(unserialize(capdatas[prop]));
checkStatePropertyValue(value, prop);
valueMap.set(prop, value);
}
return valueMap.get(prop);
},
set: value => {
const makeFieldDescriptor = prop => {
return harden({
get() {
const baseRef = getBaseRef(this);
const { valueMap, capdatas } = dataCache.get(baseRef);
if (!valueMap.has(prop)) {
const value = harden(unserialize(capdatas[prop]));
checkStatePropertyValue(value, prop);
const capdata = serialize(value);
assertAcceptableSyscallCapdataSize([capdata]);
if (isDurable) {
insistDurableCapdata(vrm, prop, capdata, true);
}
const record = dataCache.get(baseRef); // mutable
const oldSlots = record.capdatas[prop].slots;
const newSlots = capdata.slots;
vrm.updateReferenceCounts(oldSlots, newSlots);
record.capdatas[prop] = capdata; // modify in place ..
record.valueMap.set(prop, value);
dataCache.set(baseRef, record); // .. but mark as dirty
},
enumerable: true,
});
valueMap.set(prop, value);
}
return valueMap.get(prop);
},
set(value) {
const baseRef = getBaseRef(this);
checkStatePropertyValue(value, prop);
const capdata = serialize(value);
assertAcceptableSyscallCapdataSize([capdata]);
if (isDurable) {
insistDurableCapdata(vrm, prop, capdata, true);
}
const record = dataCache.get(baseRef); // mutable
const oldSlots = record.capdatas[prop].slots;
const newSlots = capdata.slots;
vrm.updateReferenceCounts(oldSlots, newSlots);
record.capdatas[prop] = capdata; // modify in place ..
record.valueMap.set(prop, value);
dataCache.set(baseRef, record); // .. but mark as dirty
},
enumerable: true,
configurable: false,
});
};

if (stateShape !== undefined) {
for (const prop of ownKeys(stateShape)) {
defineProperty(statePrototype, prop, makeFieldDescriptor(prop));
}
}

harden(statePrototype);

const makeState = baseRef => {
const state = { __proto__: statePrototype };
if (stateShape === undefined) {
for (const prop of ownKeys(dataCache.get(baseRef).capdatas)) {
assert(typeof prop === 'string');
checkStateProperty(prop);
defineProperty(state, prop, makeFieldDescriptor(prop));
}
}
return harden(state);
harden(state);
stateToBaseRefMap.set(state, baseRef);
return state;
};

// More specifically, behavior functions receive a "context"
Expand Down

0 comments on commit 52d161b

Please sign in to comment.