quickjs-emscripten-sync 1.8.4 → 1.9.1

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.
@@ -7,13 +7,21 @@ export default function marshalProperties(
7
7
  target: object | ((...args: any[]) => any),
8
8
  handle: QuickJSHandle,
9
9
  marshal: (target: unknown) => QuickJSHandle,
10
+ disposeTransient: (handle: QuickJSHandle) => void = () => {},
10
11
  ): void {
11
12
  const descs = ctx.newObject();
13
+ // Property values may be transient (json copies / BigInt) with no owner; once
14
+ // `Object.defineProperties` has copied them into `handle` the standalone
15
+ // handles are redundant and disposed below. Owned handles are left untouched.
16
+ const transient: QuickJSHandle[] = [];
12
17
  const cb = (key: string | number | symbol, desc: PropertyDescriptor) => {
13
18
  const keyHandle = marshal(key);
14
19
  const valueHandle = typeof desc.value === "undefined" ? undefined : marshal(desc.value);
15
20
  const getHandle = typeof desc.get === "undefined" ? undefined : marshal(desc.get);
16
21
  const setHandle = typeof desc.set === "undefined" ? undefined : marshal(desc.set);
22
+ if (valueHandle) transient.push(valueHandle);
23
+ if (getHandle) transient.push(getHandle);
24
+ if (setHandle) transient.push(setHandle);
17
25
 
18
26
  ctx.newObject().consume(descObj => {
19
27
  Object.entries(desc).forEach(([k, v]) => {
@@ -35,11 +43,16 @@ export default function marshalProperties(
35
43
  });
36
44
  };
37
45
 
38
- const desc = Object.getOwnPropertyDescriptors(target);
39
- Object.entries(desc).forEach(([k, v]) => cb(k, v));
40
- Object.getOwnPropertySymbols(desc).forEach(k => cb(k, (desc as any)[k]));
46
+ try {
47
+ const desc = Object.getOwnPropertyDescriptors(target);
48
+ Object.entries(desc).forEach(([k, v]) => cb(k, v));
49
+ Object.getOwnPropertySymbols(desc).forEach(k => cb(k, (desc as any)[k]));
41
50
 
42
- call(ctx, `Object.defineProperties`, undefined, handle, descs).dispose();
43
-
44
- descs.dispose();
51
+ call(ctx, `Object.defineProperties`, undefined, handle, descs).dispose();
52
+ // Safe only after defineProperties has dup'd the values into `handle`; `descs`
53
+ // still holds its own references until its own dispose() in the finally.
54
+ for (const h of transient) disposeTransient(h);
55
+ } finally {
56
+ descs.dispose();
57
+ }
45
58
  }
@@ -1,6 +1,6 @@
1
1
  import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
2
 
3
- import { call } from "../vmutil";
3
+ import { call, consume } from "../vmutil";
4
4
 
5
5
  export default function unmarshalCustom(
6
6
  ctx: QuickJSContext,
@@ -23,9 +23,40 @@ export function symbol(handle: QuickJSHandle, ctx: QuickJSContext): symbol | und
23
23
  }
24
24
 
25
25
  export function date(handle: QuickJSHandle, ctx: QuickJSContext): Date | undefined {
26
- if (!ctx.dump(call(ctx, "a => a instanceof Date", undefined, handle))) return;
27
- const t = ctx.getNumber(call(ctx, "a => a.getTime()", undefined, handle));
26
+ if (!consume(call(ctx, "a => a instanceof Date", undefined, handle), h => ctx.dump(h))) return;
27
+ const t = consume(call(ctx, "a => a.getTime()", undefined, handle), h => ctx.getNumber(h));
28
28
  return new Date(t);
29
29
  }
30
30
 
31
- export const defaultCustom = [symbol, date];
31
+ export function arrayBuffer(
32
+ handle: QuickJSHandle,
33
+ ctx: QuickJSContext,
34
+ ): ArrayBuffer | ArrayBufferView | undefined {
35
+ if (consume(call(ctx, "a => a instanceof ArrayBuffer", undefined, handle), h => ctx.dump(h))) {
36
+ const lifetime = ctx.getArrayBuffer(handle);
37
+ const copy = lifetime.value.slice();
38
+ lifetime.dispose();
39
+ return copy.buffer;
40
+ }
41
+
42
+ if (consume(call(ctx, "a => ArrayBuffer.isView(a)", undefined, handle), h => ctx.dump(h))) {
43
+ const name = consume(call(ctx, "a => a.constructor.name", undefined, handle), h =>
44
+ ctx.getString(h),
45
+ );
46
+ const Ctor = (globalThis as any)[name];
47
+ if (typeof Ctor !== "function") return;
48
+ const bufHandle = call(
49
+ ctx,
50
+ "a => a.buffer.slice(a.byteOffset, a.byteOffset + a.byteLength)",
51
+ undefined,
52
+ handle,
53
+ );
54
+ const lifetime = ctx.getArrayBuffer(bufHandle);
55
+ const bytes = lifetime.value.slice();
56
+ lifetime.dispose();
57
+ bufHandle.dispose();
58
+ return new Ctor(bytes.buffer);
59
+ }
60
+ }
61
+
62
+ export const defaultCustom = [symbol, date, arrayBuffer];
@@ -1,6 +1,6 @@
1
1
  import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
2
 
3
- import { call, mayConsumeAll } from "../vmutil";
3
+ import { call, mayConsumeAll, unwrapResult } from "../vmutil";
4
4
 
5
5
  import unmarshalProperties from "./properties";
6
6
 
@@ -26,7 +26,7 @@ export default function unmarshalFunction(
26
26
  return this;
27
27
  }
28
28
 
29
- const resultHandle = ctx.unwrapResult(ctx.callFunction(handle, thisHandle, ...argHandles));
29
+ const resultHandle = unwrapResult(ctx, ctx.callFunction(handle, thisHandle, ...argHandles));
30
30
 
31
31
  const [result, alreadyExists] = unmarshal(resultHandle);
32
32
  if (alreadyExists) resultHandle.dispose();
@@ -0,0 +1,21 @@
1
+ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
+
3
+ /**
4
+ * If `handle` is an opaque HostRef, resolve it back to the original host value.
5
+ * Returns a wrapper so the caller can tell "resolved to a falsy value" apart
6
+ * from "not a HostRef". `toHostRef` is cheap for non-HostRef handles.
7
+ */
8
+ export default function unmarshalHostRef(
9
+ ctx: QuickJSContext,
10
+ handle: QuickJSHandle,
11
+ ): { value: unknown } | undefined {
12
+ const ref = ctx.toHostRef(handle);
13
+ if (!ref) return;
14
+ try {
15
+ return { value: ref.value };
16
+ } finally {
17
+ // toHostRef returns a HostRef wrapping a *dup* of the handle, so disposing
18
+ // it does not affect the caller's handle.
19
+ ref.dispose();
20
+ }
21
+ }
@@ -2,6 +2,8 @@ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
2
 
3
3
  import unmarshalCustom, { defaultCustom } from "./custom";
4
4
  import unmarshalFunction from "./function";
5
+ import unmarshalHostRef from "./hostref";
6
+ import unmarshalMapSet from "./mapset";
5
7
  import unmarshalObject from "./object";
6
8
  import unmarshalPrimitive from "./primitive";
7
9
  import unmarshalPromise from "./promise";
@@ -13,6 +15,8 @@ export type Options = {
13
15
  find: (handle: QuickJSHandle) => unknown | undefined;
14
16
  pre: <T = unknown>(target: T, handle: QuickJSHandle) => T | undefined;
15
17
  custom?: Iterable<(obj: QuickJSHandle, ctx: QuickJSContext) => any>;
18
+ /** When true, resolve opaque HostRef handles back to their host value. */
19
+ hostRef?: boolean;
16
20
  };
17
21
 
18
22
  export function unmarshal(handle: QuickJSHandle, options: Options): any {
@@ -37,8 +41,24 @@ function unmarshalInner(handle: QuickJSHandle, options: Options): [any, boolean]
37
41
 
38
42
  const unmarshal2 = (h: QuickJSHandle) => unmarshalInner(h, options);
39
43
 
44
+ // Opaque HostRef handles resolve back to the original host value by reference.
45
+ if (options.hostRef) {
46
+ const ref = unmarshalHostRef(ctx, handle);
47
+ if (ref) return [ref.value, true];
48
+ }
49
+
50
+ // Custom types (Symbol, Date, ArrayBuffer, TypedArray, ...) are unmarshalled
51
+ // by value and not tracked in the map, so their source handle is not owned by
52
+ // anyone else and the caller must dispose it.
53
+ const custom = unmarshalCustom(ctx, handle, pre, [...defaultCustom, ...(options.custom ?? [])]);
54
+ if (custom) return [custom, true];
55
+
56
+ // Map/Set are unmarshalled by value (snapshot copy), so the source handle is
57
+ // not tracked and the caller must dispose it.
58
+ const mapSet = unmarshalMapSet(ctx, handle, unmarshal2, pre);
59
+ if (mapSet) return [mapSet, true];
60
+
40
61
  const result =
41
- unmarshalCustom(ctx, handle, pre, [...defaultCustom, ...(options.custom ?? [])]) ??
42
62
  unmarshalPromise(ctx, handle, marshal, pre) ??
43
63
  unmarshalFunction(ctx, handle, marshal, unmarshal2, pre) ??
44
64
  unmarshalObject(ctx, handle, unmarshal2, pre);
@@ -0,0 +1,43 @@
1
+ import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
+
3
+ import { call, consume } from "../vmutil";
4
+
5
+ export default function unmarshalMapSet(
6
+ ctx: QuickJSContext,
7
+ handle: QuickJSHandle,
8
+ unmarshal: (handle: QuickJSHandle) => [unknown, boolean],
9
+ preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined,
10
+ ): Map<any, any> | Set<any> | undefined {
11
+ const isMap = consume(call(ctx, "a => a instanceof Map", undefined, handle), h => ctx.dump(h));
12
+ const isSet =
13
+ !isMap && consume(call(ctx, "a => a instanceof Set", undefined, handle), h => ctx.dump(h));
14
+ if (!isMap && !isSet) return;
15
+
16
+ const result: Map<any, any> | Set<any> = isMap ? new Map() : new Set();
17
+ preUnmarshal(result, handle);
18
+
19
+ const iterator = ctx.unwrapResult(ctx.getIterator(handle));
20
+ try {
21
+ for (const elResult of iterator) {
22
+ const el = ctx.unwrapResult(elResult);
23
+ if (isMap) {
24
+ const keyHandle = ctx.getProp(el, 0);
25
+ const valueHandle = ctx.getProp(el, 1);
26
+ const [key, disposeKey] = unmarshal(keyHandle);
27
+ const [value, disposeValue] = unmarshal(valueHandle);
28
+ if (disposeKey) keyHandle.dispose();
29
+ if (disposeValue) valueHandle.dispose();
30
+ (result as Map<any, any>).set(key, value);
31
+ el.dispose();
32
+ } else {
33
+ const [value, disposeValue] = unmarshal(el);
34
+ if (disposeValue) el.dispose();
35
+ (result as Set<any>).add(value);
36
+ }
37
+ }
38
+ } finally {
39
+ if (iterator.alive) iterator.dispose();
40
+ }
41
+
42
+ return result;
43
+ }
@@ -1,6 +1,6 @@
1
1
  import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
2
 
3
- import { call } from "../vmutil";
3
+ import { call, consume } from "../vmutil";
4
4
 
5
5
  import unmarshalProperties from "./properties";
6
6
 
@@ -10,31 +10,27 @@ export default function unmarshalObject(
10
10
  unmarshal: (handle: QuickJSHandle) => [unknown, boolean],
11
11
  preUnmarshal: <T>(target: T, handle: QuickJSHandle) => T | undefined,
12
12
  ): object | undefined {
13
- if (
14
- ctx.typeof(handle) !== "object" ||
15
- // null check
16
- ctx
17
- .unwrapResult(ctx.evalCode("o => o === null"))
18
- .consume(n => ctx.dump(ctx.unwrapResult(ctx.callFunction(n, ctx.undefined, handle))))
19
- )
20
- return;
13
+ if (ctx.typeof(handle) !== "object" || ctx.sameValue(handle, ctx.null)) return;
21
14
 
22
- const raw = call(ctx, "Array.isArray", undefined, handle).consume(r => ctx.dump(r)) ? [] : {};
15
+ const raw = consume(call(ctx, "Array.isArray", undefined, handle), r => ctx.dump(r)) ? [] : {};
23
16
  const obj = preUnmarshal(raw, handle) ?? raw;
24
17
 
25
- const prototype = call(
26
- ctx,
27
- `o => {
18
+ const prototype = consume(
19
+ call(
20
+ ctx,
21
+ `o => {
28
22
  const p = Object.getPrototypeOf(o);
29
23
  return !p || p === Object.prototype || p === Array.prototype ? undefined : p;
30
24
  }`,
31
- undefined,
32
- handle,
33
- ).consume(prototype => {
34
- if (ctx.typeof(prototype) === "undefined") return;
35
- const [proto] = unmarshal(prototype);
36
- return proto;
37
- });
25
+ undefined,
26
+ handle,
27
+ ),
28
+ prototype => {
29
+ if (ctx.typeof(prototype) === "undefined") return;
30
+ const [proto] = unmarshal(prototype);
31
+ return proto;
32
+ },
33
+ );
38
34
  if (typeof prototype === "object") {
39
35
  Object.setPrototypeOf(obj, prototype);
40
36
  }
@@ -7,24 +7,13 @@ export default function unmarshalPrimitive(
7
7
  const ty = ctx.typeof(handle);
8
8
  if (ty === "undefined" || ty === "number" || ty === "string" || ty === "boolean") {
9
9
  return [ctx.dump(handle), true];
10
- } else if (ty === "object") {
11
- const isNull = ctx
12
- .unwrapResult(ctx.evalCode("a => a === null"))
13
- .consume(n => ctx.dump(ctx.unwrapResult(ctx.callFunction(n, ctx.undefined, handle))));
14
- if (isNull) {
15
- return [null, true];
16
- }
17
10
  }
18
-
19
- // BigInt is not supported by quickjs-emscripten
20
- // if (ty === "bigint") {
21
- // const str = ctx
22
- // .getProp(handle, "toString")
23
- // .consume(toString => vm.unwrapResult(vm.callFunction(toString, handle)))
24
- // .consume(str => ctx.getString(str));
25
- // const bi = BigInt(str);
26
- // return [bi, true];
27
- // }
11
+ if (ty === "bigint") {
12
+ return [ctx.getBigInt(handle), true];
13
+ }
14
+ if (ty === "object" && ctx.sameValue(handle, ctx.null)) {
15
+ return [null, true];
16
+ }
28
17
 
29
18
  return [undefined, false];
30
19
  }
@@ -1,6 +1,6 @@
1
1
  import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
2
 
3
- import { call } from "../vmutil";
3
+ import { call, consume } from "../vmutil";
4
4
 
5
5
  export default function unmarshalProperties(
6
6
  ctx: QuickJSContext,
@@ -8,8 +8,8 @@ export default function unmarshalProperties(
8
8
  target: object | ((...args: any[]) => any),
9
9
  unmarshal: (handle: QuickJSHandle) => [unknown, boolean],
10
10
  ) {
11
- ctx
12
- .newFunction("", (key, value) => {
11
+ consume(
12
+ ctx.newFunction("", (key, value) => {
13
13
  const [keyName] = unmarshal(key);
14
14
  if (typeof keyName !== "string" && typeof keyName !== "number" && typeof keyName !== "symbol")
15
15
  return;
@@ -43,8 +43,8 @@ export default function unmarshalProperties(
43
43
  }, {});
44
44
 
45
45
  Object.defineProperty(target, keyName, desc);
46
- })
47
- .consume(fn => {
46
+ }),
47
+ fn => {
48
48
  call(
49
49
  ctx,
50
50
  `(o, fn) => {
@@ -56,5 +56,6 @@ export default function unmarshalProperties(
56
56
  handle,
57
57
  fn,
58
58
  ).dispose();
59
- });
59
+ },
60
+ );
60
61
  }
package/src/vmmap.ts CHANGED
@@ -1,18 +1,29 @@
1
1
  import type { QuickJSContext, QuickJSHandle } from "quickjs-emscripten";
2
2
 
3
+ import { unwrapResult } from "./vmutil";
4
+
5
+ /**
6
+ * Bidirectional map between host values and QuickJS handles.
7
+ *
8
+ * Each registered pair gets a numeric id. A value may be registered under two
9
+ * keys (e.g. a proxy-wrapped object and the underlying object), each with its
10
+ * own handle, so every lookup direction is backed by an explicit map and id
11
+ * reverse-lookups, keeping `delete` O(1).
12
+ */
3
13
  export default class VMMap {
4
14
  ctx: QuickJSContext;
5
- _map1 = new Map<any, number>();
6
- _map2 = new Map<any, number>();
7
- _map3 = new Map<number, QuickJSHandle>();
8
- _map4 = new Map<number, QuickJSHandle>();
9
- _counterMap = new Map<number, any>();
15
+ _keyToId = new Map<any, number>();
16
+ _key2ToId = new Map<any, number>();
17
+ _idToHandle = new Map<number, QuickJSHandle>();
18
+ _idToHandle2 = new Map<number, QuickJSHandle>();
19
+ _idToKey = new Map<number, any>();
20
+ _idToKey2 = new Map<number, any>();
10
21
  _disposables = new Set<QuickJSHandle>();
11
22
  _mapGet: QuickJSHandle;
12
23
  _mapSet: QuickJSHandle;
13
24
  _mapDelete: QuickJSHandle;
14
25
  _mapClear: QuickJSHandle;
15
- _counter = Number.MIN_SAFE_INTEGER;
26
+ _nextId = Number.MIN_SAFE_INTEGER;
16
27
 
17
28
  constructor(ctx: QuickJSContext) {
18
29
  this.ctx = ctx;
@@ -68,18 +79,19 @@ export default class VMMap {
68
79
  return v === handle || v === handle2;
69
80
  }
70
81
 
71
- const counter = this._counter++;
72
- this._map1.set(key, counter);
73
- this._map3.set(counter, handle);
74
- this._counterMap.set(counter, key);
82
+ const id = this._nextId++;
83
+ this._keyToId.set(key, id);
84
+ this._idToHandle.set(id, handle);
85
+ this._idToKey.set(id, key);
75
86
  if (key2) {
76
- this._map2.set(key2, counter);
87
+ this._key2ToId.set(key2, id);
88
+ this._idToKey2.set(id, key2);
77
89
  if (handle2) {
78
- this._map4.set(counter, handle2);
90
+ this._idToHandle2.set(id, handle2);
79
91
  }
80
92
  }
81
93
 
82
- this.ctx.newNumber(counter).consume(c => {
94
+ this.ctx.newNumber(id).consume(c => {
83
95
  this._call(this._mapSet, undefined, handle, c, handle2 ?? this.ctx.undefined);
84
96
  });
85
97
 
@@ -104,8 +116,8 @@ export default class VMMap {
104
116
  }
105
117
 
106
118
  get(key: any) {
107
- const num = this._map1.get(key) ?? this._map2.get(key);
108
- const handle = typeof num === "number" ? this._map3.get(num) : undefined;
119
+ const id = this._keyToId.get(key) ?? this._key2ToId.get(key);
120
+ const handle = typeof id === "number" ? this._idToHandle.get(id) : undefined;
109
121
 
110
122
  if (!handle) return;
111
123
  if (!handle.alive) {
@@ -120,7 +132,7 @@ export default class VMMap {
120
132
  if (!handle.alive) {
121
133
  return;
122
134
  }
123
- return this._counterMap.get(this.ctx.getNumber(this._call(this._mapGet, undefined, handle)));
135
+ return this._idToKey.get(this.ctx.getNumber(this._call(this._mapGet, undefined, handle)));
124
136
  }
125
137
 
126
138
  has(key: any) {
@@ -132,46 +144,29 @@ export default class VMMap {
132
144
  }
133
145
 
134
146
  keys() {
135
- return this._map1.keys();
147
+ return this._keyToId.keys();
136
148
  }
137
149
 
138
150
  delete(key: any, dispose?: boolean) {
139
- const num = this._map1.get(key) ?? this._map2.get(key);
140
- if (typeof num === "undefined") return;
151
+ const id = this._keyToId.get(key) ?? this._key2ToId.get(key);
152
+ if (typeof id === "undefined") return;
141
153
 
142
- const handle = this._map3.get(num);
143
- const handle2 = this._map4.get(num);
154
+ const handle = this._idToHandle.get(id);
155
+ const handle2 = this._idToHandle2.get(id);
144
156
  this._call(
145
157
  this._mapDelete,
146
158
  undefined,
147
159
  ...[handle, handle2].filter((h): h is QuickJSHandle => !!h?.alive),
148
160
  );
149
161
 
150
- this._map1.delete(key);
151
- this._map2.delete(key);
152
- this._map3.delete(num);
153
- this._map4.delete(num);
154
-
155
- for (const [k, v] of this._map1) {
156
- if (v === num) {
157
- this._map1.delete(k);
158
- break;
159
- }
160
- }
161
-
162
- for (const [k, v] of this._map2) {
163
- if (v === num) {
164
- this._map2.delete(k);
165
- break;
166
- }
167
- }
168
-
169
- for (const [k, v] of this._counterMap) {
170
- if (v === key) {
171
- this._counterMap.delete(k);
172
- break;
173
- }
174
- }
162
+ const key1 = this._idToKey.get(id);
163
+ const key2 = this._idToKey2.get(id);
164
+ if (typeof key1 !== "undefined") this._keyToId.delete(key1);
165
+ if (typeof key2 !== "undefined") this._key2ToId.delete(key2);
166
+ this._idToHandle.delete(id);
167
+ this._idToHandle2.delete(id);
168
+ this._idToKey.delete(id);
169
+ this._idToKey2.delete(id);
175
170
 
176
171
  if (dispose) {
177
172
  if (handle?.alive) handle.dispose();
@@ -187,12 +182,13 @@ export default class VMMap {
187
182
  }
188
183
 
189
184
  clear() {
190
- this._counter = 0;
191
- this._map1.clear();
192
- this._map2.clear();
193
- this._map3.clear();
194
- this._map4.clear();
195
- this._counterMap.clear();
185
+ this._nextId = 0;
186
+ this._keyToId.clear();
187
+ this._key2ToId.clear();
188
+ this._idToHandle.clear();
189
+ this._idToHandle2.clear();
190
+ this._idToKey.clear();
191
+ this._idToKey2.clear();
196
192
  if (this._mapClear.alive) {
197
193
  this._call(this._mapClear, undefined);
198
194
  }
@@ -204,12 +200,12 @@ export default class VMMap {
204
200
  v.dispose();
205
201
  }
206
202
  }
207
- for (const v of this._map3.values()) {
203
+ for (const v of this._idToHandle.values()) {
208
204
  if (v.alive) {
209
205
  v.dispose();
210
206
  }
211
207
  }
212
- for (const v of this._map4.values()) {
208
+ for (const v of this._idToHandle2.values()) {
213
209
  if (v.alive) {
214
210
  v.dispose();
215
211
  }
@@ -219,37 +215,31 @@ export default class VMMap {
219
215
  }
220
216
 
221
217
  get size() {
222
- return this._map1.size;
218
+ return this._keyToId.size;
223
219
  }
224
220
 
225
221
  [Symbol.iterator](): Iterator<[any, QuickJSHandle, any, QuickJSHandle | undefined]> {
226
- const keys = this._map1.keys();
222
+ const keys = this._keyToId.keys();
227
223
  return {
228
224
  next: () => {
229
-
230
225
  while (true) {
231
226
  const k1 = keys.next();
232
227
  if (k1.done) return { value: undefined, done: true };
233
- const n = this._map1.get(k1.value);
234
- if (typeof n === "undefined") continue;
235
- const v1 = this._map3.get(n);
236
- const v2 = this._map4.get(n);
228
+ const id = this._keyToId.get(k1.value);
229
+ if (typeof id === "undefined") continue;
230
+ const v1 = this._idToHandle.get(id);
231
+ const v2 = this._idToHandle2.get(id);
237
232
  if (!v1) continue;
238
- const k2 = this._get2(n);
233
+ const k2 = this._idToKey2.get(id);
239
234
  return { value: [k1.value, v1, k2, v2], done: false };
240
235
  }
241
236
  },
242
237
  };
243
238
  }
244
239
 
245
- _get2(num: number) {
246
- for (const [k, v] of this._map2) {
247
- if (v === num) return k;
248
- }
249
- }
250
-
251
240
  _call(fn: QuickJSHandle, thisArg: QuickJSHandle | undefined, ...args: QuickJSHandle[]) {
252
- return this.ctx.unwrapResult(
241
+ return unwrapResult(
242
+ this.ctx,
253
243
  this.ctx.callFunction(
254
244
  fn,
255
245
  typeof thisArg === "undefined" ? this.ctx.undefined : thisArg,