Skip to content

Commit

Permalink
feat: optional TypeArrays remapping in realm (#447)
Browse files Browse the repository at this point in the history
  • Loading branch information
dejang authored Jan 29, 2024
1 parent 13f6999 commit ba7c125
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 107 deletions.
69 changes: 42 additions & 27 deletions packages/near-membrane-base/src/__tests__/intrinsics.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,13 @@ const ESGlobalKeys = [
// *** 19.3 Constructor Properties of the Global Object
// 'AggregateError', // Reflective
// 'Array', // Reflective
// 'ArrayBuffer', // Remapped
'BigInt',
// 'BigInt64Array', // Remapped
// 'BigUint64Array', // Remapped
'Boolean',
// 'DataView', // Remapped
// 'Date', // Remapped
// 'Error', // Reflective
// 'EvalError', // Reflective
'FinalizationRegistry',
// 'Float32Array', // Remapped
// 'Float64Array', // Remapped
// 'Function', // dangerous & Reflective
// 'Int8Array', // Remapped
// 'Int16Array', // Remapped
// 'Int32Array', // Remapped
// 'Map', // Remapped
'Number',
// 'Object', // Reflective
Expand All @@ -56,15 +47,10 @@ const ESGlobalKeys = [
// 'ReferenceError', // Reflective
'RegExp',
// 'Set', // Remapped
// 'SharedArrayBuffer', // Remapped
'String',
'Symbol',
// 'SyntaxError', // Reflective
// 'TypeError', // Reflective
// 'Uint8Array', // Remapped
// 'Uint8ClampedArray', // Remapped
// 'Uint16Array', // Remapped
// 'Uint32Array', // Remapped
// 'URIError', // Reflective
// 'WeakMap', // Remapped
// 'WeakSet', // Remapped
Expand Down Expand Up @@ -102,28 +88,31 @@ const ReflectiveIntrinsicObjectNames = [
];

const RemappedIntrinsicObjectNames = [
'ArrayBuffer',
'Atomics',
'Date',
'Intl',
'Map',
'Promise',
'Set',
'WeakMap',
'WeakSet',
];

const TypedAraysInstrinsics = [
'ArrayBuffer',
'BigInt64Array',
'BigUint64Array',
'DataView',
'Date',
'Float32Array',
'Float64Array',
'Int16Array',
'Int32Array',
'Int8Array',
'Intl',
'Map',
'Promise',
'Set',
'SharedArrayBuffer',
'Uint16Array',
'Uint32Array',
'Uint8Array',
'Uint8ClampedArray',
'WeakMap',
'WeakSet',
];

describe('assignFilteredGlobalDescriptorsFromPropertyDescriptorMap', () => {
Expand Down Expand Up @@ -158,17 +147,18 @@ describe('assignFilteredGlobalDescriptorsFromPropertyDescriptorMap', () => {
}
});
it('includes Remapped ES intrinsics', () => {
expect.assertions(RemappedIntrinsicObjectNames.length);
const remappedObjectNames = [...RemappedIntrinsicObjectNames, ...TypedAraysInstrinsics];
expect.assertions(remappedObjectNames.length);

const shape = RemappedIntrinsicObjectNames.reduce((accum, key) => {
const shape = remappedObjectNames.reduce((accum, key) => {
(accum as any)[key] = (globalThis as any)[key];
return accum;
}, {});
const descs = assignFilteredGlobalDescriptorsFromPropertyDescriptorMap(
{},
Object.getOwnPropertyDescriptors(shape)
);
for (const key of RemappedIntrinsicObjectNames) {
for (const key of remappedObjectNames) {
expect(descs[key]).toBeDefined();
}
});
Expand All @@ -186,6 +176,22 @@ describe('assignFilteredGlobalDescriptorsFromPropertyDescriptorMap', () => {
writable: true,
});
});
it('should not remap TypedArrays when flag is false', () => {
expect.assertions(RemappedIntrinsicObjectNames.length);

const shape = RemappedIntrinsicObjectNames.reduce((accum, key) => {
(accum as any)[key] = (globalThis as any)[key];
return accum;
}, {});
const descs = assignFilteredGlobalDescriptorsFromPropertyDescriptorMap(
{},
Object.getOwnPropertyDescriptors(shape),
false
);
for (const key of RemappedIntrinsicObjectNames) {
expect(descs[key]).toBeDefined();
}
});
});

describe('getFilteredGlobalOwnKeys', () => {
Expand Down Expand Up @@ -214,19 +220,28 @@ describe('getFilteredGlobalOwnKeys', () => {
}
});
it('includes Remapped ES intrinsics', () => {
const shape = RemappedIntrinsicObjectNames.reduce((accum, key) => {
const remappedObjectNames = [...RemappedIntrinsicObjectNames, ...TypedAraysInstrinsics];
const shape = remappedObjectNames.reduce((accum, key) => {
(accum as any)[key] = (globalThis as any)[key];
return accum;
}, {});
const filteredOwnKeys = getFilteredGlobalOwnKeys(shape);
expect(filteredOwnKeys).toEqual(RemappedIntrinsicObjectNames);
expect(filteredOwnKeys).toEqual(remappedObjectNames);
});
it('should include non-ES built-ins', () => {
const filteredOwnKeys = getFilteredGlobalOwnKeys({
Foo: 1,
});
expect(filteredOwnKeys).toEqual(['Foo']);
});
it('should not remap TypedArrays when flag is false', () => {
const shape = RemappedIntrinsicObjectNames.reduce((accum, key) => {
(accum as any)[key] = (globalThis as any)[key];
return accum;
}, {});
const filteredOwnKeys = getFilteredGlobalOwnKeys(shape, false);
expect(filteredOwnKeys).toEqual(RemappedIntrinsicObjectNames);
});
});

describe('linkIntrinsics()', () => {
Expand Down
168 changes: 92 additions & 76 deletions packages/near-membrane-base/src/intrinsics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,81 +27,90 @@ import { VirtualEnvironment } from './environment';
* problematic, and requires a lot more work to guarantee that objects from both sides
* can be considered equivalents (without identity discontinuity).
*/
const ESGlobalKeys = [
// *** 19.1 Value Properties of the Global Object
'globalThis',
'Infinity',
'NaN',
'undefined',
function getESGlobalKeys(remapTypedArrays = true) {
const ESGlobalKeys = [
// *** 19.1 Value Properties of the Global Object
'globalThis',
'Infinity',
'NaN',
'undefined',

// *** 19.2 Function Properties of the Global Object
// 'eval', // dangerous & Reflective
'isFinite',
'isNaN',
'parseFloat',
'parseInt',
'decodeURI',
'decodeURIComponent',
'encodeURI',
'encodeURIComponent',
// *** 19.2 Function Properties of the Global Object
// 'eval', // dangerous & Reflective
'isFinite',
'isNaN',
'parseFloat',
'parseInt',
'decodeURI',
'decodeURIComponent',
'encodeURI',
'encodeURIComponent',

// *** 19.3 Constructor Properties of the Global Object
// 'AggregateError', // Reflective
// 'Array', // Reflective
// 'ArrayBuffer', // Remapped
'BigInt',
// 'BigInt64Array', // Remapped
// 'BigUint64Array', // Remapped
'Boolean',
// 'DataView', // Remapped
// 'Date', // Remapped
// 'Error', // Reflective
// 'EvalError', // Reflective
'FinalizationRegistry',
// 'Float32Array', // Remapped
// 'Float64Array', // Remapped
// 'Function', // dangerous & Reflective
// 'Int8Array', // Remapped
// 'Int16Array', // Remapped
// 'Int32Array', // Remapped
// 'Map', // Remapped
'Number',
// 'Object', // Reflective
// Allow blue `Promise` constructor to overwrite the Red one so that promises
// created by the `Promise` constructor or APIs like `fetch` will work.
// 'Promise', // Remapped
// 'Proxy', // Reflective
// 'RangeError', // Reflective
// 'ReferenceError', // Reflective
'RegExp',
// 'Set', // Remapped
// 'SharedArrayBuffer', // Remapped
'String',
'Symbol',
// 'SyntaxError', // Reflective
// 'TypeError', // Reflective
// 'Uint8Array', // Remapped
// 'Uint8ClampedArray', // Remapped
// 'Uint16Array', // Remapped
// 'Uint32Array', // Remapped
// 'URIError', // Reflective
// 'WeakMap', // Remapped
// 'WeakSet', // Remapped
'WeakRef',
// *** 19.3 Constructor Properties of the Global Object
// 'AggregateError', // Reflective
// 'Array', // Reflective
'BigInt',
'Boolean',
// 'Date', // Remapped
// 'Error', // Reflective
// 'EvalError', // Reflective
'FinalizationRegistry',
// 'Function', // dangerous & Reflective
// 'Map', // Remapped
'Number',
// 'Object', // Reflective
// Allow blue `Promise` constructor to overwrite the Red one so that promises
// created by the `Promise` constructor or APIs like `fetch` will work.
// 'Promise', // Remapped
// 'Proxy', // Reflective
// 'RangeError', // Reflective
// 'ReferenceError', // Reflective
'RegExp',
// 'Set', // Remapped

// *** 18.4 Other Properties of the Global Object
// 'Atomics', // Remapped
'JSON',
'Math',
'Reflect',
'String',
'Symbol',
// 'SyntaxError', // Reflective
// 'TypeError', // Reflective
// 'URIError', // Reflective
// 'WeakMap', // Remapped
// 'WeakSet', // Remapped
'WeakRef',

// *** Annex B
'escape',
'unescape',
// *** 18.4 Other Properties of the Global Object
// 'Atomics', // Remapped
'JSON',
'Math',
'Reflect',

// *** ECMA-402
// 'Intl', // Remapped
];
// *** Annex B
'escape',
'unescape',

// *** ECMA-402
// 'Intl', // Remapped
];

if (remapTypedArrays === false) {
ESGlobalKeys.push(
'ArrayBuffer',
'BigInt64Array',
'BigUint64Array',
'DataView',
'Float32Array',
'Float64Array',
'Int8Array',
'Int16Array',
'Int32Array',
'SharedArrayBuffer',
'Uint8Array',
'Uint8ClampedArray',
'Uint16Array',
'Uint32Array'
);
}
return ESGlobalKeys;
}

// These are foundational things that should never be wrapped but are equivalent
// @TODO: Revisit this list.
Expand All @@ -122,10 +131,10 @@ const ReflectiveIntrinsicObjectNames = [
'globalThis',
];

const ESGlobalsAndReflectiveIntrinsicObjectNames = toSafeArray([
...ESGlobalKeys,
...ReflectiveIntrinsicObjectNames,
]);
function getESGlobalsAndReflectiveIntrinsicObjectNames(remapTypedArrays = true) {
const ESGlobalKeys = getESGlobalKeys(remapTypedArrays);
return toSafeArray([...ESGlobalKeys, ...ReflectiveIntrinsicObjectNames]);
}

function getGlobalObjectOwnKeys(source: object): PropertyKey[] {
const ownKeys = ReflectOwnKeys(source);
Expand All @@ -140,8 +149,10 @@ function getGlobalObjectOwnKeys(source: object): PropertyKey[] {

export function assignFilteredGlobalDescriptorsFromPropertyDescriptorMap<
T extends PropertyDescriptorMap
>(descs: T, source: PropertyDescriptorMap): T {
>(descs: T, source: PropertyDescriptorMap, includeTypedArrays?: boolean): T {
const ownKeys = getGlobalObjectOwnKeys(source);
const ESGlobalsAndReflectiveIntrinsicObjectNames =
getESGlobalsAndReflectiveIntrinsicObjectNames(includeTypedArrays);
for (let i = 0, { length } = ownKeys; i < length; i += 1) {
const ownKey = ownKeys[i];
// Avoid overriding ECMAScript global names that correspond to
Expand All @@ -161,10 +172,15 @@ export function assignFilteredGlobalDescriptorsFromPropertyDescriptorMap<
return descs;
}

export function getFilteredGlobalOwnKeys(source: object): PropertyKey[] {
export function getFilteredGlobalOwnKeys(
source: object,
includeTypedArrays?: boolean
): PropertyKey[] {
const result: PropertyKey[] = [];
let resultOffset = 0;
const ownKeys = getGlobalObjectOwnKeys(source);
const ESGlobalsAndReflectiveIntrinsicObjectNames =
getESGlobalsAndReflectiveIntrinsicObjectNames(includeTypedArrays);
for (let i = 0, { length } = ownKeys; i < length; i += 1) {
const ownKey = ownKeys[i];
// Avoid overriding ECMAScript global names that correspond to global
Expand Down
11 changes: 9 additions & 2 deletions packages/near-membrane-dom/src/browser-realm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ function createIframeVirtualEnvironment(
instrumentation,
keepAlive = true,
liveTargetCallback,
remapTypedArrays,
signSourceCallback,
// eslint-disable-next-line prefer-object-spread
} = ObjectAssign({ __proto__: null }, providedOptions) as BrowserEnvironmentOptions;
Expand All @@ -92,7 +93,9 @@ function createIframeVirtualEnvironment(
const shouldUseDefaultGlobalOwnKeys =
typeof globalObjectShape !== 'object' || globalObjectShape === null;
if (shouldUseDefaultGlobalOwnKeys && defaultGlobalOwnKeys === null) {
defaultGlobalOwnKeys = filterWindowKeys(getFilteredGlobalOwnKeys(redWindow));
defaultGlobalOwnKeys = filterWindowKeys(
getFilteredGlobalOwnKeys(redWindow, remapTypedArrays)
);
}
let blueConnector = blueCreateHooksCallbackCache.get(blueRefs.document) as
| Connector
Expand Down Expand Up @@ -151,7 +154,11 @@ function createIframeVirtualEnvironment(
);
if (endowments) {
const filteredEndowments: PropertyDescriptorMap = {};
assignFilteredGlobalDescriptorsFromPropertyDescriptorMap(filteredEndowments, endowments);
assignFilteredGlobalDescriptorsFromPropertyDescriptorMap(
filteredEndowments,
endowments,
remapTypedArrays
);
removeWindowDescriptors(filteredEndowments);
env.remapProperties(blueRefs.window, filteredEndowments);
}
Expand Down
1 change: 1 addition & 0 deletions packages/near-membrane-dom/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ export interface BrowserEnvironmentOptions {
instrumentation?: Instrumentation;
keepAlive?: boolean;
liveTargetCallback?: LiveTargetCallback;
remapTypedArrays?: boolean;
signSourceCallback?: SignSourceCallback;
}
Loading

0 comments on commit ba7c125

Please sign in to comment.