poe-code 14.0.82 → 14.0.84
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 +1105 -223
- 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-7LGBDF56.js → chunk-2EZQJQ2C.js} +2 -2
- package/packages/safe-js/dist/chunks/{chunk-V6LQP64H.js → chunk-CYVI4ZUK.js} +978 -161
- package/packages/safe-js/dist/chunks/chunk-CYVI4ZUK.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/array-buffer.d.ts +12 -0
- package/packages/safe-js/dist/interp/array-buffer.js +33 -0
- 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 +7 -1
- package/packages/safe-js/dist/interp/float32.js +50 -14
- package/packages/safe-js/dist/interp/globals/array-buffer.d.ts +3 -0
- package/packages/safe-js/dist/interp/globals/array-buffer.js +112 -0
- package/packages/safe-js/dist/interp/globals/float32array.d.ts +4 -3
- package/packages/safe-js/dist/interp/globals/float32array.js +463 -68
- 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 +6 -2
- package/packages/safe-js/dist/interp/host-bridge.d.ts +1 -0
- package/packages/safe-js/dist/interp/host-bridge.js +21 -0
- package/packages/safe-js/dist/interp/host-call.js +26 -2
- package/packages/safe-js/dist/interp/instanceof.js +1 -1
- 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/methods/array-iterator.js +1 -1
- package/packages/safe-js/dist/interp/object-model.js +22 -1
- package/packages/safe-js/dist/interp/values.d.ts +1 -1
- package/packages/safe-js/dist/interp/values.js +59 -9
- package/packages/safe-js/dist/lint/rules/known-globals.d.ts +1 -1
- package/packages/safe-js/dist/lint/rules/known-globals.js +1 -0
- 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/array-buffer.d.ts +13 -0
- package/packages/safe-js/dist/snapshot/array-buffer.js +40 -0
- package/packages/safe-js/dist/snapshot/dump-format.js +25 -9
- package/packages/safe-js/dist/snapshot/float32array.d.ts +11 -1
- package/packages/safe-js/dist/snapshot/float32array.js +42 -5
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +5 -0
- package/packages/safe-js/dist/snapshot/replay-data.js +35 -10
- package/packages/safe-js/dist/snapshot/restore.js +30 -3
- package/packages/safe-js/dist/snapshot/serialize.d.ts +7 -3
- package/packages/safe-js/dist/snapshot/serialize.js +24 -14
- package/packages/safe-js/dist/snapshot/validation.js +21 -1
- package/packages/safe-js/dist/chunks/chunk-V6LQP64H.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-7LGBDF56.js.map → chunk-2EZQJQ2C.js.map} +0 -0
|
@@ -1,8 +1,20 @@
|
|
|
1
|
-
import { checkFloat32Allocation, float32Number, float32Storage, isFloat32Array, isFloat32Index } from "../float32.js";
|
|
2
|
-
import { createSandboxClosure } from "../values.js";
|
|
1
|
+
import { checkFloat32Allocation, float32Number, float32Storage, float32ViewLayouts, isFloat32Array, isFloat32Index } from "../float32.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";
|
|
13
|
+
import { arrayBufferLength, arrayBufferOptions, isSandboxArrayBuffer } from "../array-buffer.js";
|
|
3
14
|
const constructors = new WeakSet();
|
|
4
|
-
export function createFloat32ArrayGlobal(budget) {
|
|
15
|
+
export function createFloat32ArrayGlobal(budget, nativePrototype = false) {
|
|
5
16
|
const constructor = createSandboxClosure({
|
|
17
|
+
guest: nativePrototype,
|
|
6
18
|
sandbox: true,
|
|
7
19
|
name: "Float32Array",
|
|
8
20
|
length: 3,
|
|
@@ -10,37 +22,332 @@ export function createFloat32ArrayGlobal(budget) {
|
|
|
10
22
|
call: () => {
|
|
11
23
|
throw new TypeError("Constructor Float32Array requires 'new'.");
|
|
12
24
|
},
|
|
13
|
-
construct: (
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
construct: (args, context) => {
|
|
26
|
+
if (!nativePrototype)
|
|
27
|
+
return allocateFloat32Array(args[0], budget);
|
|
28
|
+
return (async () => {
|
|
29
|
+
const newTarget = context?.newTarget ?? constructor;
|
|
30
|
+
const candidate = context?.getProperty === undefined
|
|
31
|
+
? getSandboxDataProperty(newTarget, "prototype", budget)
|
|
32
|
+
: await context.getProperty(newTarget, "prototype");
|
|
33
|
+
const prototype = candidate !== null && typeof candidate === "object" ? candidate : float32Prototypes.get(budget);
|
|
34
|
+
const release = retainValues(budget, () => [prototype, ...args]);
|
|
35
|
+
try {
|
|
36
|
+
if (isSandboxArrayBuffer(args[0])) {
|
|
37
|
+
const buffer = args[0];
|
|
38
|
+
const number = await sandboxNumber(args[1], budget, context);
|
|
39
|
+
const offset = Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
40
|
+
if (!Number.isSafeInteger(offset) || offset < 0 || offset % 4 !== 0)
|
|
41
|
+
throw new RangeError("Invalid Float32Array buffer offset.");
|
|
42
|
+
const bytes = arrayBufferLength(buffer);
|
|
43
|
+
let length;
|
|
44
|
+
if (args[2] === undefined) {
|
|
45
|
+
if ((arrayBufferOptions(buffer) === undefined && bytes % 4 !== 0) || offset > bytes)
|
|
46
|
+
throw new RangeError("Invalid Float32Array buffer length.");
|
|
47
|
+
length = Math.floor((bytes - offset) / 4);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const size = await sandboxNumber(args[2], budget, context);
|
|
51
|
+
length = Number.isNaN(size) ? 0 : Math.trunc(size);
|
|
52
|
+
if (!Number.isSafeInteger(length) || length < 0 || offset + length * 4 > arrayBufferLength(buffer))
|
|
53
|
+
throw new RangeError("Invalid Float32Array view length.");
|
|
54
|
+
}
|
|
55
|
+
budget.allocateArrayLength(length);
|
|
56
|
+
const result = new Float32Array(buffer, offset, args[2] === undefined ? undefined : length);
|
|
57
|
+
if (arrayBufferOptions(buffer) !== undefined)
|
|
58
|
+
float32ViewLayouts.set(result, { byteOffset: offset, ...(args[2] === undefined ? {} : { length }) });
|
|
59
|
+
setSandboxPrototype(result, prototype, budget);
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
const result = args[0] !== null && typeof args[0] === "object" && !isFloat32Array(args[0])
|
|
63
|
+
? await allocateFloat32Input(args[0], budget, context)
|
|
64
|
+
: allocateFloat32Array(args[0], budget);
|
|
65
|
+
setSandboxPrototype(result, prototype, budget);
|
|
66
|
+
return result;
|
|
26
67
|
}
|
|
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);
|
|
68
|
+
finally {
|
|
69
|
+
release();
|
|
70
|
+
}
|
|
71
|
+
})();
|
|
35
72
|
}
|
|
36
73
|
});
|
|
37
74
|
constructors.add(constructor);
|
|
38
75
|
return constructor;
|
|
39
76
|
}
|
|
77
|
+
async function allocateFloat32Input(source, budget, context) {
|
|
78
|
+
const callerContext = context;
|
|
79
|
+
const bridge = {
|
|
80
|
+
...callerContext, stack: callerContext?.stack ?? [], thisValue: undefined,
|
|
81
|
+
getProperty: callerContext?.getProperty ?? ((value, key) => {
|
|
82
|
+
const descriptor = getSandboxPropertyDescriptor(value, key, budget);
|
|
83
|
+
return descriptor === undefined ? getSandboxDataProperty(value, key, budget)
|
|
84
|
+
: readPropertyDescriptor(descriptor, value, bridge);
|
|
85
|
+
}),
|
|
86
|
+
invokeClosure: callerContext?.invokeClosure ?? ((callee, values, receiver, construct) => invokeBuiltinClosure(callee, values, budget, callerContext, receiver, construct))
|
|
87
|
+
};
|
|
88
|
+
const values = [];
|
|
89
|
+
let iterator;
|
|
90
|
+
let current;
|
|
91
|
+
let result;
|
|
92
|
+
const release = retainValues(budget, () => [source, values, iterator?.retainedValue, current, result]);
|
|
93
|
+
const checkData = createDataCheckpoint(budget, bridge);
|
|
94
|
+
try {
|
|
95
|
+
iterator = await acquireSandboxIterator(source, budget, bridge);
|
|
96
|
+
let length;
|
|
97
|
+
if (iterator !== undefined) {
|
|
98
|
+
while (true) {
|
|
99
|
+
budget.visitNode();
|
|
100
|
+
const next = await iterator.next();
|
|
101
|
+
if (typeof next !== "object" || next === null)
|
|
102
|
+
throw new TypeError("Iterator result must be an object.");
|
|
103
|
+
if ((await readIteratorResult(iterator, next, "done")).value)
|
|
104
|
+
break;
|
|
105
|
+
current = (await readIteratorResult(iterator, next, "value")).value;
|
|
106
|
+
budget.allocateArrayLength(values.length + 1);
|
|
107
|
+
values.push(current);
|
|
108
|
+
checkData(values, 1 + (budget.limits.dataSize === undefined ? 0 : measureSandboxData([current])));
|
|
109
|
+
}
|
|
110
|
+
length = values.length;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
current = await bridge.getProperty(source, "length");
|
|
114
|
+
const number = await sandboxNumber(current, budget, bridge);
|
|
115
|
+
length = Number.isNaN(number) || number <= 0 ? 0 : Math.min(Math.trunc(number), Number.MAX_SAFE_INTEGER);
|
|
116
|
+
}
|
|
117
|
+
checkFloat32Allocation(length, budget);
|
|
118
|
+
result = new Float32Array(length);
|
|
119
|
+
checkData(result, 0, true);
|
|
120
|
+
for (let index = 0; index < length; index++) {
|
|
121
|
+
budget.visitNode();
|
|
122
|
+
current = iterator === undefined ? await bridge.getProperty(source, String(index)) : values[index];
|
|
123
|
+
result[index] = await sandboxNumber(current, budget, bridge);
|
|
124
|
+
}
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
release();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function allocateFloat32Array(source, budget) {
|
|
132
|
+
if (Array.isArray(source) || isFloat32Array(source)) {
|
|
133
|
+
const length = isFloat32Array(source) ? float32Storage(source).length : source.length;
|
|
134
|
+
checkFloat32Allocation(length, budget);
|
|
135
|
+
if (isFloat32Array(source))
|
|
136
|
+
return new Float32Array(source);
|
|
137
|
+
const result = new Float32Array(length);
|
|
138
|
+
for (let index = 0; index < length; index += 1) {
|
|
139
|
+
budget.visitNode();
|
|
140
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, index);
|
|
141
|
+
if (descriptor !== undefined && !("value" in descriptor))
|
|
142
|
+
throw new TypeError("Float32Array input accessors are not supported.");
|
|
143
|
+
result[index] = float32Number(descriptor?.value);
|
|
144
|
+
}
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
const number = float32Number(source);
|
|
148
|
+
const length = Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
149
|
+
if (length < 0 || !Number.isSafeInteger(length))
|
|
150
|
+
throw new RangeError("Invalid typed array length.");
|
|
151
|
+
checkFloat32Allocation(length, budget);
|
|
152
|
+
return new Float32Array(length);
|
|
153
|
+
}
|
|
154
|
+
export function createFloat32ArrayPrototypes(budget, constructor) {
|
|
155
|
+
const prototype = Object.create(null);
|
|
156
|
+
const shared = Object.create(null);
|
|
157
|
+
const abstractCall = () => { throw new TypeError("Abstract TypedArray constructor cannot be called."); };
|
|
158
|
+
const typedArray = createSandboxClosure({ guest: true, sandbox: true, name: "TypedArray", length: 0,
|
|
159
|
+
call: abstractCall, construct: abstractCall });
|
|
160
|
+
Object.defineProperty(materializeFunctionProperties(typedArray), "prototype", { value: shared, writable: false });
|
|
161
|
+
Object.defineProperty(materializeFunctionProperties(typedArray), "from", {
|
|
162
|
+
writable: true, configurable: true,
|
|
163
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "from", length: 1,
|
|
164
|
+
call: async (args, context) => {
|
|
165
|
+
const target = context?.thisValue;
|
|
166
|
+
const [source, mapper, receiver] = args;
|
|
167
|
+
if (!isSandboxClosure(target) || target.construct === undefined)
|
|
168
|
+
throw new TypeError("TypedArray.from requires a constructor receiver.");
|
|
169
|
+
if (mapper !== undefined && !isSandboxClosure(mapper))
|
|
170
|
+
throw new TypeError("TypedArray.from mapper must be callable.");
|
|
171
|
+
if (source === null || source === undefined)
|
|
172
|
+
throw new TypeError("TypedArray.from requires a non-null source.");
|
|
173
|
+
const callerContext = context;
|
|
174
|
+
context = {
|
|
175
|
+
...callerContext,
|
|
176
|
+
stack: callerContext?.stack ?? [],
|
|
177
|
+
thisValue: target,
|
|
178
|
+
getProperty: callerContext?.getProperty ?? ((value, key) => {
|
|
179
|
+
const descriptor = getSandboxPropertyDescriptor(value, key, budget);
|
|
180
|
+
return descriptor === undefined ? getSandboxDataProperty(value, key, budget)
|
|
181
|
+
: readPropertyDescriptor(descriptor, value, context);
|
|
182
|
+
}),
|
|
183
|
+
invokeClosure: callerContext?.invokeClosure ?? ((callee, values, thisValue, construct) => invokeBuiltinClosure(callee, values, budget, callerContext, thisValue, construct))
|
|
184
|
+
};
|
|
185
|
+
let result;
|
|
186
|
+
let current;
|
|
187
|
+
let iterator;
|
|
188
|
+
const values = [];
|
|
189
|
+
const release = retainValues(budget, () => [target, result, current, iterator?.retainedValue, values, ...args]);
|
|
190
|
+
const checkData = createDataCheckpoint(budget, context);
|
|
191
|
+
const read = (key) => context?.getProperty === undefined
|
|
192
|
+
? getSandboxDataProperty(source, key, budget) : context.getProperty(source, key);
|
|
193
|
+
try {
|
|
194
|
+
iterator = await acquireSandboxIterator(source, budget, context);
|
|
195
|
+
let length;
|
|
196
|
+
if (iterator !== undefined) {
|
|
197
|
+
while (true) {
|
|
198
|
+
budget.visitNode();
|
|
199
|
+
const next = await iterator.next();
|
|
200
|
+
if (typeof next !== "object" || next === null)
|
|
201
|
+
throw new TypeError("Iterator result must be an object.");
|
|
202
|
+
if ((await readIteratorResult(iterator, next, "done")).value)
|
|
203
|
+
break;
|
|
204
|
+
current = (await readIteratorResult(iterator, next, "value")).value;
|
|
205
|
+
budget.allocateArrayLength(values.length + 1);
|
|
206
|
+
values.push(current);
|
|
207
|
+
checkData(values, 1 + (budget.limits.dataSize === undefined ? 0 : measureSandboxData([current])));
|
|
208
|
+
}
|
|
209
|
+
length = values.length;
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
const number = await sandboxNumber(await read("length"), budget, context);
|
|
213
|
+
length = Number.isNaN(number) || number <= 0 ? 0 : Math.min(Math.trunc(number), Number.MAX_SAFE_INTEGER);
|
|
214
|
+
}
|
|
215
|
+
result = await invokeBuiltinClosure(target, [length], budget, context, undefined, true);
|
|
216
|
+
if (!isFloat32Array(result) || float32Storage(result).length < length)
|
|
217
|
+
throw new TypeError("TypedArray.from constructor must return sufficient typed storage.");
|
|
218
|
+
checkData(result, 0, true);
|
|
219
|
+
for (let index = 0; index < length; index++) {
|
|
220
|
+
budget.visitNode();
|
|
221
|
+
current = iterator === undefined ? await read(String(index)) : values[index];
|
|
222
|
+
if (mapper !== undefined)
|
|
223
|
+
current = await invokeBuiltinClosure(mapper, [current, index], budget, context, receiver);
|
|
224
|
+
result[index] = await sandboxNumber(current, budget, context);
|
|
225
|
+
}
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
release();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
Object.defineProperty(materializeFunctionProperties(typedArray), "of", {
|
|
235
|
+
writable: true, configurable: true,
|
|
236
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "of", length: 0,
|
|
237
|
+
call: async (args, context) => {
|
|
238
|
+
const target = context?.thisValue;
|
|
239
|
+
if (!isSandboxClosure(target) || target.construct === undefined)
|
|
240
|
+
throw new TypeError("TypedArray.of requires a constructor receiver.");
|
|
241
|
+
let result;
|
|
242
|
+
const release = retainValues(budget, () => [target, result, ...args]);
|
|
243
|
+
try {
|
|
244
|
+
result = await invokeBuiltinClosure(target, [args.length], budget, context, undefined, true);
|
|
245
|
+
if (!isFloat32Array(result) || float32Storage(result).length < args.length)
|
|
246
|
+
throw new TypeError("TypedArray.of constructor must return sufficient typed storage.");
|
|
247
|
+
for (let index = 0; index < args.length; index++) {
|
|
248
|
+
budget.visitNode();
|
|
249
|
+
result[index] = await sandboxNumber(args[index], budget, context);
|
|
250
|
+
}
|
|
251
|
+
return result;
|
|
252
|
+
}
|
|
253
|
+
finally {
|
|
254
|
+
release();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
})
|
|
258
|
+
});
|
|
259
|
+
Object.defineProperties(materializeFunctionProperties(constructor), {
|
|
260
|
+
prototype: { value: prototype, writable: false },
|
|
261
|
+
BYTES_PER_ELEMENT: { value: 4, writable: false, enumerable: false, configurable: false }
|
|
262
|
+
});
|
|
263
|
+
Object.defineProperties(prototype, {
|
|
264
|
+
constructor: { value: constructor, writable: true, configurable: true },
|
|
265
|
+
BYTES_PER_ELEMENT: { value: 4 }
|
|
266
|
+
});
|
|
267
|
+
Object.defineProperty(shared, "constructor", { value: typedArray, writable: true, configurable: true });
|
|
268
|
+
setSandboxPrototype(constructor, typedArray);
|
|
269
|
+
setSandboxPrototype(prototype, shared);
|
|
270
|
+
setSandboxPrototype(shared, getSandboxPrototype(Object.create(null), budget));
|
|
271
|
+
const getters = [];
|
|
272
|
+
const species = createSandboxClosure({ guest: true, sandbox: true, name: "get [Symbol.species]", length: 0,
|
|
273
|
+
call: (_args, context) => context?.thisValue });
|
|
274
|
+
getters.push(species);
|
|
275
|
+
Object.defineProperty(materializeFunctionProperties(typedArray), Symbol.species, {
|
|
276
|
+
get: accessorAdapter(species, "get"), configurable: true
|
|
277
|
+
});
|
|
278
|
+
for (const key of ["length", "byteLength", "byteOffset", "buffer"]) {
|
|
279
|
+
const getter = createSandboxClosure({ guest: true, sandbox: true, name: `get ${key}`, length: 0,
|
|
280
|
+
call: (_args, context) => {
|
|
281
|
+
if (!isFloat32Array(context?.thisValue))
|
|
282
|
+
throw new TypeError(`TypedArray ${key} requires a typed array receiver.`);
|
|
283
|
+
const storage = float32Storage(context.thisValue);
|
|
284
|
+
return key === "byteLength" ? storage.length * 4 : storage[key];
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
getters.push(getter);
|
|
288
|
+
Object.defineProperty(shared, key, { get: accessorAdapter(getter, "get"), configurable: true });
|
|
289
|
+
}
|
|
290
|
+
for (const key of ["set", "slice", "subarray"])
|
|
291
|
+
Object.defineProperty(shared, key, { value: getFloat32Member(new Float32Array(0), key, budget, constructor), writable: true, configurable: true });
|
|
292
|
+
const arrayPrototype = resolveIntrinsicIdentity(budget, '["Array","prototype"]');
|
|
293
|
+
Object.defineProperty(shared, "toString", { value: getSandboxDataProperty(arrayPrototype, "toString", budget), writable: true, configurable: true });
|
|
294
|
+
Object.defineProperty(shared, "join", { writable: true, configurable: true,
|
|
295
|
+
value: createSandboxClosure({ guest: true, sandbox: true, name: "join", length: 1,
|
|
296
|
+
call: async (args, context) => {
|
|
297
|
+
if (!isFloat32Array(context?.thisValue))
|
|
298
|
+
throw new TypeError("TypedArray join requires a typed array receiver.");
|
|
299
|
+
const receiver = context.thisValue;
|
|
300
|
+
const length = float32Storage(receiver, true).length;
|
|
301
|
+
let separator = ",";
|
|
302
|
+
let text = "";
|
|
303
|
+
const release = retainValues(budget, () => [receiver, separator, text, ...args]);
|
|
304
|
+
try {
|
|
305
|
+
if (args[0] !== undefined)
|
|
306
|
+
separator = await sandboxString(args[0], budget, context);
|
|
307
|
+
for (let index = 0; index < length; index++) {
|
|
308
|
+
budget.visitNode();
|
|
309
|
+
const value = receiver[index];
|
|
310
|
+
text = budget.allocateString(text + (index === 0 ? "" : separator) + (value === undefined ? "" : String(value)));
|
|
311
|
+
}
|
|
312
|
+
return text;
|
|
313
|
+
}
|
|
314
|
+
finally {
|
|
315
|
+
release();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
})
|
|
319
|
+
});
|
|
320
|
+
const tagGetter = createSandboxClosure({ guest: true, sandbox: true, name: "get [Symbol.toStringTag]", length: 0,
|
|
321
|
+
call: (_args, context) => isFloat32Array(context?.thisValue) ? "Float32Array" : undefined });
|
|
322
|
+
getters.push(tagGetter);
|
|
323
|
+
Object.defineProperty(shared, Symbol.toStringTag, { get: accessorAdapter(tagGetter, "get"), configurable: true });
|
|
324
|
+
for (const key of ["values", "keys", "entries"]) {
|
|
325
|
+
const method = getSandboxDataProperty(arrayPrototype, key, budget);
|
|
326
|
+
const closure = createSandboxClosure({ guest: true, sandbox: true, name: key, length: 0,
|
|
327
|
+
call: (args, context) => {
|
|
328
|
+
if (!isFloat32Array(context?.thisValue))
|
|
329
|
+
throw new TypeError(`TypedArray ${key} requires a typed array receiver.`);
|
|
330
|
+
float32Storage(context.thisValue, true);
|
|
331
|
+
return invokeBuiltinClosure(method, args, budget, context, context.thisValue);
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
Object.defineProperty(shared, key, { value: closure, writable: true, configurable: true });
|
|
335
|
+
if (key === "values")
|
|
336
|
+
Object.defineProperty(shared, Symbol.iterator, { value: closure, writable: true, configurable: true });
|
|
337
|
+
}
|
|
338
|
+
float32Prototypes.set(budget, prototype);
|
|
339
|
+
registerBuiltinIdentities(budget, { Float32Array: constructor, "%TypedArray%": typedArray });
|
|
340
|
+
registerIntrinsicFunction(budget, constructor);
|
|
341
|
+
registerIntrinsicFunction(budget, typedArray);
|
|
342
|
+
registerIntrinsicObject(budget, prototype);
|
|
343
|
+
registerIntrinsicObject(budget, shared);
|
|
344
|
+
for (const getter of getters)
|
|
345
|
+
registerIntrinsicFunction(budget, getter);
|
|
346
|
+
}
|
|
40
347
|
export function isFloat32ArrayConstructor(value) {
|
|
41
348
|
return typeof value === "object" && value !== null && constructors.has(value);
|
|
42
349
|
}
|
|
43
|
-
export function getFloat32Member(value, property, budget) {
|
|
350
|
+
export function getFloat32Member(value, property, budget, defaultConstructor) {
|
|
44
351
|
const key = String(property);
|
|
45
352
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
46
353
|
if (descriptor !== undefined) {
|
|
@@ -48,6 +355,8 @@ export function getFloat32Member(value, property, budget) {
|
|
|
48
355
|
throw new TypeError("Float32Array accessors are not supported.");
|
|
49
356
|
return descriptor.value;
|
|
50
357
|
}
|
|
358
|
+
if (float32Prototypes.has(budget))
|
|
359
|
+
return undefined;
|
|
51
360
|
const storage = float32Storage(value);
|
|
52
361
|
if (key === "length")
|
|
53
362
|
return storage.length;
|
|
@@ -60,6 +369,7 @@ export function getFloat32Member(value, property, budget) {
|
|
|
60
369
|
if (!["set", "slice", "subarray"].includes(key))
|
|
61
370
|
return undefined;
|
|
62
371
|
return createSandboxClosure({
|
|
372
|
+
guest: true,
|
|
63
373
|
sandbox: true,
|
|
64
374
|
name: key,
|
|
65
375
|
length: key === "set" ? 1 : 2,
|
|
@@ -67,64 +377,149 @@ export function getFloat32Member(value, property, budget) {
|
|
|
67
377
|
const receiver = context?.thisValue;
|
|
68
378
|
if (!isFloat32Array(receiver))
|
|
69
379
|
throw new TypeError(`Float32Array#${key} requires a Float32Array receiver.`);
|
|
70
|
-
const storage = float32Storage(receiver);
|
|
380
|
+
const storage = float32Storage(receiver, key === "slice");
|
|
381
|
+
const bridge = {
|
|
382
|
+
...context, stack: context?.stack ?? [], thisValue: receiver,
|
|
383
|
+
getProperty: context?.getProperty ?? ((value, property) => {
|
|
384
|
+
const descriptor = getSandboxPropertyDescriptor(value, property, budget);
|
|
385
|
+
return descriptor === undefined ? getSandboxDataProperty(value, property, budget)
|
|
386
|
+
: readPropertyDescriptor(descriptor, value, bridge);
|
|
387
|
+
}),
|
|
388
|
+
invokeClosure: context?.invokeClosure ?? ((callee, values, thisValue, construct) => invokeBuiltinClosure(callee, values, budget, context, thisValue, construct))
|
|
389
|
+
};
|
|
71
390
|
if (key === "set") {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
391
|
+
return (async () => {
|
|
392
|
+
const [source, offsetValue = 0] = args;
|
|
393
|
+
let current;
|
|
394
|
+
let sourceObject;
|
|
395
|
+
const release = retainValues(budget, () => [receiver, sourceObject, current, ...args]);
|
|
396
|
+
try {
|
|
397
|
+
const number = await sandboxNumber(offsetValue, budget, bridge);
|
|
398
|
+
const offset = Number.isNaN(number) ? 0 : Math.trunc(number);
|
|
399
|
+
if (offset < 0)
|
|
400
|
+
throw new RangeError("Float32Array#set offset is out of bounds.");
|
|
401
|
+
const targetStorage = float32Storage(receiver, true);
|
|
402
|
+
if (source === null || source === undefined)
|
|
403
|
+
throw new TypeError("Float32Array#set requires a non-null source.");
|
|
404
|
+
let length;
|
|
405
|
+
if (isFloat32Array(source))
|
|
406
|
+
length = float32Storage(source, true).length;
|
|
407
|
+
else {
|
|
408
|
+
sourceObject = typeof source === "object" ? source : createSandboxBox(source);
|
|
409
|
+
current = await bridge.getProperty(sourceObject, "length");
|
|
410
|
+
const size = await sandboxNumber(current, budget, bridge);
|
|
411
|
+
length = Number.isNaN(size) || size <= 0 ? 0 : Math.min(Math.trunc(size), Number.MAX_SAFE_INTEGER);
|
|
412
|
+
}
|
|
413
|
+
if (offset + length > targetStorage.length)
|
|
414
|
+
throw new RangeError("Float32Array#set source is out of bounds.");
|
|
415
|
+
if (isFloat32Array(source))
|
|
416
|
+
Float32Array.prototype.set.call(receiver, source, offset);
|
|
417
|
+
else
|
|
418
|
+
for (let index = 0; index < length; index++) {
|
|
419
|
+
budget.visitNode();
|
|
420
|
+
current = await bridge.getProperty(sourceObject, String(index));
|
|
421
|
+
receiver[offset + index] = await sandboxNumber(current, budget, bridge);
|
|
422
|
+
}
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
finally {
|
|
426
|
+
release();
|
|
427
|
+
}
|
|
428
|
+
})();
|
|
429
|
+
}
|
|
430
|
+
return (async () => {
|
|
431
|
+
let candidate;
|
|
432
|
+
let result;
|
|
433
|
+
const release = retainValues(budget, () => [receiver, candidate, result, ...args]);
|
|
434
|
+
try {
|
|
435
|
+
const start = relativeIndex(await sandboxNumber(args[0], budget, bridge), storage.length);
|
|
436
|
+
const end = args[1] === undefined ? storage.length
|
|
437
|
+
: relativeIndex(await sandboxNumber(args[1], budget, bridge), storage.length);
|
|
438
|
+
const length = Math.max(end - start, 0);
|
|
439
|
+
const layout = float32ViewLayouts.get(receiver);
|
|
440
|
+
const offset = (layout?.byteOffset ?? storage.byteOffset) + start * 4;
|
|
441
|
+
const tracking = layout !== undefined && layout.length === undefined && args[1] === undefined;
|
|
442
|
+
if (defaultConstructor !== undefined) {
|
|
443
|
+
candidate = await bridge.getProperty(receiver, "constructor");
|
|
444
|
+
if (candidate !== undefined) {
|
|
445
|
+
if (candidate === null || typeof candidate !== "object")
|
|
446
|
+
throw new TypeError("TypedArray constructor must be an object.");
|
|
447
|
+
candidate = await bridge.getProperty(candidate, Symbol.species);
|
|
448
|
+
if (candidate !== undefined && candidate !== null &&
|
|
449
|
+
(!isSandboxClosure(candidate) || candidate.construct === undefined))
|
|
450
|
+
throw new TypeError("TypedArray species must be a constructor.");
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (candidate !== undefined && candidate !== null && candidate !== defaultConstructor) {
|
|
454
|
+
const values = key === "slice" ? [length]
|
|
455
|
+
: [storage.buffer, offset, tracking ? undefined : length];
|
|
456
|
+
result = await invokeBuiltinClosure(candidate, values, budget, bridge, undefined, true);
|
|
457
|
+
if (!isFloat32Array(result))
|
|
458
|
+
throw new TypeError("TypedArray species must return typed storage.");
|
|
459
|
+
const target = float32Storage(result, key === "slice");
|
|
460
|
+
if (key === "slice" && target.length < length)
|
|
461
|
+
throw new TypeError("TypedArray species returned insufficient storage.");
|
|
462
|
+
}
|
|
463
|
+
if (key === "subarray") {
|
|
464
|
+
if (result === undefined) {
|
|
465
|
+
result = new Float32Array(storage.buffer, offset, tracking ? undefined : length);
|
|
466
|
+
if (arrayBufferOptions(storage.buffer) !== undefined)
|
|
467
|
+
float32ViewLayouts.set(result, { byteOffset: offset, ...(tracking ? {} : { length }) });
|
|
468
|
+
}
|
|
469
|
+
return result;
|
|
470
|
+
}
|
|
471
|
+
if (result === undefined) {
|
|
472
|
+
checkFloat32Allocation(length, budget);
|
|
473
|
+
result = new Float32Array(length);
|
|
474
|
+
}
|
|
475
|
+
if (!isFloat32Array(result))
|
|
476
|
+
throw new TypeError("TypedArray species must return typed storage.");
|
|
477
|
+
if (length > 0) {
|
|
478
|
+
const current = float32Storage(receiver, true);
|
|
479
|
+
const target = float32Storage(result, true);
|
|
480
|
+
const count = Math.min(length, Math.max(current.length - start, 0));
|
|
481
|
+
if (count > 0) {
|
|
482
|
+
const sourceBytes = new Uint8Array(current.buffer, current.byteOffset + start * 4, count * 4);
|
|
483
|
+
const targetBytes = new Uint8Array(target.buffer, target.byteOffset, count * 4);
|
|
484
|
+
if (current.buffer === target.buffer && targetBytes.byteOffset > sourceBytes.byteOffset &&
|
|
485
|
+
targetBytes.byteOffset < sourceBytes.byteOffset + sourceBytes.length) {
|
|
486
|
+
for (let index = 0; index < sourceBytes.length; index++) {
|
|
487
|
+
budget.visitNode();
|
|
488
|
+
targetBytes[index] = sourceBytes[index];
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
else
|
|
492
|
+
targetBytes.set(sourceBytes);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return result;
|
|
83
496
|
}
|
|
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);
|
|
497
|
+
finally {
|
|
498
|
+
release();
|
|
92
499
|
}
|
|
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;
|
|
500
|
+
})();
|
|
105
501
|
}
|
|
106
502
|
});
|
|
107
503
|
}
|
|
108
|
-
export function setFloat32Member(value, property, entry) {
|
|
109
|
-
const key = String(property);
|
|
110
|
-
if (isFloat32Index(key)) {
|
|
504
|
+
export function setFloat32Member(value, property, entry, budget) {
|
|
505
|
+
const key = typeof property === "symbol" ? property : String(property);
|
|
506
|
+
if (typeof key !== "symbol" && isFloat32Index(key)) {
|
|
111
507
|
Reflect.set(value, key, float32Number(entry));
|
|
112
508
|
return;
|
|
113
509
|
}
|
|
114
510
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
115
|
-
|
|
511
|
+
const inherited = descriptor ?? (budget === undefined ? undefined : getSandboxPropertyDescriptor(value, key, budget));
|
|
512
|
+
if (descriptor === undefined && typeof key === "string" &&
|
|
513
|
+
(budget === undefined || !float32Prototypes.has(budget)) &&
|
|
116
514
|
["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}'.`);
|
|
515
|
+
throw new TypeError(`Cannot assign to read only property '${String(key)}'.`);
|
|
516
|
+
if (inherited !== undefined && (!("value" in inherited) || !inherited.writable))
|
|
517
|
+
throw new TypeError(`Cannot assign to read only property '${String(key)}'.`);
|
|
120
518
|
Object.defineProperty(value, key, descriptor === undefined
|
|
121
519
|
? { value: entry, configurable: true, enumerable: true, writable: true }
|
|
122
520
|
: { value: entry });
|
|
123
521
|
}
|
|
124
|
-
function relativeIndex(
|
|
125
|
-
if (value === undefined)
|
|
126
|
-
return fallback;
|
|
127
|
-
const numeric = float32Number(value);
|
|
522
|
+
function relativeIndex(numeric, length) {
|
|
128
523
|
const integer = Number.isNaN(numeric) ? 0 : Math.trunc(numeric);
|
|
129
524
|
return integer < 0 ? Math.max(length + integer, 0) : Math.min(integer, length);
|
|
130
525
|
}
|
|
@@ -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)
|
|
@@ -5,6 +5,7 @@ export declare function createBuiltinBindings(options: Parameters<typeof createC
|
|
|
5
5
|
clock?: RunClock;
|
|
6
6
|
functionHasInstance?: boolean;
|
|
7
7
|
errorPrototypes?: boolean;
|
|
8
|
+
float32Prototypes?: boolean;
|
|
8
9
|
}): {
|
|
9
10
|
RegExp: import("./values.js").SandboxClosure;
|
|
10
11
|
Promise: import("./values.js").SandboxClosure;
|
|
@@ -17,6 +18,7 @@ export declare function createBuiltinBindings(options: Parameters<typeof createC
|
|
|
17
18
|
parseFloat: import("./values.js").SandboxClosure;
|
|
18
19
|
isNaN: import("./values.js").SandboxClosure;
|
|
19
20
|
isFinite: import("./values.js").SandboxClosure;
|
|
21
|
+
ArrayBuffer: import("./values.js").SandboxClosure;
|
|
20
22
|
Object: import("./values.js").SandboxClosure;
|
|
21
23
|
Array: import("./values.js").SandboxClosure;
|
|
22
24
|
String: import("./values.js").SandboxClosure;
|