Skip to content

Commit

Permalink
refactor: stateShape causes accessor sharing
Browse files Browse the repository at this point in the history
  • Loading branch information
erights committed Apr 18, 2023
1 parent c583f3f commit ea21995
Showing 1 changed file with 43 additions and 37 deletions.
80 changes: 43 additions & 37 deletions packages/swingset-liveslots/src/virtualObjectManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { assert, Fail } from '@agoric/assert';
import { assertPattern, mustMatch } from '@agoric/store';
import { defendPrototype, defendPrototypeKit } from '@endo/exo/tools.js';
import { Far, hasOwnPropertyOf, passStyleOf } from '@endo/marshal';
import { Far, passStyleOf } from '@endo/marshal';
import { Nat } from '@endo/nat';
import { parseVatSlot, makeBaseRef } from './parseVatSlots.js';
import { enumerateKeysWithPrefix } from './vatstore-iterators.js';
Expand All @@ -13,7 +13,7 @@ import { assessFacetiousness } from './facetiousness.js';

/** @template T @typedef {import('@agoric/vat-data').DefineKindOptions<T>} DefineKindOptions */

const { defineProperty, getOwnPropertyNames } = Object;
const { hasOwn, defineProperty, getOwnPropertyNames } = Object;
const { ownKeys } = Reflect;
const { quote: q } = assert;

Expand Down Expand Up @@ -742,6 +742,7 @@ export const makeVirtualObjectManager = (
} = options;

let facetNames; // undefined or a list of strings
const statePrototype = {}; // Not frozen yet

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

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 =>
hasOwnPropertyOf(stateShape, prop) ||
Fail`State must only have fields described by stateShape: ${q(
ownKeys(stateShape),
)}`;
checkStateProperty = prop => {
hasOwn(stateShape, prop) ||
Fail`State must only have fields described by stateShape: ${q(
ownKeys(stateShape),
)}`;
};
checkStatePropertyValue = (value, prop) => {
checkStateProperty(prop);
mustMatch(value, stateShape[prop]);
Expand Down Expand Up @@ -854,37 +856,41 @@ export const makeVirtualObjectManager = (
// * when state.prop is written, invoking the setter
// This will cause a syscall.vatstoreGet only once per crank.

const makeFieldDescriptor = (prop, baseRef) => {
return harden({
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 => {
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,
});
};

const makeState = baseRef => {
const state = {};
const state = { __proto__: statePrototype };
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 => {
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,
});
defineProperty(state, prop, makeFieldDescriptor(prop, baseRef));
}
return harden(state);
};
Expand Down

0 comments on commit ea21995

Please sign in to comment.