poe-code 14.0.81 → 14.0.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +933 -353
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-js/dist/chunks/{chunk-2LNBLFJ3.js → chunk-37V6Q4K3.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-ZSYBRZU6.js → chunk-PT7PBLVT.js} +764 -224
- package/packages/safe-js/dist/chunks/chunk-PT7PBLVT.js.map +7 -0
- package/packages/safe-js/dist/cli.js +2 -2
- package/packages/safe-js/dist/core.js +1 -1
- package/packages/safe-js/dist/index.js +2 -2
- package/packages/safe-js/dist/interp/error-prototypes.d.ts +3 -0
- package/packages/safe-js/dist/interp/error-prototypes.js +1 -0
- package/packages/safe-js/dist/interp/exceptions.d.ts +1 -0
- package/packages/safe-js/dist/interp/exceptions.js +39 -15
- package/packages/safe-js/dist/interp/float32-prototypes.d.ts +3 -0
- package/packages/safe-js/dist/interp/float32-prototypes.js +1 -0
- package/packages/safe-js/dist/interp/float32.d.ts +1 -0
- package/packages/safe-js/dist/interp/float32.js +12 -4
- package/packages/safe-js/dist/interp/globals/error.d.ts +2 -0
- package/packages/safe-js/dist/interp/globals/error.js +104 -4
- package/packages/safe-js/dist/interp/globals/float32array.d.ts +3 -2
- package/packages/safe-js/dist/interp/globals/float32array.js +371 -65
- package/packages/safe-js/dist/interp/globals/object-array.js +3 -3
- package/packages/safe-js/dist/interp/globals.d.ts +2 -0
- package/packages/safe-js/dist/interp/globals.js +8 -4
- package/packages/safe-js/dist/interp/host-bridge.js +4 -2
- package/packages/safe-js/dist/interp/instanceof.js +4 -3
- package/packages/safe-js/dist/interp/interpreter.js +2 -4
- package/packages/safe-js/dist/interp/iteration.js +15 -6
- package/packages/safe-js/dist/interp/object-model.js +27 -1
- package/packages/safe-js/dist/interp/values.js +59 -6
- package/packages/safe-js/dist/parse/parser.js +8 -3
- package/packages/safe-js/dist/parse/tokenizer.js +45 -3
- package/packages/safe-js/dist/snapshot/float32array.d.ts +3 -0
- package/packages/safe-js/dist/snapshot/float32array.js +20 -1
- package/packages/safe-js/dist/snapshot/guest-heap-validation.js +4 -1
- package/packages/safe-js/dist/snapshot/guest-heap.d.ts +2 -0
- package/packages/safe-js/dist/snapshot/guest-heap.js +6 -2
- package/packages/safe-js/dist/snapshot/restore.js +33 -3
- package/packages/safe-js/dist/snapshot/serialize.d.ts +2 -1
- package/packages/safe-js/dist/snapshot/serialize.js +10 -9
- package/packages/safe-js/dist/snapshot/validation.js +11 -1
- package/packages/safe-js/dist/chunks/chunk-ZSYBRZU6.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-2LNBLFJ3.js.map → chunk-37V6Q4K3.js.map} +0 -0
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { checkFloat32Allocation, float32Number, float32Storage, isFloat32Array, isFloat32Index } from "../float32.js";
|
|
2
|
-
import { createSandboxClosure } from "../values.js";
|
|
2
|
+
import { createSandboxClosure, isSandboxClosure, measureSandboxData } from "../values.js";
|
|
3
|
+
import { accessorAdapter, readPropertyDescriptor } from "../accessors.js";
|
|
4
|
+
import { float32Prototypes } from "../float32-prototypes.js";
|
|
5
|
+
import { getSandboxDataProperty, getSandboxPropertyDescriptor, getSandboxPrototype, materializeFunctionProperties, registerIntrinsicFunction, registerIntrinsicObject, setSandboxPrototype } from "../object-model.js";
|
|
6
|
+
import { registerBuiltinIdentities, resolveIntrinsicIdentity } from "../intrinsics.js";
|
|
7
|
+
import { invokeBuiltinClosure } from "../builtin-call.js";
|
|
8
|
+
import { retainValues } from "../resources.js";
|
|
9
|
+
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
10
|
+
import { acquireSandboxIterator, readIteratorResult } from "../iteration.js";
|
|
11
|
+
import { createDataCheckpoint } from "../data-checkpoint.js";
|
|
12
|
+
import { createSandboxBox } from "../boxed.js";
|
|
3
13
|
const constructors = new WeakSet();
|
|
4
|
-
export function createFloat32ArrayGlobal(budget) {
|
|
14
|
+
export function createFloat32ArrayGlobal(budget, nativePrototype = false) {
|
|
5
15
|
const constructor = createSandboxClosure({
|
|
16
|
+
guest: nativePrototype,
|
|
6
17
|
sandbox: true,
|
|
7
18
|
name: "Float32Array",
|
|
8
19
|
length: 3,
|
|
@@ -10,33 +21,294 @@ export function createFloat32ArrayGlobal(budget) {
|
|
|
10
21
|
call: () => {
|
|
11
22
|
throw new TypeError("Constructor Float32Array requires 'new'.");
|
|
12
23
|
},
|
|
13
|
-
construct: (
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
construct: (args, context) => {
|
|
25
|
+
if (!nativePrototype)
|
|
26
|
+
return allocateFloat32Array(args[0], budget);
|
|
27
|
+
return (async () => {
|
|
28
|
+
const newTarget = context?.newTarget ?? constructor;
|
|
29
|
+
const candidate = context?.getProperty === undefined
|
|
30
|
+
? getSandboxDataProperty(newTarget, "prototype", budget)
|
|
31
|
+
: await context.getProperty(newTarget, "prototype");
|
|
32
|
+
const prototype = candidate !== null && typeof candidate === "object" ? candidate : float32Prototypes.get(budget);
|
|
33
|
+
const release = retainValues(budget, () => [prototype, ...args]);
|
|
34
|
+
try {
|
|
35
|
+
const result = args[0] !== null && typeof args[0] === "object" && !isFloat32Array(args[0])
|
|
36
|
+
? await allocateFloat32Input(args[0], budget, context)
|
|
37
|
+
: allocateFloat32Array(args[0], budget);
|
|
38
|
+
setSandboxPrototype(result, prototype, budget);
|
|
39
|
+
return result;
|
|
26
40
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (length < 0 || !Number.isSafeInteger(length))
|
|
32
|
-
throw new RangeError("Invalid typed array length.");
|
|
33
|
-
checkFloat32Allocation(length, budget);
|
|
34
|
-
return new Float32Array(length);
|
|
41
|
+
finally {
|
|
42
|
+
release();
|
|
43
|
+
}
|
|
44
|
+
})();
|
|
35
45
|
}
|
|
36
46
|
});
|
|
37
47
|
constructors.add(constructor);
|
|
38
48
|
return constructor;
|
|
39
49
|
}
|
|
50
|
+
async function allocateFloat32Input(source, budget, context) {
|
|
51
|
+
const callerContext = context;
|
|
52
|
+
const bridge = {
|
|
53
|
+
...callerContext, stack: callerContext?.stack ?? [], thisValue: undefined,
|
|
54
|
+
getProperty: callerContext?.getProperty ?? ((value, key) => {
|
|
55
|
+
const descriptor = getSandboxPropertyDescriptor(value, key, budget);
|
|
56
|
+
return descriptor === undefined ? getSandboxDataProperty(value, key, budget)
|
|
57
|
+
: readPropertyDescriptor(descriptor, value, bridge);
|
|
58
|
+
}),
|
|
59
|
+
invokeClosure: callerContext?.invokeClosure ?? ((callee, values, receiver, construct) => invokeBuiltinClosure(callee, values, budget, callerContext, receiver, construct))
|
|
60
|
+
};
|
|
61
|
+
const values = [];
|
|
62
|
+
let iterator;
|
|
63
|
+
let current;
|
|
64
|
+
let result;
|
|
65
|
+
const release = retainValues(budget, () => [source, values, iterator?.retainedValue, current, result]);
|
|
66
|
+
const checkData = createDataCheckpoint(budget, bridge);
|
|
67
|
+
try {
|
|
68
|
+
iterator = await acquireSandboxIterator(source, budget, bridge);
|
|
69
|
+
let length;
|
|
70
|
+
if (iterator !== undefined) {
|
|
71
|
+
while (true) {
|
|
72
|
+
budget.visitNode();
|
|
73
|
+
const next = await iterator.next();
|
|
74
|
+
if (typeof next !== "object" || next === null)
|
|
75
|
+
throw new TypeError("Iterator result must be an object.");
|
|
76
|
+
if ((await readIteratorResult(iterator, next, "done")).value)
|
|
77
|
+
break;
|
|
78
|
+
current = (await readIteratorResult(iterator, next, "value")).value;
|
|
79
|
+
budget.allocateArrayLength(values.length + 1);
|
|
80
|
+
values.push(current);
|
|
81
|
+
checkData(values, 1 + (budget.limits.dataSize === undefined ? 0 : measureSandboxData([current])));
|
|
82
|
+
}
|
|
83
|
+
length = values.length;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
current = await bridge.getProperty(source, "length");
|
|
87
|
+
const number = await sandboxNumber(current, budget, bridge);
|
|
88
|
+
length = Number.isNaN(number) || number <= 0 ? 0 : Math.min(Math.trunc(number), Number.MAX_SAFE_INTEGER);
|
|
89
|
+
}
|
|
90
|
+
checkFloat32Allocation(length, budget);
|
|
91
|
+
result = new Float32Array(length);
|
|
92
|
+
checkData(result, 0, true);
|
|
93
|
+
for (let index = 0; index < length; index++) {
|
|
94
|
+
budget.visitNode();
|
|
95
|
+
current = iterator === undefined ? await bridge.getProperty(source, String(index)) : values[index];
|
|
96
|
+
result[index] = await sandboxNumber(current, budget, bridge);
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
release();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function allocateFloat32Array(source, budget) {
|
|
105
|
+
if (Array.isArray(source) || isFloat32Array(source)) {
|
|
106
|
+
const length = isFloat32Array(source) ? float32Storage(source).length : source.length;
|
|
107
|
+
checkFloat32Allocation(length, budget);
|
|
108
|
+
if (isFloat32Array(source))
|
|
109
|
+
return new Float32Array(source);
|
|
110
|
+
const result = new Float32Array(length);
|
|
111
|
+
for (let index = 0; index < length; index += 1) {
|
|
112
|
+
budget.visitNode();
|
|
113
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, index);
|
|
114
|
+
if (descriptor !== undefined && !("value" in descriptor))
|
|
115
|
+
throw new TypeError("Float32Array input accessors are not supported.");
|
|
116
|
+
result[index] = float32Number(descriptor?.value);
|
|
117
|
+
}
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
const number = float32Number(source);
|
|
121
|
+
const length = Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
122
|
+
if (length < 0 || !Number.isSafeInteger(length))
|
|
123
|
+
throw new RangeError("Invalid typed array length.");
|
|
124
|
+
checkFloat32Allocation(length, budget);
|
|
125
|
+
return new Float32Array(length);
|
|
126
|
+
}
|
|
127
|
+
export function createFloat32ArrayPrototypes(budget, constructor) {
|
|
128
|
+
const prototype = Object.create(null);
|
|
129
|
+
const shared = Object.create(null);
|
|
130
|
+
const abstractCall = () => { throw new TypeError("Abstract TypedArray constructor cannot be called."); };
|
|
131
|
+
const typedArray = createSandboxClosure({ guest: true, sandbox: true, name: "TypedArray", length: 0,
|
|
132
|
+
call: abstractCall, construct: abstractCall });
|
|
133
|
+
Object.defineProperty(materializeFunctionProperties(typedArray), "prototype", { value: shared, writable: false });
|
|
134
|
+
Object.defineProperty(materializeFunctionProperties(typedArray), "from", {
|
|
135
|
+
writable: true, configurable: true,
|
|
136
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "from", length: 1,
|
|
137
|
+
call: async (args, context) => {
|
|
138
|
+
const target = context?.thisValue;
|
|
139
|
+
const [source, mapper, receiver] = args;
|
|
140
|
+
if (!isSandboxClosure(target) || target.construct === undefined)
|
|
141
|
+
throw new TypeError("TypedArray.from requires a constructor receiver.");
|
|
142
|
+
if (mapper !== undefined && !isSandboxClosure(mapper))
|
|
143
|
+
throw new TypeError("TypedArray.from mapper must be callable.");
|
|
144
|
+
if (source === null || source === undefined)
|
|
145
|
+
throw new TypeError("TypedArray.from requires a non-null source.");
|
|
146
|
+
const callerContext = context;
|
|
147
|
+
context = {
|
|
148
|
+
...callerContext,
|
|
149
|
+
stack: callerContext?.stack ?? [],
|
|
150
|
+
thisValue: target,
|
|
151
|
+
getProperty: callerContext?.getProperty ?? ((value, key) => {
|
|
152
|
+
const descriptor = getSandboxPropertyDescriptor(value, key, budget);
|
|
153
|
+
return descriptor === undefined ? getSandboxDataProperty(value, key, budget)
|
|
154
|
+
: readPropertyDescriptor(descriptor, value, context);
|
|
155
|
+
}),
|
|
156
|
+
invokeClosure: callerContext?.invokeClosure ?? ((callee, values, thisValue, construct) => invokeBuiltinClosure(callee, values, budget, callerContext, thisValue, construct))
|
|
157
|
+
};
|
|
158
|
+
let result;
|
|
159
|
+
let current;
|
|
160
|
+
let iterator;
|
|
161
|
+
const values = [];
|
|
162
|
+
const release = retainValues(budget, () => [target, result, current, iterator?.retainedValue, values, ...args]);
|
|
163
|
+
const checkData = createDataCheckpoint(budget, context);
|
|
164
|
+
const read = (key) => context?.getProperty === undefined
|
|
165
|
+
? getSandboxDataProperty(source, key, budget) : context.getProperty(source, key);
|
|
166
|
+
try {
|
|
167
|
+
iterator = await acquireSandboxIterator(source, budget, context);
|
|
168
|
+
let length;
|
|
169
|
+
if (iterator !== undefined) {
|
|
170
|
+
while (true) {
|
|
171
|
+
budget.visitNode();
|
|
172
|
+
const next = await iterator.next();
|
|
173
|
+
if (typeof next !== "object" || next === null)
|
|
174
|
+
throw new TypeError("Iterator result must be an object.");
|
|
175
|
+
if ((await readIteratorResult(iterator, next, "done")).value)
|
|
176
|
+
break;
|
|
177
|
+
current = (await readIteratorResult(iterator, next, "value")).value;
|
|
178
|
+
budget.allocateArrayLength(values.length + 1);
|
|
179
|
+
values.push(current);
|
|
180
|
+
checkData(values, 1 + (budget.limits.dataSize === undefined ? 0 : measureSandboxData([current])));
|
|
181
|
+
}
|
|
182
|
+
length = values.length;
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
const number = await sandboxNumber(await read("length"), budget, context);
|
|
186
|
+
length = Number.isNaN(number) || number <= 0 ? 0 : Math.min(Math.trunc(number), Number.MAX_SAFE_INTEGER);
|
|
187
|
+
}
|
|
188
|
+
result = await invokeBuiltinClosure(target, [length], budget, context, undefined, true);
|
|
189
|
+
if (!isFloat32Array(result) || float32Storage(result).length < length)
|
|
190
|
+
throw new TypeError("TypedArray.from constructor must return sufficient typed storage.");
|
|
191
|
+
checkData(result, 0, true);
|
|
192
|
+
for (let index = 0; index < length; index++) {
|
|
193
|
+
budget.visitNode();
|
|
194
|
+
current = iterator === undefined ? await read(String(index)) : values[index];
|
|
195
|
+
if (mapper !== undefined)
|
|
196
|
+
current = await invokeBuiltinClosure(mapper, [current, index], budget, context, receiver);
|
|
197
|
+
result[index] = await sandboxNumber(current, budget, context);
|
|
198
|
+
}
|
|
199
|
+
return result;
|
|
200
|
+
}
|
|
201
|
+
finally {
|
|
202
|
+
release();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
})
|
|
206
|
+
});
|
|
207
|
+
Object.defineProperty(materializeFunctionProperties(typedArray), "of", {
|
|
208
|
+
writable: true, configurable: true,
|
|
209
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "of", length: 0,
|
|
210
|
+
call: async (args, context) => {
|
|
211
|
+
const target = context?.thisValue;
|
|
212
|
+
if (!isSandboxClosure(target) || target.construct === undefined)
|
|
213
|
+
throw new TypeError("TypedArray.of requires a constructor receiver.");
|
|
214
|
+
let result;
|
|
215
|
+
const release = retainValues(budget, () => [target, result, ...args]);
|
|
216
|
+
try {
|
|
217
|
+
result = await invokeBuiltinClosure(target, [args.length], budget, context, undefined, true);
|
|
218
|
+
if (!isFloat32Array(result) || float32Storage(result).length < args.length)
|
|
219
|
+
throw new TypeError("TypedArray.of constructor must return sufficient typed storage.");
|
|
220
|
+
for (let index = 0; index < args.length; index++) {
|
|
221
|
+
budget.visitNode();
|
|
222
|
+
result[index] = await sandboxNumber(args[index], budget, context);
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
release();
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
})
|
|
231
|
+
});
|
|
232
|
+
Object.defineProperties(materializeFunctionProperties(constructor), {
|
|
233
|
+
prototype: { value: prototype, writable: false },
|
|
234
|
+
BYTES_PER_ELEMENT: { value: 4, writable: false, enumerable: false, configurable: false }
|
|
235
|
+
});
|
|
236
|
+
Object.defineProperties(prototype, {
|
|
237
|
+
constructor: { value: constructor, writable: true, configurable: true },
|
|
238
|
+
BYTES_PER_ELEMENT: { value: 4 }
|
|
239
|
+
});
|
|
240
|
+
Object.defineProperty(shared, "constructor", { value: typedArray, writable: true, configurable: true });
|
|
241
|
+
setSandboxPrototype(constructor, typedArray);
|
|
242
|
+
setSandboxPrototype(prototype, shared);
|
|
243
|
+
setSandboxPrototype(shared, getSandboxPrototype(Object.create(null), budget));
|
|
244
|
+
const getters = [];
|
|
245
|
+
for (const key of ["length", "byteLength", "byteOffset"]) {
|
|
246
|
+
const getter = createSandboxClosure({ guest: true, sandbox: true, name: `get ${key}`, length: 0,
|
|
247
|
+
call: (_args, context) => {
|
|
248
|
+
if (!isFloat32Array(context?.thisValue))
|
|
249
|
+
throw new TypeError(`TypedArray ${key} requires a typed array receiver.`);
|
|
250
|
+
const storage = float32Storage(context.thisValue);
|
|
251
|
+
return key === "byteLength" ? storage.length * 4 : storage[key];
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
getters.push(getter);
|
|
255
|
+
Object.defineProperty(shared, key, { get: accessorAdapter(getter, "get"), configurable: true });
|
|
256
|
+
}
|
|
257
|
+
for (const key of ["set", "slice", "subarray"])
|
|
258
|
+
Object.defineProperty(shared, key, { value: getFloat32Member(new Float32Array(0), key, budget), writable: true, configurable: true });
|
|
259
|
+
const arrayPrototype = resolveIntrinsicIdentity(budget, '["Array","prototype"]');
|
|
260
|
+
Object.defineProperty(shared, "toString", { value: getSandboxDataProperty(arrayPrototype, "toString", budget), writable: true, configurable: true });
|
|
261
|
+
Object.defineProperty(shared, "join", { writable: true, configurable: true,
|
|
262
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "join", length: 1,
|
|
263
|
+
call: async (args, context) => {
|
|
264
|
+
if (!isFloat32Array(context?.thisValue))
|
|
265
|
+
throw new TypeError("TypedArray join requires a typed array receiver.");
|
|
266
|
+
const receiver = context.thisValue;
|
|
267
|
+
const length = float32Storage(receiver).length;
|
|
268
|
+
let separator = ",";
|
|
269
|
+
let text = "";
|
|
270
|
+
const release = retainValues(budget, () => [receiver, separator, text, ...args]);
|
|
271
|
+
try {
|
|
272
|
+
if (args[0] !== undefined)
|
|
273
|
+
separator = await sandboxString(args[0], budget, context);
|
|
274
|
+
for (let index = 0; index < length; index++) {
|
|
275
|
+
budget.visitNode();
|
|
276
|
+
text = budget.allocateString(text + (index === 0 ? "" : separator) + String(receiver[index]));
|
|
277
|
+
}
|
|
278
|
+
return text;
|
|
279
|
+
}
|
|
280
|
+
finally {
|
|
281
|
+
release();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
});
|
|
286
|
+
const tagGetter = createSandboxClosure({ guest: true, sandbox: true, name: "get [Symbol.toStringTag]", length: 0,
|
|
287
|
+
call: (_args, context) => isFloat32Array(context?.thisValue) ? "Float32Array" : undefined });
|
|
288
|
+
getters.push(tagGetter);
|
|
289
|
+
Object.defineProperty(shared, Symbol.toStringTag, { get: accessorAdapter(tagGetter, "get"), configurable: true });
|
|
290
|
+
for (const key of ["values", "keys", "entries"]) {
|
|
291
|
+
const method = getSandboxDataProperty(arrayPrototype, key, budget);
|
|
292
|
+
const closure = createSandboxClosure({ guest: true, sandbox: true, name: key, length: 0,
|
|
293
|
+
call: (args, context) => {
|
|
294
|
+
if (!isFloat32Array(context?.thisValue))
|
|
295
|
+
throw new TypeError(`TypedArray ${key} requires a typed array receiver.`);
|
|
296
|
+
return invokeBuiltinClosure(method, args, budget, context, context.thisValue);
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
Object.defineProperty(shared, key, { value: closure, writable: true, configurable: true });
|
|
300
|
+
if (key === "values")
|
|
301
|
+
Object.defineProperty(shared, Symbol.iterator, { value: closure, writable: true, configurable: true });
|
|
302
|
+
}
|
|
303
|
+
float32Prototypes.set(budget, prototype);
|
|
304
|
+
registerBuiltinIdentities(budget, { Float32Array: constructor, "%TypedArray%": typedArray });
|
|
305
|
+
registerIntrinsicFunction(budget, constructor);
|
|
306
|
+
registerIntrinsicFunction(budget, typedArray);
|
|
307
|
+
registerIntrinsicObject(budget, prototype);
|
|
308
|
+
registerIntrinsicObject(budget, shared);
|
|
309
|
+
for (const getter of getters)
|
|
310
|
+
registerIntrinsicFunction(budget, getter);
|
|
311
|
+
}
|
|
40
312
|
export function isFloat32ArrayConstructor(value) {
|
|
41
313
|
return typeof value === "object" && value !== null && constructors.has(value);
|
|
42
314
|
}
|
|
@@ -48,6 +320,8 @@ export function getFloat32Member(value, property, budget) {
|
|
|
48
320
|
throw new TypeError("Float32Array accessors are not supported.");
|
|
49
321
|
return descriptor.value;
|
|
50
322
|
}
|
|
323
|
+
if (float32Prototypes.has(budget))
|
|
324
|
+
return undefined;
|
|
51
325
|
const storage = float32Storage(value);
|
|
52
326
|
if (key === "length")
|
|
53
327
|
return storage.length;
|
|
@@ -60,6 +334,7 @@ export function getFloat32Member(value, property, budget) {
|
|
|
60
334
|
if (!["set", "slice", "subarray"].includes(key))
|
|
61
335
|
return undefined;
|
|
62
336
|
return createSandboxClosure({
|
|
337
|
+
guest: true,
|
|
63
338
|
sandbox: true,
|
|
64
339
|
name: key,
|
|
65
340
|
length: key === "set" ? 1 : 2,
|
|
@@ -68,63 +343,94 @@ export function getFloat32Member(value, property, budget) {
|
|
|
68
343
|
if (!isFloat32Array(receiver))
|
|
69
344
|
throw new TypeError(`Float32Array#${key} requires a Float32Array receiver.`);
|
|
70
345
|
const storage = float32Storage(receiver);
|
|
346
|
+
const bridge = {
|
|
347
|
+
...context, stack: context?.stack ?? [], thisValue: receiver,
|
|
348
|
+
getProperty: context?.getProperty ?? ((value, property) => {
|
|
349
|
+
const descriptor = getSandboxPropertyDescriptor(value, property, budget);
|
|
350
|
+
return descriptor === undefined ? getSandboxDataProperty(value, property, budget)
|
|
351
|
+
: readPropertyDescriptor(descriptor, value, bridge);
|
|
352
|
+
}),
|
|
353
|
+
invokeClosure: context?.invokeClosure ?? ((callee, values, thisValue, construct) => invokeBuiltinClosure(callee, values, budget, context, thisValue, construct))
|
|
354
|
+
};
|
|
71
355
|
if (key === "set") {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
356
|
+
return (async () => {
|
|
357
|
+
const [source, offsetValue = 0] = args;
|
|
358
|
+
let current;
|
|
359
|
+
let sourceObject;
|
|
360
|
+
const release = retainValues(budget, () => [receiver, sourceObject, current, ...args]);
|
|
361
|
+
try {
|
|
362
|
+
const number = await sandboxNumber(offsetValue, budget, bridge);
|
|
363
|
+
const offset = Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
364
|
+
if (offset < 0)
|
|
365
|
+
throw new RangeError("Float32Array#set offset is out of bounds.");
|
|
366
|
+
if (source === null || source === undefined)
|
|
367
|
+
throw new TypeError("Float32Array#set requires a non-null source.");
|
|
368
|
+
let length;
|
|
369
|
+
if (isFloat32Array(source))
|
|
370
|
+
length = float32Storage(source).length;
|
|
371
|
+
else {
|
|
372
|
+
sourceObject = typeof source === "object" ? source : createSandboxBox(source);
|
|
373
|
+
current = await bridge.getProperty(sourceObject, "length");
|
|
374
|
+
const size = await sandboxNumber(current, budget, bridge);
|
|
375
|
+
length = Number.isNaN(size) || size <= 0 ? 0 : Math.min(Math.trunc(size), Number.MAX_SAFE_INTEGER);
|
|
376
|
+
}
|
|
377
|
+
if (offset + length > storage.length)
|
|
378
|
+
throw new RangeError("Float32Array#set source is out of bounds.");
|
|
379
|
+
if (isFloat32Array(source))
|
|
380
|
+
Float32Array.prototype.set.call(receiver, source, offset);
|
|
381
|
+
else
|
|
382
|
+
for (let index = 0; index < length; index++) {
|
|
383
|
+
budget.visitNode();
|
|
384
|
+
current = await bridge.getProperty(sourceObject, String(index));
|
|
385
|
+
receiver[offset + index] = await sandboxNumber(current, budget, bridge);
|
|
386
|
+
}
|
|
387
|
+
return undefined;
|
|
388
|
+
}
|
|
389
|
+
finally {
|
|
390
|
+
release();
|
|
391
|
+
}
|
|
392
|
+
})();
|
|
393
|
+
}
|
|
394
|
+
return (async () => {
|
|
395
|
+
const release = retainValues(budget, () => [receiver, ...args]);
|
|
396
|
+
try {
|
|
397
|
+
const start = relativeIndex(await sandboxNumber(args[0], budget, bridge), storage.length);
|
|
398
|
+
const end = args[1] === undefined ? storage.length
|
|
399
|
+
: relativeIndex(await sandboxNumber(args[1], budget, bridge), storage.length);
|
|
400
|
+
const length = Math.max(end - start, 0);
|
|
401
|
+
if (key === "subarray")
|
|
402
|
+
return new Float32Array(storage.buffer, storage.byteOffset + start * 4, length);
|
|
403
|
+
checkFloat32Allocation(length, budget);
|
|
404
|
+
const result = new Float32Array(length);
|
|
405
|
+
new Uint8Array(result.buffer).set(new Uint8Array(storage.buffer, storage.byteOffset + start * 4, length * 4));
|
|
406
|
+
return result;
|
|
83
407
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
for (let index = 0; index < length; index += 1) {
|
|
87
|
-
budget.visitNode();
|
|
88
|
-
const entry = Object.getOwnPropertyDescriptor(source, index);
|
|
89
|
-
if (entry !== undefined && !("value" in entry))
|
|
90
|
-
throw new TypeError("Float32Array input accessors are not supported.");
|
|
91
|
-
copied[index] = float32Number(entry?.value);
|
|
408
|
+
finally {
|
|
409
|
+
release();
|
|
92
410
|
}
|
|
93
|
-
|
|
94
|
-
return undefined;
|
|
95
|
-
}
|
|
96
|
-
const start = relativeIndex(args[0], storage.length, 0);
|
|
97
|
-
const end = relativeIndex(args[1], storage.length, storage.length);
|
|
98
|
-
const length = Math.max(end - start, 0);
|
|
99
|
-
if (key === "subarray")
|
|
100
|
-
return new Float32Array(storage.buffer, storage.byteOffset + start * 4, length);
|
|
101
|
-
checkFloat32Allocation(length, budget);
|
|
102
|
-
const result = new Float32Array(length);
|
|
103
|
-
new Uint8Array(result.buffer).set(new Uint8Array(storage.buffer, storage.byteOffset + start * 4, length * 4));
|
|
104
|
-
return result;
|
|
411
|
+
})();
|
|
105
412
|
}
|
|
106
413
|
});
|
|
107
414
|
}
|
|
108
|
-
export function setFloat32Member(value, property, entry) {
|
|
109
|
-
const key = String(property);
|
|
110
|
-
if (isFloat32Index(key)) {
|
|
415
|
+
export function setFloat32Member(value, property, entry, budget) {
|
|
416
|
+
const key = typeof property === "symbol" ? property : String(property);
|
|
417
|
+
if (typeof key !== "symbol" && isFloat32Index(key)) {
|
|
111
418
|
Reflect.set(value, key, float32Number(entry));
|
|
112
419
|
return;
|
|
113
420
|
}
|
|
114
421
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
115
|
-
|
|
422
|
+
const inherited = descriptor ?? (budget === undefined ? undefined : getSandboxPropertyDescriptor(value, key, budget));
|
|
423
|
+
if (descriptor === undefined && typeof key === "string" &&
|
|
424
|
+
(budget === undefined || !float32Prototypes.has(budget)) &&
|
|
116
425
|
["length", "byteLength", "byteOffset", "buffer", "BYTES_PER_ELEMENT"].includes(key))
|
|
117
|
-
throw new TypeError(`Cannot assign to read only property '${key}'.`);
|
|
118
|
-
if (
|
|
119
|
-
throw new TypeError(`Cannot assign to read only property '${key}'.`);
|
|
426
|
+
throw new TypeError(`Cannot assign to read only property '${String(key)}'.`);
|
|
427
|
+
if (inherited !== undefined && (!("value" in inherited) || !inherited.writable))
|
|
428
|
+
throw new TypeError(`Cannot assign to read only property '${String(key)}'.`);
|
|
120
429
|
Object.defineProperty(value, key, descriptor === undefined
|
|
121
430
|
? { value: entry, configurable: true, enumerable: true, writable: true }
|
|
122
431
|
: { value: entry });
|
|
123
432
|
}
|
|
124
|
-
function relativeIndex(
|
|
125
|
-
if (value === undefined)
|
|
126
|
-
return fallback;
|
|
127
|
-
const numeric = float32Number(value);
|
|
433
|
+
function relativeIndex(numeric, length) {
|
|
128
434
|
const integer = Number.isNaN(numeric) ? 0 : Math.trunc(numeric);
|
|
129
435
|
return integer < 0 ? Math.max(length + integer, 0) : Math.min(integer, length);
|
|
130
436
|
}
|
|
@@ -12,7 +12,7 @@ import { isSandboxDate } from "../date.js";
|
|
|
12
12
|
import { createSandboxBox } from "../boxed.js";
|
|
13
13
|
import { createObjectGlobal, hasOwnSandboxProperty } from "./object.js";
|
|
14
14
|
import { isGuestHostObject } from "../host-capabilities.js";
|
|
15
|
-
import { isFloat32Array } from "../float32.js";
|
|
15
|
+
import { float32Number, isFloat32Array, isFloat32Index } from "../float32.js";
|
|
16
16
|
import { deleteSandboxProperty, setSandboxProperty } from "../interpreter.js";
|
|
17
17
|
import { acquireSandboxIterator, closeIterator, getSandboxIterator, readIteratorResult } from "../iteration.js";
|
|
18
18
|
import { sandboxNumber, sandboxString } from "../string-coercion.js";
|
|
@@ -681,8 +681,8 @@ async function definePropertiesFromObject(target, descriptors, budget, context)
|
|
|
681
681
|
}
|
|
682
682
|
export function defineDataProperty(target, key, descriptor, budget) {
|
|
683
683
|
budget.visitNode();
|
|
684
|
-
if (isFloat32Array(target))
|
|
685
|
-
|
|
684
|
+
if (isFloat32Array(target) && typeof key !== "symbol" && isFloat32Index(String(key)) && "value" in descriptor)
|
|
685
|
+
descriptor = { ...descriptor, value: float32Number(descriptor.value) };
|
|
686
686
|
const properties = objectProperties(target, true);
|
|
687
687
|
if (Array.isArray(properties)) {
|
|
688
688
|
if (key === "length" && "value" in descriptor)
|
|
@@ -4,6 +4,8 @@ export declare function createBuiltinBindings(options: Parameters<typeof createC
|
|
|
4
4
|
random?: () => number;
|
|
5
5
|
clock?: RunClock;
|
|
6
6
|
functionHasInstance?: boolean;
|
|
7
|
+
errorPrototypes?: boolean;
|
|
8
|
+
float32Prototypes?: boolean;
|
|
7
9
|
}): {
|
|
8
10
|
RegExp: import("./values.js").SandboxClosure;
|
|
9
11
|
Promise: import("./values.js").SandboxClosure;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createConsoleJsonGlobals } from "./globals/console-json.js";
|
|
2
2
|
import { createCollectionGlobals } from "./globals/collections.js";
|
|
3
|
-
import { createFloat32ArrayGlobal } from "./globals/float32array.js";
|
|
4
|
-
import { createErrorGlobals } from "./globals/error.js";
|
|
3
|
+
import { createFloat32ArrayGlobal, createFloat32ArrayPrototypes } from "./globals/float32array.js";
|
|
4
|
+
import { createErrorGlobals, createErrorPrototypes } from "./globals/error.js";
|
|
5
5
|
import { createMathGlobals } from "./globals/math.js";
|
|
6
6
|
import { createRegexGlobals } from "./globals/regex.js";
|
|
7
7
|
import { createMiscGlobals } from "./globals/misc.js";
|
|
@@ -18,11 +18,11 @@ export function createBuiltinBindings(options) {
|
|
|
18
18
|
const bindings = {
|
|
19
19
|
...createConsoleJsonGlobals(options),
|
|
20
20
|
...createCollectionGlobals(options),
|
|
21
|
-
Float32Array: createFloat32ArrayGlobal(options.budget),
|
|
21
|
+
Float32Array: createFloat32ArrayGlobal(options.budget, options.float32Prototypes !== false),
|
|
22
22
|
Date: createDateGlobal(options),
|
|
23
23
|
Symbol: createSymbolGlobal(options.budget),
|
|
24
24
|
BigInt: createBigIntGlobal(options.budget),
|
|
25
|
-
...createErrorGlobals(options),
|
|
25
|
+
...createErrorGlobals({ ...options, errorPrototypes: options.errorPrototypes !== false }),
|
|
26
26
|
...createMathGlobals({ random: options.random, budget: options.budget }),
|
|
27
27
|
...createObjectArrayGlobals(options),
|
|
28
28
|
...createMiscGlobals(options),
|
|
@@ -31,6 +31,10 @@ export function createBuiltinBindings(options) {
|
|
|
31
31
|
...createRegexGlobals(options)
|
|
32
32
|
};
|
|
33
33
|
createFunctionPrototype(options.budget, options.functionHasInstance);
|
|
34
|
+
if (options.float32Prototypes !== false)
|
|
35
|
+
createFloat32ArrayPrototypes(options.budget, bindings.Float32Array);
|
|
36
|
+
if (options.errorPrototypes !== false)
|
|
37
|
+
createErrorPrototypes(options.budget, bindings);
|
|
34
38
|
createGeneratorPrototypes(options.budget);
|
|
35
39
|
registerBuiltinIdentities(options.budget, bindings);
|
|
36
40
|
return bindings;
|
|
@@ -408,10 +408,12 @@ function createHostErrorValue(reason, stackFrames, budget, span, state = { seen:
|
|
|
408
408
|
const error = reason instanceof Error
|
|
409
409
|
? createSubsetErrorValue(reason.name, reason.message, stackFrames, budget, {
|
|
410
410
|
cause: reason,
|
|
411
|
-
chargeBudget
|
|
411
|
+
chargeBudget,
|
|
412
|
+
transport: true
|
|
412
413
|
})
|
|
413
414
|
: createSubsetErrorValue("Error", describeThrownReason(reason), stackFrames, budget, {
|
|
414
|
-
chargeBudget: false
|
|
415
|
+
chargeBudget: false,
|
|
416
|
+
transport: true
|
|
415
417
|
});
|
|
416
418
|
if (reason instanceof Error) {
|
|
417
419
|
state.seen.set(reason, error);
|
|
@@ -4,7 +4,7 @@ import { invokeBuiltinClosure } from "./builtin-call.js";
|
|
|
4
4
|
import { isFloat32Array } from "./float32.js";
|
|
5
5
|
import { isFloat32ArrayConstructor } from "./globals/float32array.js";
|
|
6
6
|
import { isSandboxErrorConstructorInstance } from "./globals/error.js";
|
|
7
|
-
import { getSandboxPropertyDescriptor, getSandboxPrototype, isGuestClosure } from "./object-model.js";
|
|
7
|
+
import { getSandboxPropertyDescriptor, getSandboxPrototype, hasExplicitSandboxPrototype, isGuestClosure } from "./object-model.js";
|
|
8
8
|
import { isSandboxClosure } from "./values.js";
|
|
9
9
|
export async function evaluateInstanceof(value, constructor, budget, context) {
|
|
10
10
|
if (constructor === null || typeof constructor !== "object")
|
|
@@ -27,9 +27,10 @@ export async function ordinaryHasInstance(value, constructor, budget, context) {
|
|
|
27
27
|
return evaluateInstanceof(value, constructor.boundTarget, budget, context);
|
|
28
28
|
}
|
|
29
29
|
// These existing built-ins do not yet have ordinary prototype graphs.
|
|
30
|
-
if (isFloat32ArrayConstructor(constructor))
|
|
30
|
+
if (isFloat32ArrayConstructor(constructor) && !isGuestClosure(constructor))
|
|
31
31
|
return isFloat32Array(value);
|
|
32
|
-
if (
|
|
32
|
+
if ((!isGuestClosure(constructor) || (value !== null && typeof value === "object" && !hasExplicitSandboxPrototype(value))) &&
|
|
33
|
+
isSandboxErrorConstructorInstance(value, constructor))
|
|
33
34
|
return true;
|
|
34
35
|
if (!isGuestClosure(constructor) || typeof value !== "object" || value === null)
|
|
35
36
|
return false;
|
|
@@ -2380,7 +2380,7 @@ async function evaluateMemberCallExpression(node, context) {
|
|
|
2380
2380
|
return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
|
|
2381
2381
|
}
|
|
2382
2382
|
if (isFloat32Array(member.object)) {
|
|
2383
|
-
return evaluateResolvedCallExpression(node,
|
|
2383
|
+
return evaluateResolvedCallExpression(node, await getPropertyValue(member.object, member.property, context), context, member.object);
|
|
2384
2384
|
}
|
|
2385
2385
|
if (isSandboxSet(member.object)) {
|
|
2386
2386
|
return evaluatePrimitiveMemberCall(node, "Set", member.property, getSetMember(member.object, member.property, createSetMethodOptions(context)), context);
|
|
@@ -2911,9 +2911,7 @@ export function setSandboxProperty(target, property, value, budget, checkInherit
|
|
|
2911
2911
|
if (isSandboxMap(target) || isSandboxSet(target))
|
|
2912
2912
|
target = getCollectionProperties(target);
|
|
2913
2913
|
if (isFloat32Array(target)) {
|
|
2914
|
-
|
|
2915
|
-
throw new TypeError("Typed array symbol properties are not yet supported.");
|
|
2916
|
-
setFloat32Member(target, property, value);
|
|
2914
|
+
setFloat32Member(target, property, value, budget);
|
|
2917
2915
|
return;
|
|
2918
2916
|
}
|
|
2919
2917
|
if (isSandboxRegex(target)) {
|