jseption 0.0.0-stage → 0.0.2
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/LICENSE +26 -0
- package/README.md +191 -2
- package/dist/atoms.d.ts +255 -0
- package/dist/atoms.js +445 -0
- package/dist/atoms.js.map +1 -0
- package/dist/builtins/array.d.ts +3 -0
- package/dist/builtins/array.js +116 -0
- package/dist/builtins/array.js.map +1 -0
- package/dist/builtins/bigint.d.ts +3 -0
- package/dist/builtins/bigint.js +122 -0
- package/dist/builtins/bigint.js.map +1 -0
- package/dist/builtins/boolean.d.ts +2 -0
- package/dist/builtins/boolean.js +26 -0
- package/dist/builtins/boolean.js.map +1 -0
- package/dist/builtins/date.d.ts +3 -0
- package/dist/builtins/date.js +1046 -0
- package/dist/builtins/date.js.map +1 -0
- package/dist/builtins/error.d.ts +2 -0
- package/dist/builtins/error.js +154 -0
- package/dist/builtins/error.js.map +1 -0
- package/dist/builtins/function.d.ts +5 -0
- package/dist/builtins/function.js +164 -0
- package/dist/builtins/function.js.map +1 -0
- package/dist/builtins/global.d.ts +2 -0
- package/dist/builtins/global.js +29 -0
- package/dist/builtins/global.js.map +1 -0
- package/dist/builtins/index.d.ts +3 -0
- package/dist/builtins/index.js +139 -0
- package/dist/builtins/index.js.map +1 -0
- package/dist/builtins/json.d.ts +6 -0
- package/dist/builtins/json.js +984 -0
- package/dist/builtins/json.js.map +1 -0
- package/dist/builtins/mapset.d.ts +4 -0
- package/dist/builtins/mapset.js +234 -0
- package/dist/builtins/mapset.js.map +1 -0
- package/dist/builtins/math.d.ts +2 -0
- package/dist/builtins/math.js +62 -0
- package/dist/builtins/math.js.map +1 -0
- package/dist/builtins/native.d.ts +22 -0
- package/dist/builtins/native.js +250 -0
- package/dist/builtins/native.js.map +1 -0
- package/dist/builtins/number.d.ts +4 -0
- package/dist/builtins/number.js +76 -0
- package/dist/builtins/number.js.map +1 -0
- package/dist/builtins/object.d.ts +12 -0
- package/dist/builtins/object.js +575 -0
- package/dist/builtins/object.js.map +1 -0
- package/dist/builtins/promise.d.ts +13 -0
- package/dist/builtins/promise.js +582 -0
- package/dist/builtins/promise.js.map +1 -0
- package/dist/builtins/proxy.d.ts +3 -0
- package/dist/builtins/proxy.js +226 -0
- package/dist/builtins/proxy.js.map +1 -0
- package/dist/builtins/reflect.d.ts +2 -0
- package/dist/builtins/reflect.js +109 -0
- package/dist/builtins/reflect.js.map +1 -0
- package/dist/builtins/regexp.d.ts +2 -0
- package/dist/builtins/regexp.js +203 -0
- package/dist/builtins/regexp.js.map +1 -0
- package/dist/builtins/string.d.ts +4 -0
- package/dist/builtins/string.js +135 -0
- package/dist/builtins/string.js.map +1 -0
- package/dist/builtins/symbol.d.ts +3 -0
- package/dist/builtins/symbol.js +98 -0
- package/dist/builtins/symbol.js.map +1 -0
- package/dist/builtins/typedarray.d.ts +15 -0
- package/dist/builtins/typedarray.js +1838 -0
- package/dist/builtins/typedarray.js.map +1 -0
- package/dist/builtins/weakref.d.ts +18 -0
- package/dist/builtins/weakref.js +130 -0
- package/dist/builtins/weakref.js.map +1 -0
- package/dist/dump.d.ts +2 -0
- package/dist/dump.js +124 -0
- package/dist/dump.js.map +1 -0
- package/dist/embed.d.ts +18 -0
- package/dist/embed.js +286 -0
- package/dist/embed.js.map +1 -0
- package/dist/interpreter.d.ts +81 -0
- package/dist/interpreter.js +3768 -0
- package/dist/interpreter.js.map +1 -0
- package/dist/jit.d.ts +59 -0
- package/dist/jit.js +3440 -0
- package/dist/jit.js.map +1 -0
- package/dist/jit_hook.d.ts +21 -0
- package/dist/jit_hook.js +4 -0
- package/dist/jit_hook.js.map +1 -0
- package/dist/jit_runtime.d.ts +104 -0
- package/dist/jit_runtime.js +721 -0
- package/dist/jit_runtime.js.map +1 -0
- package/dist/jit_stack.d.ts +24 -0
- package/dist/jit_stack.js +227 -0
- package/dist/jit_stack.js.map +1 -0
- package/dist/jseption.d.ts +15 -0
- package/dist/jseption.js +61 -0
- package/dist/jseption.js.map +1 -0
- package/dist/opcodes.d.ts +347 -0
- package/dist/opcodes.js +322 -0
- package/dist/opcodes.js.map +1 -0
- package/dist/parser.d.ts +283 -0
- package/dist/parser.js +9752 -0
- package/dist/parser.js.map +1 -0
- package/dist/qjs.d.ts +2 -0
- package/dist/qjs.js +122 -0
- package/dist/qjs.js.map +1 -0
- package/dist/quickjs.d.ts +460 -0
- package/dist/quickjs.js +3408 -0
- package/dist/quickjs.js.map +1 -0
- package/dist/std.d.ts +4 -0
- package/dist/std.js +273 -0
- package/dist/std.js.map +1 -0
- package/dist/values.d.ts +447 -0
- package/dist/values.js +461 -0
- package/dist/values.js.map +1 -0
- package/package.json +59 -4
package/dist/quickjs.js
ADDED
|
@@ -0,0 +1,3408 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* jseption: TypeScript port of QuickJS
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2017-2025 Fabrice Bellard (original C implementation)
|
|
5
|
+
* Copyright (c) 2017-2025 Charlie Gordon (original C implementation)
|
|
6
|
+
*
|
|
7
|
+
* This file is the port of the "core" part of quickjs.c: runtime and
|
|
8
|
+
* context management, atoms, exceptions, the object model (property
|
|
9
|
+
* lookup, definition, deletion), value conversions and the abstract
|
|
10
|
+
* operators used by the interpreter and the builtins.
|
|
11
|
+
*
|
|
12
|
+
* Host-values model (docs/HOST_VALUES.md): guest objects are host objects
|
|
13
|
+
* with guest-owned prototype chains, properties are the host object's own
|
|
14
|
+
* properties (accessed through Reflect), and engine metadata lives in a
|
|
15
|
+
* WeakMap. Guest functions are strict host wrapper functions.
|
|
16
|
+
*/
|
|
17
|
+
import { jit_hooks } from "./jit_hook.js";
|
|
18
|
+
import { AtomTable, JS_ATOM_NULL, JS_ATOM_TYPE_STRING, JS_ATOM_TYPE_SYMBOL, __JS_AtomIsTaggedInt, __JS_AtomFromUInt32, __JS_AtomToUInt32, JS_ATOM_MAX_INT, JS_ATOM_length, JS_ATOM_prototype, JS_ATOM_constructor, JS_ATOM_message, JS_ATOM_stack, JS_ATOM_toString, JS_ATOM_valueOf, JS_ATOM_Symbol_toPrimitive, JS_ATOM_Symbol_iterator, JS_ATOM_Symbol_hasInstance, JS_ATOM_done, JS_ATOM_value, JS_ATOM_return, JS_ATOM_get, JS_ATOM_set, JS_ATOM_configurable, JS_ATOM_writable, JS_ATOM_enumerable, JS_ATOM_undefined, JS_ATOM_object, JS_ATOM_boolean, JS_ATOM_number, JS_ATOM_string, JS_ATOM_symbol, JS_ATOM_bigint, JS_ATOM_function, JS_ATOM_lineNumber, JS_ATOM_fileName, JS_ATOM_columnNumber, JS_ATOM_Error, JS_ATOM___proto__, JS_ATOM_Symbol_asyncIterator, JS_ATOM_null, JS_ATOM_false, JS_ATOM_true, JS_ATOM_Object, JS_ATOM_Function, JS_ATOM_Array, JS_ATOM_Number, JS_ATOM_String, JS_ATOM_Boolean, JS_ATOM_Symbol, JS_ATOM_Arguments, JS_ATOM_BigInt, JS_ATOM_Date, JS_ATOM_RegExp, JS_ATOM_Map, JS_ATOM_Set, JS_ATOM_WeakMap, JS_ATOM_WeakSet, JS_ATOM_Generator, JS_ATOM_Proxy, JS_ATOM_Promise, JS_ATOM_AsyncFunction, JS_ATOM_AsyncGenerator, JS_ATOM_GeneratorFunction, JS_ATOM_AsyncGeneratorFunction, JS_ATOM_ForInIterator, JS_ATOM_Map_Iterator, JS_ATOM_Set_Iterator, JS_ATOM_Array_Iterator, JS_ATOM_String_Iterator, JS_ATOM_RegExp_String_Iterator, JS_ATOM_PromiseResolveFunction, JS_ATOM_PromiseRejectFunction, JS_ATOM_AsyncFunctionResolve, JS_ATOM_AsyncFunctionReject, JS_ATOM_ArrayBuffer, JS_ATOM_SharedArrayBuffer, JS_ATOM_Uint8ClampedArray, JS_ATOM_Int8Array, JS_ATOM_Uint8Array, JS_ATOM_Int16Array, JS_ATOM_Uint16Array, JS_ATOM_Int32Array, JS_ATOM_Uint32Array, JS_ATOM_BigInt64Array, JS_ATOM_BigUint64Array, JS_ATOM_Float32Array, JS_ATOM_Float64Array, JS_ATOM_DataView, JS_ATOM_WeakRef, JS_ATOM_FinalizationRegistry, JS_ATOM_Module, } from "./atoms.js";
|
|
19
|
+
import { JSSpecial, JS_EXCEPTION, JS_UNINITIALIZED, JS_MODE_BACKTRACE_BARRIER, JS_PROP_CONFIGURABLE, JS_PROP_WRITABLE, JS_PROP_ENUMERABLE, JS_PROP_C_W_E, JS_PROP_TMASK, JS_PROP_GETSET, JS_PROP_HAS_CONFIGURABLE, JS_PROP_HAS_WRITABLE, JS_PROP_HAS_ENUMERABLE, JS_PROP_HAS_GET, JS_PROP_HAS_SET, JS_PROP_HAS_VALUE, JS_PROP_THROW, JS_PROP_THROW_STRICT, JS_PROP_NO_ADD, JS_GPN_STRING_MASK, JS_GPN_SYMBOL_MASK, JS_GPN_ENUM_ONLY, JS_GPN_SET_ENUM, JS_IsException, JS_IsObject, JS_IsUndefined, JSCFunctionRecord, JSCFunctionDataRecord, JSStackFrame, JS_CALL_FLAG_CONSTRUCTOR, JS_CALL_FLAG_COPY_ARGV, JSForInState, JSObjectMeta, JS_MODE_STRICT, } from "./values.js";
|
|
20
|
+
export * from "./values.js";
|
|
21
|
+
export * from "./atoms.js";
|
|
22
|
+
export class JSClass {
|
|
23
|
+
class_id;
|
|
24
|
+
class_name;
|
|
25
|
+
constructor(class_id, def) {
|
|
26
|
+
this.class_id = class_id;
|
|
27
|
+
this.class_name = def.class_name;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/* engine metadata of guest objects (class id, internal slots, bytecode).
|
|
31
|
+
Objects belong to a single runtime, so one table is shared. */
|
|
32
|
+
export const js_meta = new WeakMap();
|
|
33
|
+
/* private fields and brands: object -> (private symbol -> value) */
|
|
34
|
+
export const js_privates = new WeakMap();
|
|
35
|
+
/* direct call entries for the compiled tier: guest function object ->
|
|
36
|
+
(this_val, new_target, ...args) => result, using the host exception
|
|
37
|
+
convention. Borrowed natives register their host function here. */
|
|
38
|
+
export const js_direct = new WeakMap();
|
|
39
|
+
export function js_get_meta(obj) {
|
|
40
|
+
if (typeof obj === 'object' || typeof obj === 'function') {
|
|
41
|
+
if (obj === null)
|
|
42
|
+
return undefined;
|
|
43
|
+
return js_meta.get(obj);
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
export function js_ensure_meta(obj, class_id = 1 /* JSClassID.OBJECT */) {
|
|
48
|
+
let m = js_meta.get(obj);
|
|
49
|
+
if (!m) {
|
|
50
|
+
m = new JSObjectMeta(class_id);
|
|
51
|
+
js_meta.set(obj, m);
|
|
52
|
+
}
|
|
53
|
+
return m;
|
|
54
|
+
}
|
|
55
|
+
/* bytecode function data of a function object, or null */
|
|
56
|
+
export function JS_GetFunctionData(func) {
|
|
57
|
+
const m = js_get_meta(func);
|
|
58
|
+
return m ? m.func : null;
|
|
59
|
+
}
|
|
60
|
+
export class JSRuntime {
|
|
61
|
+
atoms = new AtomTable();
|
|
62
|
+
class_array = [];
|
|
63
|
+
class_count = 0;
|
|
64
|
+
current_exception = undefined;
|
|
65
|
+
exception_pending = false;
|
|
66
|
+
current_stack_frame = null;
|
|
67
|
+
interrupt_handler = null;
|
|
68
|
+
interrupt_opaque = null;
|
|
69
|
+
host_promise_rejection_tracker = null;
|
|
70
|
+
host_promise_rejection_tracker_opaque = null;
|
|
71
|
+
job_list = [];
|
|
72
|
+
module_normalize_func = null;
|
|
73
|
+
module_loader_func = null;
|
|
74
|
+
module_loader_opaque = null;
|
|
75
|
+
stack_depth = 0;
|
|
76
|
+
max_stack_depth = 2000;
|
|
77
|
+
user_opaque = null;
|
|
78
|
+
/* symbols registered with Symbol.for() */
|
|
79
|
+
global_symbol_registry = new Map();
|
|
80
|
+
can_block = false;
|
|
81
|
+
context_list = [];
|
|
82
|
+
interrupt_counter = 0;
|
|
83
|
+
}
|
|
84
|
+
export class JSContext {
|
|
85
|
+
rt;
|
|
86
|
+
class_proto = [];
|
|
87
|
+
function_proto = null;
|
|
88
|
+
function_ctor = null;
|
|
89
|
+
array_ctor = null;
|
|
90
|
+
regexp_ctor = null;
|
|
91
|
+
promise_ctor = null;
|
|
92
|
+
native_error_proto = [];
|
|
93
|
+
error_ctor = null;
|
|
94
|
+
error_prepare_stack = undefined;
|
|
95
|
+
error_stack_trace_limit = 10;
|
|
96
|
+
iterator_proto = null;
|
|
97
|
+
async_iterator_proto = null;
|
|
98
|
+
array_proto_values = undefined;
|
|
99
|
+
throw_type_error = null;
|
|
100
|
+
eval_obj = undefined;
|
|
101
|
+
/* the global object (an ordinary guest object) */
|
|
102
|
+
global_obj;
|
|
103
|
+
/* compiled tier: true while Object.prototype has no accessor and no read-only data
|
|
104
|
+
property (other than __proto__), so that the fields of an object literal can be
|
|
105
|
+
assigned instead of defined. Cleared by JS_DefineProperty. */
|
|
106
|
+
plain_object_proto = { ok: true };
|
|
107
|
+
/* global lexical bindings (let/const/class at the top level): an engine
|
|
108
|
+
internal object with a null prototype, never visible to guest code */
|
|
109
|
+
global_var_obj;
|
|
110
|
+
user_opaque = null;
|
|
111
|
+
loaded_modules = new Map();
|
|
112
|
+
interrupt_counter = 0;
|
|
113
|
+
array_iterator_proto = null;
|
|
114
|
+
generator_proto = null;
|
|
115
|
+
async_generator_proto = null;
|
|
116
|
+
constructor(rt) {
|
|
117
|
+
this.rt = rt;
|
|
118
|
+
for (let i = 0; i < rt.class_count; i++)
|
|
119
|
+
this.class_proto.push(null);
|
|
120
|
+
for (let i = 0; i < 8 /* JSErrorEnum.NATIVE_ERROR_COUNT */; i++)
|
|
121
|
+
this.native_error_proto.push(null);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
export const hooks = {
|
|
125
|
+
JS_CallInternal: () => { throw new Error('interpreter not loaded'); },
|
|
126
|
+
JS_EvalInternal: () => { throw new Error('parser not loaded'); },
|
|
127
|
+
JS_AddIntrinsicBaseObjects: () => { throw new Error('builtins not loaded'); },
|
|
128
|
+
js_closure: () => { throw new Error('interpreter not loaded'); },
|
|
129
|
+
js_regexp_constructor_internal: null,
|
|
130
|
+
js_borrow_native: () => { throw new Error('native builtins not loaded'); },
|
|
131
|
+
init_runtime: [],
|
|
132
|
+
};
|
|
133
|
+
export function JS_NewClass1(rt, class_id, def) {
|
|
134
|
+
while (rt.class_array.length <= class_id)
|
|
135
|
+
rt.class_array.push(null);
|
|
136
|
+
rt.class_array[class_id] = new JSClass(class_id, def);
|
|
137
|
+
if (class_id >= rt.class_count)
|
|
138
|
+
rt.class_count = class_id + 1;
|
|
139
|
+
for (const ctx of rt.context_list) {
|
|
140
|
+
while (ctx.class_proto.length < rt.class_count)
|
|
141
|
+
ctx.class_proto.push(null);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export function JS_NewClass(rt, class_id, def) {
|
|
145
|
+
JS_NewClass1(rt, class_id, def);
|
|
146
|
+
return 0;
|
|
147
|
+
}
|
|
148
|
+
let next_class_id = 56 /* JSClassID.INIT_COUNT */;
|
|
149
|
+
export function JS_NewClassID() {
|
|
150
|
+
return next_class_id++;
|
|
151
|
+
}
|
|
152
|
+
export function JS_IsRegisteredClass(rt, class_id) {
|
|
153
|
+
return class_id < rt.class_array.length && rt.class_array[class_id] !== null;
|
|
154
|
+
}
|
|
155
|
+
/* class definitions of the predefined classes */
|
|
156
|
+
const js_std_class_def = [
|
|
157
|
+
[1 /* JSClassID.OBJECT */, JS_ATOM_Object],
|
|
158
|
+
[2 /* JSClassID.ARRAY */, JS_ATOM_Array],
|
|
159
|
+
[3 /* JSClassID.ERROR */, JS_ATOM_Error],
|
|
160
|
+
[4 /* JSClassID.NUMBER */, JS_ATOM_Number],
|
|
161
|
+
[5 /* JSClassID.STRING */, JS_ATOM_String],
|
|
162
|
+
[6 /* JSClassID.BOOLEAN */, JS_ATOM_Boolean],
|
|
163
|
+
[7 /* JSClassID.SYMBOL */, JS_ATOM_Symbol],
|
|
164
|
+
[8 /* JSClassID.ARGUMENTS */, JS_ATOM_Arguments],
|
|
165
|
+
[9 /* JSClassID.MAPPED_ARGUMENTS */, JS_ATOM_Arguments],
|
|
166
|
+
[10 /* JSClassID.DATE */, JS_ATOM_Date],
|
|
167
|
+
[11 /* JSClassID.MODULE_NS */, JS_ATOM_Module],
|
|
168
|
+
[12 /* JSClassID.C_FUNCTION */, JS_ATOM_Function],
|
|
169
|
+
[13 /* JSClassID.BYTECODE_FUNCTION */, JS_ATOM_Function],
|
|
170
|
+
[14 /* JSClassID.BOUND_FUNCTION */, JS_ATOM_Function],
|
|
171
|
+
[15 /* JSClassID.C_FUNCTION_DATA */, JS_ATOM_Function],
|
|
172
|
+
[16 /* JSClassID.GENERATOR_FUNCTION */, JS_ATOM_GeneratorFunction],
|
|
173
|
+
[17 /* JSClassID.FOR_IN_ITERATOR */, JS_ATOM_ForInIterator],
|
|
174
|
+
[18 /* JSClassID.REGEXP */, JS_ATOM_RegExp],
|
|
175
|
+
[19 /* JSClassID.ARRAY_BUFFER */, JS_ATOM_ArrayBuffer],
|
|
176
|
+
[20 /* JSClassID.SHARED_ARRAY_BUFFER */, JS_ATOM_SharedArrayBuffer],
|
|
177
|
+
[21 /* JSClassID.UINT8C_ARRAY */, JS_ATOM_Uint8ClampedArray],
|
|
178
|
+
[22 /* JSClassID.INT8_ARRAY */, JS_ATOM_Int8Array],
|
|
179
|
+
[23 /* JSClassID.UINT8_ARRAY */, JS_ATOM_Uint8Array],
|
|
180
|
+
[24 /* JSClassID.INT16_ARRAY */, JS_ATOM_Int16Array],
|
|
181
|
+
[25 /* JSClassID.UINT16_ARRAY */, JS_ATOM_Uint16Array],
|
|
182
|
+
[26 /* JSClassID.INT32_ARRAY */, JS_ATOM_Int32Array],
|
|
183
|
+
[27 /* JSClassID.UINT32_ARRAY */, JS_ATOM_Uint32Array],
|
|
184
|
+
[28 /* JSClassID.BIG_INT64_ARRAY */, JS_ATOM_BigInt64Array],
|
|
185
|
+
[29 /* JSClassID.BIG_UINT64_ARRAY */, JS_ATOM_BigUint64Array],
|
|
186
|
+
[30 /* JSClassID.FLOAT32_ARRAY */, JS_ATOM_Float32Array],
|
|
187
|
+
[31 /* JSClassID.FLOAT64_ARRAY */, JS_ATOM_Float64Array],
|
|
188
|
+
[32 /* JSClassID.DATAVIEW */, JS_ATOM_DataView],
|
|
189
|
+
[33 /* JSClassID.BIG_INT */, JS_ATOM_BigInt],
|
|
190
|
+
[34 /* JSClassID.MAP */, JS_ATOM_Map],
|
|
191
|
+
[35 /* JSClassID.SET */, JS_ATOM_Set],
|
|
192
|
+
[36 /* JSClassID.WEAKMAP */, JS_ATOM_WeakMap],
|
|
193
|
+
[37 /* JSClassID.WEAKSET */, JS_ATOM_WeakSet],
|
|
194
|
+
[38 /* JSClassID.MAP_ITERATOR */, JS_ATOM_Map_Iterator],
|
|
195
|
+
[39 /* JSClassID.SET_ITERATOR */, JS_ATOM_Set_Iterator],
|
|
196
|
+
[40 /* JSClassID.ARRAY_ITERATOR */, JS_ATOM_Array_Iterator],
|
|
197
|
+
[41 /* JSClassID.STRING_ITERATOR */, JS_ATOM_String_Iterator],
|
|
198
|
+
[42 /* JSClassID.REGEXP_STRING_ITERATOR */, JS_ATOM_RegExp_String_Iterator],
|
|
199
|
+
[43 /* JSClassID.GENERATOR */, JS_ATOM_Generator],
|
|
200
|
+
[44 /* JSClassID.PROXY */, JS_ATOM_Proxy],
|
|
201
|
+
[45 /* JSClassID.PROMISE */, JS_ATOM_Promise],
|
|
202
|
+
[46 /* JSClassID.PROMISE_RESOLVE_FUNCTION */, JS_ATOM_PromiseResolveFunction],
|
|
203
|
+
[47 /* JSClassID.PROMISE_REJECT_FUNCTION */, JS_ATOM_PromiseRejectFunction],
|
|
204
|
+
[48 /* JSClassID.ASYNC_FUNCTION */, JS_ATOM_AsyncFunction],
|
|
205
|
+
[49 /* JSClassID.ASYNC_FUNCTION_RESOLVE */, JS_ATOM_AsyncFunctionResolve],
|
|
206
|
+
[50 /* JSClassID.ASYNC_FUNCTION_REJECT */, JS_ATOM_AsyncFunctionReject],
|
|
207
|
+
[51 /* JSClassID.ASYNC_FROM_SYNC_ITERATOR */, JS_ATOM_Object],
|
|
208
|
+
[52 /* JSClassID.ASYNC_GENERATOR_FUNCTION */, JS_ATOM_AsyncGeneratorFunction],
|
|
209
|
+
[53 /* JSClassID.ASYNC_GENERATOR */, JS_ATOM_AsyncGenerator],
|
|
210
|
+
[54 /* JSClassID.WEAK_REF */, JS_ATOM_WeakRef],
|
|
211
|
+
[55 /* JSClassID.FINALIZATION_REGISTRY */, JS_ATOM_FinalizationRegistry],
|
|
212
|
+
];
|
|
213
|
+
export function JS_NewRuntime() {
|
|
214
|
+
const rt = new JSRuntime();
|
|
215
|
+
for (const [id, name] of js_std_class_def) {
|
|
216
|
+
JS_NewClass1(rt, id, { class_name: name });
|
|
217
|
+
}
|
|
218
|
+
for (const f of hooks.init_runtime)
|
|
219
|
+
f(rt);
|
|
220
|
+
return rt;
|
|
221
|
+
}
|
|
222
|
+
export function JS_FreeRuntime(rt) {
|
|
223
|
+
rt.job_list.length = 0;
|
|
224
|
+
rt.context_list.length = 0;
|
|
225
|
+
}
|
|
226
|
+
export function JS_SetRuntimeOpaque(rt, opaque) { rt.user_opaque = opaque; }
|
|
227
|
+
export function JS_GetRuntimeOpaque(rt) { return rt.user_opaque; }
|
|
228
|
+
export function JS_SetContextOpaque(ctx, opaque) { ctx.user_opaque = opaque; }
|
|
229
|
+
export function JS_GetContextOpaque(ctx) { return ctx.user_opaque; }
|
|
230
|
+
export function JS_GetRuntime(ctx) { return ctx.rt; }
|
|
231
|
+
export function JS_SetMaxStackSize(rt, depth) { rt.max_stack_depth = depth; }
|
|
232
|
+
export function JS_SetInterruptHandler(rt, cb, opaque) {
|
|
233
|
+
rt.interrupt_handler = cb;
|
|
234
|
+
rt.interrupt_opaque = opaque;
|
|
235
|
+
}
|
|
236
|
+
export function JS_SetHostPromiseRejectionTracker(rt, cb, opaque) {
|
|
237
|
+
rt.host_promise_rejection_tracker = cb;
|
|
238
|
+
rt.host_promise_rejection_tracker_opaque = opaque;
|
|
239
|
+
}
|
|
240
|
+
export function JS_NewContextRaw(rt) {
|
|
241
|
+
const ctx = new JSContext(rt);
|
|
242
|
+
rt.context_list.push(ctx);
|
|
243
|
+
ctx.class_proto[1 /* JSClassID.OBJECT */] = JS_NewObjectProto(ctx, null);
|
|
244
|
+
/* placeholder replaced by the builtins (Function.prototype is a function) */
|
|
245
|
+
ctx.function_proto = JS_NewObjectProtoClass(ctx, ctx.class_proto[1 /* JSClassID.OBJECT */], 1 /* JSClassID.OBJECT */);
|
|
246
|
+
ctx.global_obj = JS_NewObject(ctx);
|
|
247
|
+
ctx.global_var_obj = Object.create(null);
|
|
248
|
+
return ctx;
|
|
249
|
+
}
|
|
250
|
+
export function JS_NewContext(rt) {
|
|
251
|
+
const ctx = JS_NewContextRaw(rt);
|
|
252
|
+
hooks.JS_AddIntrinsicBaseObjects(ctx);
|
|
253
|
+
return ctx;
|
|
254
|
+
}
|
|
255
|
+
export function JS_FreeContext(ctx) {
|
|
256
|
+
const i = ctx.rt.context_list.indexOf(ctx);
|
|
257
|
+
if (i >= 0)
|
|
258
|
+
ctx.rt.context_list.splice(i, 1);
|
|
259
|
+
}
|
|
260
|
+
export function JS_GetClassProto(ctx, class_id) {
|
|
261
|
+
return ctx.class_proto[class_id] ?? undefined;
|
|
262
|
+
}
|
|
263
|
+
export function JS_SetClassProto(ctx, class_id, obj) {
|
|
264
|
+
ctx.class_proto[class_id] = obj;
|
|
265
|
+
}
|
|
266
|
+
export function JS_GetGlobalObject(ctx) { return ctx.global_obj; }
|
|
267
|
+
/* ---------------------------------------------------------------------
|
|
268
|
+
Atoms
|
|
269
|
+
--------------------------------------------------------------------- */
|
|
270
|
+
export function JS_NewAtom(ctx, str) { return ctx.rt.atoms.newAtomStr(str); }
|
|
271
|
+
export function JS_NewAtomStr(ctx, str) { return ctx.rt.atoms.newAtomStr(str); }
|
|
272
|
+
export function JS_NewAtomUInt32(ctx, n) { return ctx.rt.atoms.newAtomUInt32(n); }
|
|
273
|
+
export function JS_NewAtomInt64(ctx, n) {
|
|
274
|
+
if (n >= 0 && n <= JS_ATOM_MAX_INT)
|
|
275
|
+
return __JS_AtomFromUInt32(n);
|
|
276
|
+
return ctx.rt.atoms.newAtomStr(String(n));
|
|
277
|
+
}
|
|
278
|
+
export function JS_DupAtom(_ctx, v) { return v; }
|
|
279
|
+
export function JS_FreeAtom(_ctx, _v) { }
|
|
280
|
+
export function JS_FreeValue(_ctx, _v) { }
|
|
281
|
+
export function JS_DupValue(_ctx, v) { return v; }
|
|
282
|
+
export function JS_AtomIsString(ctx, atom) { return ctx.rt.atoms.isString(atom); }
|
|
283
|
+
export function JS_AtomIsSymbol(ctx, atom) { return ctx.rt.atoms.isSymbol(atom); }
|
|
284
|
+
export function JS_AtomGetStr(ctx, atom) { return ctx.rt.atoms.toDisplayStr(atom); }
|
|
285
|
+
export function JS_AtomGetStrRT(rt, atom) { return rt.atoms.toDisplayStr(atom); }
|
|
286
|
+
export function JS_AtomToKey(ctx, atom) {
|
|
287
|
+
return ctx.rt.atoms.toKey(atom);
|
|
288
|
+
}
|
|
289
|
+
/* atom from a host property key (as returned by Reflect.ownKeys) */
|
|
290
|
+
export function JS_KeyToAtom(ctx, key) {
|
|
291
|
+
switch (typeof key) {
|
|
292
|
+
case 'string': return ctx.rt.atoms.newAtomStr(key);
|
|
293
|
+
case 'number': return ctx.rt.atoms.newAtomUInt32(key);
|
|
294
|
+
default: return ctx.rt.atoms.symbolToAtom(key);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
/* atom to JS value: string or symbol */
|
|
298
|
+
export function JS_AtomToValue(ctx, atom) {
|
|
299
|
+
const atoms = ctx.rt.atoms;
|
|
300
|
+
if (atoms.isSymbol(atom))
|
|
301
|
+
return atoms.getSymbol(atom);
|
|
302
|
+
return atoms.toStr(atom);
|
|
303
|
+
}
|
|
304
|
+
/* atom to string (symbols are converted to their description) */
|
|
305
|
+
export function JS_AtomToString(ctx, atom) {
|
|
306
|
+
return ctx.rt.atoms.toStr(atom);
|
|
307
|
+
}
|
|
308
|
+
/* return the array index (0 .. 2^32-2) or -1 if the atom is not an array index */
|
|
309
|
+
export function JS_AtomIsArrayIndex(ctx, atom) {
|
|
310
|
+
if (__JS_AtomIsTaggedInt(atom))
|
|
311
|
+
return __JS_AtomToUInt32(atom);
|
|
312
|
+
const atoms = ctx.rt.atoms;
|
|
313
|
+
if (atoms.getType(atom) !== JS_ATOM_TYPE_STRING)
|
|
314
|
+
return -1;
|
|
315
|
+
const str = atoms.toStr(atom);
|
|
316
|
+
/* canonical uint32 string larger than JS_ATOM_MAX_INT */
|
|
317
|
+
if (str.length !== 10)
|
|
318
|
+
return -1;
|
|
319
|
+
if (!/^[1-9][0-9]{9}$/.test(str))
|
|
320
|
+
return -1;
|
|
321
|
+
const n = Number(str);
|
|
322
|
+
if (n > 0xfffffffe)
|
|
323
|
+
return -1;
|
|
324
|
+
return n;
|
|
325
|
+
}
|
|
326
|
+
/* return TRUE if the atom is a numeric index (canonical numeric string) */
|
|
327
|
+
export function JS_AtomIsNumericIndex1(ctx, atom) {
|
|
328
|
+
if (__JS_AtomIsTaggedInt(atom))
|
|
329
|
+
return __JS_AtomToUInt32(atom);
|
|
330
|
+
if (!ctx.rt.atoms.isString(atom))
|
|
331
|
+
return undefined;
|
|
332
|
+
const str = ctx.rt.atoms.toStr(atom);
|
|
333
|
+
if (str === '-0')
|
|
334
|
+
return -0;
|
|
335
|
+
if (str === 'Infinity')
|
|
336
|
+
return Infinity;
|
|
337
|
+
if (str === '-Infinity')
|
|
338
|
+
return -Infinity;
|
|
339
|
+
if (str === 'NaN')
|
|
340
|
+
return NaN;
|
|
341
|
+
const n = Number(str);
|
|
342
|
+
if (Number.isNaN(n) || str.trim() !== str || str === '')
|
|
343
|
+
return undefined;
|
|
344
|
+
if (js_number_to_string(n, 10) !== str)
|
|
345
|
+
return undefined;
|
|
346
|
+
return n;
|
|
347
|
+
}
|
|
348
|
+
export function JS_AtomIsNumericIndex(ctx, atom) {
|
|
349
|
+
return JS_AtomIsNumericIndex1(ctx, atom) !== undefined;
|
|
350
|
+
}
|
|
351
|
+
/* ToPropertyKey */
|
|
352
|
+
export function JS_ValueToAtom(ctx, val) {
|
|
353
|
+
switch (typeof val) {
|
|
354
|
+
case 'number':
|
|
355
|
+
if (Number.isInteger(val) && val >= 0 && val <= JS_ATOM_MAX_INT)
|
|
356
|
+
return __JS_AtomFromUInt32(val);
|
|
357
|
+
return ctx.rt.atoms.newAtomStr(js_number_to_string(val, 10));
|
|
358
|
+
case 'string':
|
|
359
|
+
return ctx.rt.atoms.newAtomStr(val);
|
|
360
|
+
case 'symbol':
|
|
361
|
+
return ctx.rt.atoms.symbolToAtom(val);
|
|
362
|
+
case 'boolean':
|
|
363
|
+
return val ? JS_ATOM_true : JS_ATOM_false;
|
|
364
|
+
case 'undefined':
|
|
365
|
+
return JS_ATOM_undefined;
|
|
366
|
+
case 'bigint':
|
|
367
|
+
return ctx.rt.atoms.newAtomStr(val.toString());
|
|
368
|
+
case 'object':
|
|
369
|
+
case 'function':
|
|
370
|
+
if (val === null)
|
|
371
|
+
return JS_ATOM_null;
|
|
372
|
+
if (JS_IsObject(val)) {
|
|
373
|
+
const prim = JS_ToPrimitive(ctx, val, HINT_STRING);
|
|
374
|
+
if (JS_IsException(prim))
|
|
375
|
+
return JS_ATOM_NULL;
|
|
376
|
+
return JS_ValueToAtom(ctx, prim);
|
|
377
|
+
}
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
JS_ThrowTypeError(ctx, 'invalid property key');
|
|
381
|
+
return JS_ATOM_NULL;
|
|
382
|
+
}
|
|
383
|
+
export function JS_NewSymbol(ctx, description, atom_type = JS_ATOM_TYPE_SYMBOL) {
|
|
384
|
+
return ctx.rt.atoms.newSymbol(description, atom_type);
|
|
385
|
+
}
|
|
386
|
+
export function JS_NewSymbolFromAtom(ctx, descr, atom_type) {
|
|
387
|
+
return ctx.rt.atoms.newSymbol(ctx.rt.atoms.toStr(descr), atom_type);
|
|
388
|
+
}
|
|
389
|
+
/* ---------------------------------------------------------------------
|
|
390
|
+
Exceptions
|
|
391
|
+
--------------------------------------------------------------------- */
|
|
392
|
+
export function JS_Throw(ctx, obj) {
|
|
393
|
+
const rt = ctx.rt;
|
|
394
|
+
rt.current_exception = obj;
|
|
395
|
+
rt.exception_pending = true;
|
|
396
|
+
return JS_EXCEPTION;
|
|
397
|
+
}
|
|
398
|
+
export function JS_GetException(ctx) {
|
|
399
|
+
const rt = ctx.rt;
|
|
400
|
+
const val = rt.current_exception;
|
|
401
|
+
rt.current_exception = undefined;
|
|
402
|
+
rt.exception_pending = false;
|
|
403
|
+
return val;
|
|
404
|
+
}
|
|
405
|
+
export function JS_HasException(ctx) { return ctx.rt.exception_pending; }
|
|
406
|
+
/* take the pending exception to throw it as a host exception (used by the
|
|
407
|
+
function wrappers at the engine/host boundary) */
|
|
408
|
+
export function js_take_exception(ctx) {
|
|
409
|
+
return JS_GetException(ctx);
|
|
410
|
+
}
|
|
411
|
+
/* Convert a value thrown by host code into the engine convention. Guest
|
|
412
|
+
values pass through; host intrinsic errors (their prototype chain reaches
|
|
413
|
+
the host Error.prototype, which no guest object has) become guest errors.
|
|
414
|
+
Always returns JS_EXCEPTION. */
|
|
415
|
+
/* Host error messages quote the expression that failed ("$s1 is not a function. (In
|
|
416
|
+
'$s1(...)', ...)"): map the common ones to the QuickJS wording so that generated code
|
|
417
|
+
never shows through, and drop the quoted source otherwise. */
|
|
418
|
+
export function js_normalize_host_message(e) {
|
|
419
|
+
let msg = String(e.message);
|
|
420
|
+
if (e instanceof TypeError) {
|
|
421
|
+
if (/ is not a function\b/.test(msg))
|
|
422
|
+
return 'not a function';
|
|
423
|
+
if (/ is not a constructor\b/.test(msg))
|
|
424
|
+
return 'not a constructor';
|
|
425
|
+
const m = /^(null|undefined) is not an object \(evaluating '([^']*)'\)$/.exec(msg);
|
|
426
|
+
if (m) {
|
|
427
|
+
const expr = m[2];
|
|
428
|
+
const eq = expr.indexOf(' = ');
|
|
429
|
+
const lhs = eq >= 0 ? expr.slice(0, eq) : expr;
|
|
430
|
+
const name = /\.([A-Za-z_$][\w$]*)$/.exec(lhs);
|
|
431
|
+
const what = eq >= 0 ? 'cannot set property' : 'cannot read property';
|
|
432
|
+
return name ? `${what} '${name[1]}' of ${m[1]}` : `${what} of ${m[1]}`;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
msg = msg.replace(/\s*\((?:evaluating|In) '.*$/, '');
|
|
436
|
+
return msg;
|
|
437
|
+
}
|
|
438
|
+
export function js_host_exception_to_guest(ctx, e) {
|
|
439
|
+
if (e === JS_EXCEPTION)
|
|
440
|
+
return JS_EXCEPTION; /* already pending */
|
|
441
|
+
if (e instanceof Error) {
|
|
442
|
+
let msg = js_normalize_host_message(e);
|
|
443
|
+
let num;
|
|
444
|
+
if (e instanceof RangeError) {
|
|
445
|
+
if (/call stack|stack size|recursion|stack overflow/i.test(msg))
|
|
446
|
+
return JS_ThrowStackOverflow(ctx);
|
|
447
|
+
num = 1 /* JSErrorEnum.RANGE_ERROR */;
|
|
448
|
+
}
|
|
449
|
+
else if (e instanceof TypeError)
|
|
450
|
+
num = 4 /* JSErrorEnum.TYPE_ERROR */;
|
|
451
|
+
else if (e instanceof SyntaxError)
|
|
452
|
+
num = 3 /* JSErrorEnum.SYNTAX_ERROR */;
|
|
453
|
+
else if (e instanceof ReferenceError)
|
|
454
|
+
num = 2 /* JSErrorEnum.REFERENCE_ERROR */;
|
|
455
|
+
else if (e instanceof URIError)
|
|
456
|
+
num = 5 /* JSErrorEnum.URI_ERROR */;
|
|
457
|
+
else if (e instanceof EvalError)
|
|
458
|
+
num = 0 /* JSErrorEnum.EVAL_ERROR */;
|
|
459
|
+
else {
|
|
460
|
+
num = 6 /* JSErrorEnum.INTERNAL_ERROR */;
|
|
461
|
+
msg = 'internal error: ' + msg;
|
|
462
|
+
}
|
|
463
|
+
/* the host captured the stack where the error was raised: compiled guest frames are
|
|
464
|
+
located from it (see build_backtrace) */
|
|
465
|
+
return JS_ThrowError2(ctx, num, msg, true, typeof e.stack === 'string' ? e.stack : null);
|
|
466
|
+
}
|
|
467
|
+
return JS_Throw(ctx, e);
|
|
468
|
+
}
|
|
469
|
+
export function JS_IsError(ctx, val) {
|
|
470
|
+
const m = js_get_meta(val);
|
|
471
|
+
return m !== undefined && m.class_id === 3 /* JSClassID.ERROR */;
|
|
472
|
+
}
|
|
473
|
+
export function JS_IsUncatchableError(ctx, val) {
|
|
474
|
+
const m = js_get_meta(val);
|
|
475
|
+
return m !== undefined && m.class_id === 3 /* JSClassID.ERROR */ && m.is_uncatchable_error;
|
|
476
|
+
}
|
|
477
|
+
export function JS_SetUncatchableError(ctx, val, flag) {
|
|
478
|
+
const m = js_get_meta(val);
|
|
479
|
+
if (m && m.class_id === 3 /* JSClassID.ERROR */)
|
|
480
|
+
m.is_uncatchable_error = flag;
|
|
481
|
+
}
|
|
482
|
+
export function JS_NewError(ctx) {
|
|
483
|
+
return JS_NewObjectProtoClass(ctx, ctx.class_proto[3 /* JSClassID.ERROR */], 3 /* JSClassID.ERROR */);
|
|
484
|
+
}
|
|
485
|
+
export function JS_NewErrorNative(ctx, error_num, message) {
|
|
486
|
+
let proto;
|
|
487
|
+
if (error_num === 8 /* JSErrorEnum.PLAIN_ERROR */)
|
|
488
|
+
proto = ctx.class_proto[3 /* JSClassID.ERROR */];
|
|
489
|
+
else
|
|
490
|
+
proto = ctx.native_error_proto[error_num];
|
|
491
|
+
const obj = JS_NewObjectProtoClass(ctx, proto, 3 /* JSClassID.ERROR */);
|
|
492
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_message, message, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
493
|
+
return obj;
|
|
494
|
+
}
|
|
495
|
+
export const JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL = 1 << 0;
|
|
496
|
+
/* Build the 'stack' property of an error from the current call stack.
|
|
497
|
+
|
|
498
|
+
Interpreter and C function frames are the `JSStackFrame` chain. Compiled
|
|
499
|
+
functions (src/jit.ts) have no such frame: when the compiled tier is on,
|
|
500
|
+
the host stack (`host_stack`, or the current one) is mapped to guest frames
|
|
501
|
+
by src/jit_stack.ts and the engine frames found in it consume the chain in
|
|
502
|
+
order, so both kinds appear interleaved as they were called. Frames of
|
|
503
|
+
host builtins called by guest code appear as `(native)`.
|
|
504
|
+
|
|
505
|
+
`fileName`/`lineNumber`/`columnNumber` are set from the given position or,
|
|
506
|
+
when none is given, from the innermost frame with a position. */
|
|
507
|
+
export function build_backtrace(ctx, error_obj, filename, line_num, col_num, backtrace_flags, host_stack = null) {
|
|
508
|
+
let str = '';
|
|
509
|
+
const is_obj = JS_IsObject(error_obj);
|
|
510
|
+
let has_pos = false;
|
|
511
|
+
const set_pos = (file, line, col) => {
|
|
512
|
+
has_pos = true;
|
|
513
|
+
if (!is_obj)
|
|
514
|
+
return;
|
|
515
|
+
/* Note: SpiderMonkey does that, could update once there is a standard */
|
|
516
|
+
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_fileName, file, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
517
|
+
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_lineNumber, line, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
518
|
+
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_columnNumber, col, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
519
|
+
};
|
|
520
|
+
if (filename) {
|
|
521
|
+
str += ` at ${filename}`;
|
|
522
|
+
if (line_num !== -1)
|
|
523
|
+
str += `:${line_num}:${col_num}`;
|
|
524
|
+
str += '\n';
|
|
525
|
+
set_pos(filename, line_num, col_num);
|
|
526
|
+
}
|
|
527
|
+
/* one line for an engine frame */
|
|
528
|
+
const frame_line = (sf) => {
|
|
529
|
+
const f = sf.cur_func;
|
|
530
|
+
let func_name = '';
|
|
531
|
+
if (JS_IsObject(f))
|
|
532
|
+
func_name = get_func_name(ctx, f);
|
|
533
|
+
let s = ` at ${func_name || '<anonymous>'}`;
|
|
534
|
+
const fd = JS_GetFunctionData(f);
|
|
535
|
+
if (fd) {
|
|
536
|
+
const b = fd.function_bytecode;
|
|
537
|
+
if (b.has_debug) {
|
|
538
|
+
const fname = ctx.rt.atoms.toStr(b.debug.filename);
|
|
539
|
+
const [line1, col1] = find_line_num(ctx, b, sf.cur_pc - 1);
|
|
540
|
+
s += ` (${fname}`;
|
|
541
|
+
if (line1 > 0) {
|
|
542
|
+
s += `:${line1}:${col1}`;
|
|
543
|
+
if (!has_pos)
|
|
544
|
+
set_pos(fname, line1, col1);
|
|
545
|
+
}
|
|
546
|
+
s += ')';
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
s += ' (native)';
|
|
551
|
+
}
|
|
552
|
+
return s + '\n';
|
|
553
|
+
};
|
|
554
|
+
let skip = (backtrace_flags & JS_BACKTRACE_FLAG_SKIP_FIRST_LEVEL) !== 0;
|
|
555
|
+
let sf = ctx.rt.current_stack_frame;
|
|
556
|
+
const hooks = jit_hooks.stack;
|
|
557
|
+
if (hooks !== null) {
|
|
558
|
+
const frames = hooks.frames(host_stack ?? hooks.capture());
|
|
559
|
+
let stop = false;
|
|
560
|
+
for (let i = 0; i < frames.length && !stop; i++) {
|
|
561
|
+
const hf = frames[i];
|
|
562
|
+
switch (hf.kind) {
|
|
563
|
+
case 'compiled':
|
|
564
|
+
if (skip) {
|
|
565
|
+
skip = false;
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
str += ` at ${hf.name || '<anonymous>'} (${hf.file}`;
|
|
569
|
+
if (hf.line > 0) {
|
|
570
|
+
str += `:${hf.line}:${hf.col}`;
|
|
571
|
+
if (!has_pos)
|
|
572
|
+
set_pos(hf.file, hf.line, hf.col);
|
|
573
|
+
}
|
|
574
|
+
str += ')\n';
|
|
575
|
+
break;
|
|
576
|
+
case 'native':
|
|
577
|
+
if (skip) {
|
|
578
|
+
skip = false;
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
str += ` at ${hf.name || '<anonymous>'} (native)\n`;
|
|
582
|
+
break;
|
|
583
|
+
default: {
|
|
584
|
+
/* the next engine frame, when of the matching kind (the frame of a C function that
|
|
585
|
+
raised a host exception is already unwound when the exception is converted) */
|
|
586
|
+
if (sf === null)
|
|
587
|
+
break;
|
|
588
|
+
if ((JS_GetFunctionData(sf.cur_func) !== null) !== (hf.kind === 'interp'))
|
|
589
|
+
break;
|
|
590
|
+
if (sf.js_mode & JS_MODE_BACKTRACE_BARRIER) {
|
|
591
|
+
sf = null;
|
|
592
|
+
stop = true;
|
|
593
|
+
break;
|
|
594
|
+
}
|
|
595
|
+
const cur = sf;
|
|
596
|
+
sf = sf.prev_frame;
|
|
597
|
+
/* a frame replaced by compiled code (on-stack replacement) is shown by its compiled
|
|
598
|
+
frame, which precedes it on the host stack */
|
|
599
|
+
if (cur.osr)
|
|
600
|
+
break;
|
|
601
|
+
if (skip) {
|
|
602
|
+
skip = false;
|
|
603
|
+
break;
|
|
604
|
+
}
|
|
605
|
+
str += frame_line(cur);
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
/* engine frames the host stack did not show (its depth limit) follow */
|
|
611
|
+
}
|
|
612
|
+
for (; sf !== null; sf = sf.prev_frame) {
|
|
613
|
+
if (sf.js_mode & JS_MODE_BACKTRACE_BARRIER)
|
|
614
|
+
break;
|
|
615
|
+
if (sf.osr)
|
|
616
|
+
continue;
|
|
617
|
+
if (skip) {
|
|
618
|
+
skip = false;
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
str += frame_line(sf);
|
|
622
|
+
}
|
|
623
|
+
if (is_obj) {
|
|
624
|
+
JS_DefinePropertyValue(ctx, error_obj, JS_ATOM_stack, str, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
625
|
+
const m = js_get_meta(error_obj);
|
|
626
|
+
if (m)
|
|
627
|
+
m.has_backtrace = true;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
export function get_func_name(ctx, func) {
|
|
631
|
+
try {
|
|
632
|
+
const d = Reflect.getOwnPropertyDescriptor(func, 'name');
|
|
633
|
+
if (d && 'value' in d && typeof d.value === 'string')
|
|
634
|
+
return d.value;
|
|
635
|
+
}
|
|
636
|
+
catch { /* proxy trap failures are ignored here */ }
|
|
637
|
+
const fd = JS_GetFunctionData(func);
|
|
638
|
+
if (fd)
|
|
639
|
+
return ctx.rt.atoms.toStr(fd.function_bytecode.func_name);
|
|
640
|
+
return '';
|
|
641
|
+
}
|
|
642
|
+
/* decode the pc2line table: returns [line, col] of the last entry whose
|
|
643
|
+
pc is <= pc_value. pc_value < 0 returns the function start position. */
|
|
644
|
+
export function find_line_num(ctx, b, pc_value) {
|
|
645
|
+
const buf = b.debug.pc2line;
|
|
646
|
+
if (!buf || buf.length === 0)
|
|
647
|
+
return [-1, -1];
|
|
648
|
+
/* encoding: sequence of (pc_delta: leb128, line_delta: sleb128, col_delta: sleb128);
|
|
649
|
+
the first entry gives the function start position */
|
|
650
|
+
let pos = 0, pc = 0, line = 0, col = 0;
|
|
651
|
+
let last_line = -1, last_col = -1;
|
|
652
|
+
let first = true;
|
|
653
|
+
while (pos < buf.length) {
|
|
654
|
+
const r1 = get_leb128(buf, pos);
|
|
655
|
+
pos = r1[1];
|
|
656
|
+
const r2 = get_sleb128(buf, pos);
|
|
657
|
+
pos = r2[1];
|
|
658
|
+
const r3 = get_sleb128(buf, pos);
|
|
659
|
+
pos = r3[1];
|
|
660
|
+
pc += r1[0];
|
|
661
|
+
line += r2[0];
|
|
662
|
+
col += r3[0];
|
|
663
|
+
if (first) {
|
|
664
|
+
first = false;
|
|
665
|
+
last_line = line;
|
|
666
|
+
last_col = col;
|
|
667
|
+
if (pc_value < 0)
|
|
668
|
+
break;
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
if (pc > pc_value)
|
|
672
|
+
break;
|
|
673
|
+
last_line = line;
|
|
674
|
+
last_col = col;
|
|
675
|
+
}
|
|
676
|
+
return [last_line, last_col];
|
|
677
|
+
}
|
|
678
|
+
export function get_leb128(buf, pos) {
|
|
679
|
+
let v = 0, shift = 0;
|
|
680
|
+
for (;;) {
|
|
681
|
+
const a = buf[pos++];
|
|
682
|
+
v += (a & 0x7f) * Math.pow(2, shift);
|
|
683
|
+
if (!(a & 0x80))
|
|
684
|
+
break;
|
|
685
|
+
shift += 7;
|
|
686
|
+
}
|
|
687
|
+
return [v, pos];
|
|
688
|
+
}
|
|
689
|
+
export function get_sleb128(buf, pos) {
|
|
690
|
+
const [v, p] = get_leb128(buf, pos);
|
|
691
|
+
/* zigzag */
|
|
692
|
+
return [(v % 2 === 1) ? -((v + 1) / 2) : v / 2, p];
|
|
693
|
+
}
|
|
694
|
+
export function JS_ThrowError2(ctx, error_num, message, add_backtrace, host_stack = null) {
|
|
695
|
+
const obj = JS_NewErrorNative(ctx, error_num, message);
|
|
696
|
+
if (add_backtrace)
|
|
697
|
+
build_backtrace(ctx, obj, null, 0, 0, 0, host_stack);
|
|
698
|
+
return JS_Throw(ctx, obj);
|
|
699
|
+
}
|
|
700
|
+
export function JS_ThrowError(ctx, error_num, message) {
|
|
701
|
+
/* the backtrace is added later (with the exact position) if called
|
|
702
|
+
from a bytecode function */
|
|
703
|
+
const sf = ctx.rt.current_stack_frame;
|
|
704
|
+
if (!sf || JS_GetFunctionData(sf.cur_func) === null)
|
|
705
|
+
return JS_ThrowError2(ctx, error_num, message, true);
|
|
706
|
+
const hooks = jit_hooks.stack;
|
|
707
|
+
if (hooks !== null) {
|
|
708
|
+
/* a compiled function has no interpreter frame: when it is the thrower, its position is
|
|
709
|
+
on the host stack now and gone once the exception has propagated */
|
|
710
|
+
const stack = hooks.capture();
|
|
711
|
+
if (hooks.compiled_on_top(stack))
|
|
712
|
+
return JS_ThrowError2(ctx, error_num, message, true, stack);
|
|
713
|
+
}
|
|
714
|
+
return JS_ThrowError2(ctx, error_num, message, false);
|
|
715
|
+
}
|
|
716
|
+
export function JS_ThrowSyntaxError(ctx, msg) { return JS_ThrowError(ctx, 3 /* JSErrorEnum.SYNTAX_ERROR */, msg); }
|
|
717
|
+
export function JS_ThrowTypeError(ctx, msg) { return JS_ThrowError(ctx, 4 /* JSErrorEnum.TYPE_ERROR */, msg); }
|
|
718
|
+
export function JS_ThrowReferenceError(ctx, msg) { return JS_ThrowError(ctx, 2 /* JSErrorEnum.REFERENCE_ERROR */, msg); }
|
|
719
|
+
export function JS_ThrowRangeError(ctx, msg) { return JS_ThrowError(ctx, 1 /* JSErrorEnum.RANGE_ERROR */, msg); }
|
|
720
|
+
export function JS_ThrowInternalError(ctx, msg) { return JS_ThrowError(ctx, 6 /* JSErrorEnum.INTERNAL_ERROR */, msg); }
|
|
721
|
+
export function JS_ThrowURIError(ctx, msg) { return JS_ThrowError(ctx, 5 /* JSErrorEnum.URI_ERROR */, msg); }
|
|
722
|
+
export function JS_ThrowEvalError(ctx, msg) { return JS_ThrowError(ctx, 0 /* JSErrorEnum.EVAL_ERROR */, msg); }
|
|
723
|
+
export function JS_ThrowOutOfMemory(ctx) { return JS_ThrowInternalError(ctx, 'out of memory'); }
|
|
724
|
+
export function JS_ThrowStackOverflow(ctx) { return JS_ThrowInternalError(ctx, 'stack overflow'); }
|
|
725
|
+
export function JS_ThrowTypeErrorAtom(ctx, fmt, atom) {
|
|
726
|
+
return JS_ThrowTypeError(ctx, fmt.replace('%s', JS_AtomGetStr(ctx, atom)));
|
|
727
|
+
}
|
|
728
|
+
export function JS_ThrowSyntaxErrorAtom(ctx, fmt, atom) {
|
|
729
|
+
return JS_ThrowSyntaxError(ctx, fmt.replace('%s', JS_AtomGetStr(ctx, atom)));
|
|
730
|
+
}
|
|
731
|
+
export function JS_ThrowReferenceErrorNotDefined(ctx, name) {
|
|
732
|
+
return JS_ThrowReferenceError(ctx, `'${JS_AtomGetStr(ctx, name)}' is not defined`);
|
|
733
|
+
}
|
|
734
|
+
export function JS_ThrowReferenceErrorUninitialized(ctx, name) {
|
|
735
|
+
return JS_ThrowReferenceError(ctx, `${name === JS_ATOM_NULL ? 'lexical variable' : "'" + JS_AtomGetStr(ctx, name) + "'"} is not initialized`);
|
|
736
|
+
}
|
|
737
|
+
export function JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, is_ref) {
|
|
738
|
+
let atom = JS_ATOM_NULL;
|
|
739
|
+
if (is_ref)
|
|
740
|
+
atom = b.closure_var[idx].var_name;
|
|
741
|
+
else
|
|
742
|
+
atom = b.vardefs[b.arg_count + idx]?.var_name ?? JS_ATOM_NULL;
|
|
743
|
+
return JS_ThrowReferenceErrorUninitialized(ctx, atom);
|
|
744
|
+
}
|
|
745
|
+
export function JS_ThrowTypeErrorReadOnly(ctx, flags, atom) {
|
|
746
|
+
if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
|
|
747
|
+
JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", atom);
|
|
748
|
+
return -1;
|
|
749
|
+
}
|
|
750
|
+
return 0;
|
|
751
|
+
}
|
|
752
|
+
export function JS_ThrowTypeErrorNotAnObject(ctx) { return JS_ThrowTypeError(ctx, 'not an object'); }
|
|
753
|
+
export function JS_ThrowTypeErrorNotASymbol(ctx) { return JS_ThrowTypeError(ctx, 'not a symbol'); }
|
|
754
|
+
export function JS_ThrowTypeErrorInvalidClass(ctx, class_id) {
|
|
755
|
+
const name = ctx.rt.class_array[class_id]?.class_name ?? JS_ATOM_Object;
|
|
756
|
+
return JS_ThrowTypeErrorAtom(ctx, '%s object expected', name);
|
|
757
|
+
}
|
|
758
|
+
export function JS_ThrowTypeErrorNotAFunction(ctx) { return JS_ThrowTypeError(ctx, 'not a function'); }
|
|
759
|
+
export function is_strict_mode(ctx) {
|
|
760
|
+
const sf = ctx.rt.current_stack_frame;
|
|
761
|
+
return !!sf && (sf.js_mode & JS_MODE_STRICT) !== 0;
|
|
762
|
+
}
|
|
763
|
+
/* host-side error class used only to signal fatal interpreter bugs */
|
|
764
|
+
export class JSInternalError extends Error {
|
|
765
|
+
}
|
|
766
|
+
/* ---------------------------------------------------------------------
|
|
767
|
+
Object creation
|
|
768
|
+
--------------------------------------------------------------------- */
|
|
769
|
+
function js_is_function_class(class_id) {
|
|
770
|
+
switch (class_id) {
|
|
771
|
+
case 12 /* JSClassID.C_FUNCTION */:
|
|
772
|
+
case 15 /* JSClassID.C_FUNCTION_DATA */:
|
|
773
|
+
case 13 /* JSClassID.BYTECODE_FUNCTION */:
|
|
774
|
+
case 14 /* JSClassID.BOUND_FUNCTION */:
|
|
775
|
+
case 16 /* JSClassID.GENERATOR_FUNCTION */:
|
|
776
|
+
case 48 /* JSClassID.ASYNC_FUNCTION */:
|
|
777
|
+
case 52 /* JSClassID.ASYNC_GENERATOR_FUNCTION */:
|
|
778
|
+
case 46 /* JSClassID.PROMISE_RESOLVE_FUNCTION */:
|
|
779
|
+
case 47 /* JSClassID.PROMISE_REJECT_FUNCTION */:
|
|
780
|
+
case 49 /* JSClassID.ASYNC_FUNCTION_RESOLVE */:
|
|
781
|
+
case 50 /* JSClassID.ASYNC_FUNCTION_REJECT */:
|
|
782
|
+
return true;
|
|
783
|
+
default:
|
|
784
|
+
return false;
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
/* Create a guest object with the given prototype and class. Arrays are
|
|
788
|
+
host arrays re-prototyped to the guest prototype; the other classes are
|
|
789
|
+
ordinary objects with metadata when class_id != JS_CLASS_OBJECT.
|
|
790
|
+
Function classes must be created with JS_NewCFunction* or js_closure. */
|
|
791
|
+
export function JS_NewObjectProtoClass(ctx, proto, class_id) {
|
|
792
|
+
const p = JS_IsObject(proto) ? proto : null;
|
|
793
|
+
let obj;
|
|
794
|
+
if (class_id === 2 /* JSClassID.ARRAY */) {
|
|
795
|
+
obj = [];
|
|
796
|
+
Object.setPrototypeOf(obj, p);
|
|
797
|
+
}
|
|
798
|
+
else {
|
|
799
|
+
if (js_is_function_class(class_id))
|
|
800
|
+
throw new JSInternalError('function objects must be created with js_new_host_function');
|
|
801
|
+
obj = Object.create(p);
|
|
802
|
+
}
|
|
803
|
+
if (class_id !== 1 /* JSClassID.OBJECT */)
|
|
804
|
+
js_meta.set(obj, new JSObjectMeta(class_id));
|
|
805
|
+
return obj;
|
|
806
|
+
}
|
|
807
|
+
export function JS_NewObjectClass(ctx, class_id) {
|
|
808
|
+
return JS_NewObjectProtoClass(ctx, ctx.class_proto[class_id], class_id);
|
|
809
|
+
}
|
|
810
|
+
export function JS_NewObjectProto(ctx, proto) {
|
|
811
|
+
return Object.create(JS_IsObject(proto) ? proto : null);
|
|
812
|
+
}
|
|
813
|
+
export function JS_NewObject(ctx) {
|
|
814
|
+
return Object.create(ctx.class_proto[1 /* JSClassID.OBJECT */]);
|
|
815
|
+
}
|
|
816
|
+
export function JS_NewArray(ctx) {
|
|
817
|
+
const a = [];
|
|
818
|
+
Object.setPrototypeOf(a, ctx.class_proto[2 /* JSClassID.ARRAY */]);
|
|
819
|
+
return a;
|
|
820
|
+
}
|
|
821
|
+
/* create an array from a list of values (the list is copied) */
|
|
822
|
+
export function js_create_array(ctx, values) {
|
|
823
|
+
const a = values.slice();
|
|
824
|
+
Object.setPrototypeOf(a, ctx.class_proto[2 /* JSClassID.ARRAY */]);
|
|
825
|
+
return a;
|
|
826
|
+
}
|
|
827
|
+
/* create an array from a list of values (takes ownership of the list) */
|
|
828
|
+
export function JS_NewArrayFrom(ctx, values) {
|
|
829
|
+
Object.setPrototypeOf(values, ctx.class_proto[2 /* JSClassID.ARRAY */]);
|
|
830
|
+
return values;
|
|
831
|
+
}
|
|
832
|
+
/* return the host array backing a guest array (not a proxy) when it is
|
|
833
|
+
dense (no holes), or null. QuickJS fast arrays never have holes, so the
|
|
834
|
+
fast paths of the builtins may assume that every element is present. */
|
|
835
|
+
export function js_get_fast_array(ctx, obj) {
|
|
836
|
+
/* host arrays may contain holes: callers must use 'i in arr' where the
|
|
837
|
+
spec requires HasProperty (a scan here would make every call O(n)) */
|
|
838
|
+
if (!Array.isArray(obj) || js_meta.get(obj) !== undefined)
|
|
839
|
+
return null;
|
|
840
|
+
return obj;
|
|
841
|
+
}
|
|
842
|
+
export function JS_SetOpaque(obj, opaque) {
|
|
843
|
+
if (!JS_IsObject(obj))
|
|
844
|
+
return -1;
|
|
845
|
+
js_ensure_meta(obj).u = opaque;
|
|
846
|
+
return 0;
|
|
847
|
+
}
|
|
848
|
+
export function JS_GetOpaque(obj, class_id) {
|
|
849
|
+
const m = js_get_meta(obj);
|
|
850
|
+
if (m && m.class_id === class_id)
|
|
851
|
+
return m.u;
|
|
852
|
+
return null;
|
|
853
|
+
}
|
|
854
|
+
export function JS_GetOpaque2(ctx, obj, class_id) {
|
|
855
|
+
const p = JS_GetOpaque(obj, class_id);
|
|
856
|
+
if (p === null || p === undefined)
|
|
857
|
+
JS_ThrowTypeErrorInvalidClass(ctx, class_id);
|
|
858
|
+
return p;
|
|
859
|
+
}
|
|
860
|
+
export function JS_GetAnyOpaque(obj) {
|
|
861
|
+
const m = js_get_meta(obj);
|
|
862
|
+
return m ? m.u : null;
|
|
863
|
+
}
|
|
864
|
+
/* class id of a value: 0 for non objects */
|
|
865
|
+
export function JS_GetClassID(v) {
|
|
866
|
+
if (!JS_IsObject(v))
|
|
867
|
+
return 0;
|
|
868
|
+
const m = js_meta.get(v);
|
|
869
|
+
if (m)
|
|
870
|
+
return m.class_id;
|
|
871
|
+
if (Array.isArray(v))
|
|
872
|
+
return 2 /* JSClassID.ARRAY */;
|
|
873
|
+
if (typeof v === 'function')
|
|
874
|
+
return 12 /* JSClassID.C_FUNCTION */;
|
|
875
|
+
return 1 /* JSClassID.OBJECT */;
|
|
876
|
+
}
|
|
877
|
+
/* (plain module code: ES modules are strict, and no code generation from
|
|
878
|
+
strings is needed, so the runtime loads under a CSP without 'unsafe-eval'
|
|
879
|
+
and on platforms such as Cloudflare Workers) */
|
|
880
|
+
const host_fn_factory = {
|
|
881
|
+
mk_method(impl) {
|
|
882
|
+
const o = { m(...args) { return impl(this, undefined, args); } };
|
|
883
|
+
return o.m;
|
|
884
|
+
},
|
|
885
|
+
mk_function(impl) {
|
|
886
|
+
const f = function (...args) { return impl(this, new.target, args); };
|
|
887
|
+
f.prototype = undefined; /* replaced by the engine; never a host object */
|
|
888
|
+
return f;
|
|
889
|
+
},
|
|
890
|
+
};
|
|
891
|
+
/* create a guest function object calling 'impl' (which uses the host
|
|
892
|
+
exception convention) */
|
|
893
|
+
export function js_new_host_function(ctx, impl, is_ctor, name, length, proto, class_id) {
|
|
894
|
+
const f = is_ctor ? host_fn_factory.mk_function(impl) : host_fn_factory.mk_method(impl);
|
|
895
|
+
js_direct.set(f, (t, nt, ...args) => impl(t, nt, args));
|
|
896
|
+
js_init_host_function(ctx, f, is_ctor, name, length, proto, class_id);
|
|
897
|
+
return f;
|
|
898
|
+
}
|
|
899
|
+
/* make a freshly created strict host function `f` a guest function object (prototype, length,
|
|
900
|
+
name, metadata). A `function` must have had its host `prototype` property replaced already. */
|
|
901
|
+
export function js_init_host_function(ctx, f, is_ctor, name, length, proto, class_id) {
|
|
902
|
+
Object.setPrototypeOf(f, JS_IsObject(proto) ? proto : null);
|
|
903
|
+
Reflect.defineProperty(f, 'length', { value: length, writable: false, enumerable: false, configurable: true });
|
|
904
|
+
Reflect.defineProperty(f, 'name', { value: name, writable: false, enumerable: false, configurable: true });
|
|
905
|
+
const m = new JSObjectMeta(class_id);
|
|
906
|
+
m.is_constructor = is_ctor;
|
|
907
|
+
m.realm = ctx;
|
|
908
|
+
js_meta.set(f, m);
|
|
909
|
+
return m;
|
|
910
|
+
}
|
|
911
|
+
export function JS_IsFunction(ctx, val) {
|
|
912
|
+
return typeof val === 'function';
|
|
913
|
+
}
|
|
914
|
+
/* IsConstructor for host functions without metadata (bound functions
|
|
915
|
+
created by the host, borrowed natives): Reflect.construct validates its
|
|
916
|
+
new.target argument without calling it */
|
|
917
|
+
function js_is_host_constructor(f) {
|
|
918
|
+
try {
|
|
919
|
+
Reflect.construct(String, [], f);
|
|
920
|
+
return true;
|
|
921
|
+
}
|
|
922
|
+
catch {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
export function JS_IsConstructor(ctx, val) {
|
|
927
|
+
if (typeof val !== 'function')
|
|
928
|
+
return false;
|
|
929
|
+
const m = js_meta.get(val);
|
|
930
|
+
if (m)
|
|
931
|
+
return m.is_constructor;
|
|
932
|
+
return js_is_host_constructor(val);
|
|
933
|
+
}
|
|
934
|
+
export function JS_SetConstructorBit(ctx, func_obj, val) {
|
|
935
|
+
if (typeof func_obj !== 'function')
|
|
936
|
+
return false;
|
|
937
|
+
js_ensure_meta(func_obj, 12 /* JSClassID.C_FUNCTION */).is_constructor = val;
|
|
938
|
+
return true;
|
|
939
|
+
}
|
|
940
|
+
/* IsArray: -1 on exception (revoked proxy) */
|
|
941
|
+
export function JS_IsArray(ctx, val) {
|
|
942
|
+
const m = js_get_meta(val);
|
|
943
|
+
if (m && m.class_id === 44 /* JSClassID.PROXY */) {
|
|
944
|
+
const s = m.u;
|
|
945
|
+
if (s.is_revoked) {
|
|
946
|
+
JS_ThrowTypeError(ctx, 'revoked proxy');
|
|
947
|
+
return -1;
|
|
948
|
+
}
|
|
949
|
+
return JS_IsArray(ctx, s.target);
|
|
950
|
+
}
|
|
951
|
+
try {
|
|
952
|
+
return Array.isArray(val) ? 1 : 0;
|
|
953
|
+
}
|
|
954
|
+
catch (e) {
|
|
955
|
+
JS_ThrowTypeError(ctx, 'revoked proxy');
|
|
956
|
+
return -1;
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
function js_cfunc_is_ctor(cproto) {
|
|
960
|
+
return cproto === 2 /* JSCFunctionEnum.constructor */ ||
|
|
961
|
+
cproto === 3 /* JSCFunctionEnum.constructor_magic */ ||
|
|
962
|
+
cproto === 4 /* JSCFunctionEnum.constructor_or_func */ ||
|
|
963
|
+
cproto === 5 /* JSCFunctionEnum.constructor_or_func_magic */;
|
|
964
|
+
}
|
|
965
|
+
export function JS_NewCFunction3(ctx, func, name, length, cproto, magic, proto_val) {
|
|
966
|
+
const rec = new JSCFunctionRecord(func, length, cproto, magic);
|
|
967
|
+
let fobj;
|
|
968
|
+
const impl = (this_val, new_target, args) => {
|
|
969
|
+
let ret;
|
|
970
|
+
if (new_target !== undefined)
|
|
971
|
+
ret = js_call_c_function(ctx, fobj, new_target, args, JS_CALL_FLAG_CONSTRUCTOR);
|
|
972
|
+
else
|
|
973
|
+
ret = js_call_c_function(ctx, fobj, this_val, args, 0);
|
|
974
|
+
if (ret === JS_EXCEPTION)
|
|
975
|
+
throw js_take_exception(ctx);
|
|
976
|
+
return ret;
|
|
977
|
+
};
|
|
978
|
+
fobj = js_new_host_function(ctx, impl, js_cfunc_is_ctor(cproto), name, length, proto_val, 12 /* JSClassID.C_FUNCTION */);
|
|
979
|
+
js_meta.get(fobj).cfunc = rec;
|
|
980
|
+
return fobj;
|
|
981
|
+
}
|
|
982
|
+
export function JS_NewCFunction2(ctx, func, name, length, cproto, magic) {
|
|
983
|
+
return JS_NewCFunction3(ctx, func, name, length, cproto, magic, ctx.function_proto);
|
|
984
|
+
}
|
|
985
|
+
export function JS_NewCFunction(ctx, func, name, length) {
|
|
986
|
+
return JS_NewCFunction2(ctx, func, name, length, 0 /* JSCFunctionEnum.generic */, 0);
|
|
987
|
+
}
|
|
988
|
+
export function JS_NewCFunctionMagic(ctx, func, name, length, cproto, magic) {
|
|
989
|
+
return JS_NewCFunction2(ctx, func, name, length, cproto, magic);
|
|
990
|
+
}
|
|
991
|
+
export function JS_NewCFunctionData(ctx, func, length, magic, data) {
|
|
992
|
+
const s = new JSCFunctionDataRecord(func, length, magic, data.slice());
|
|
993
|
+
let fobj;
|
|
994
|
+
const impl = (this_val, new_target, args) => {
|
|
995
|
+
const ret = js_c_function_data_call(ctx, fobj, this_val, args, 0);
|
|
996
|
+
if (ret === JS_EXCEPTION)
|
|
997
|
+
throw js_take_exception(ctx);
|
|
998
|
+
return ret;
|
|
999
|
+
};
|
|
1000
|
+
fobj = js_new_host_function(ctx, impl, false, '', length, ctx.function_proto, 15 /* JSClassID.C_FUNCTION_DATA */);
|
|
1001
|
+
js_meta.get(fobj).u = s;
|
|
1002
|
+
return fobj;
|
|
1003
|
+
}
|
|
1004
|
+
export function js_c_function_data_call(ctx, func_obj, this_val, argv, flags) {
|
|
1005
|
+
const s = js_meta.get(func_obj).u;
|
|
1006
|
+
const rt = ctx.rt;
|
|
1007
|
+
if (rt.stack_depth >= rt.max_stack_depth)
|
|
1008
|
+
return JS_ThrowStackOverflow(ctx);
|
|
1009
|
+
const sf = new JSStackFrame();
|
|
1010
|
+
sf.cur_func = func_obj;
|
|
1011
|
+
sf.arg_buf = argv;
|
|
1012
|
+
sf.arg_count = argv.length;
|
|
1013
|
+
sf.prev_frame = rt.current_stack_frame;
|
|
1014
|
+
rt.current_stack_frame = sf;
|
|
1015
|
+
rt.stack_depth++;
|
|
1016
|
+
try {
|
|
1017
|
+
return s.func(ctx, this_val, argv, s.magic, s.data);
|
|
1018
|
+
}
|
|
1019
|
+
finally {
|
|
1020
|
+
rt.current_stack_frame = sf.prev_frame;
|
|
1021
|
+
rt.stack_depth--;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
/* call a C function. In the constructor case, 'this_obj' is new_target. */
|
|
1025
|
+
export function js_call_c_function(ctx, func_obj, this_obj, argv, flags) {
|
|
1026
|
+
const meta = js_meta.get(func_obj);
|
|
1027
|
+
const rec = meta.cfunc;
|
|
1028
|
+
const rt = ctx.rt;
|
|
1029
|
+
const realm = meta.realm;
|
|
1030
|
+
if (rt.stack_depth >= rt.max_stack_depth)
|
|
1031
|
+
return JS_ThrowStackOverflow(ctx);
|
|
1032
|
+
const sf = new JSStackFrame();
|
|
1033
|
+
sf.cur_func = func_obj;
|
|
1034
|
+
sf.arg_buf = argv;
|
|
1035
|
+
sf.arg_count = argv.length;
|
|
1036
|
+
sf.prev_frame = rt.current_stack_frame;
|
|
1037
|
+
rt.current_stack_frame = sf;
|
|
1038
|
+
rt.stack_depth++;
|
|
1039
|
+
/* argv is not padded: argv.length is argc and missing arguments read as undefined */
|
|
1040
|
+
const args = argv;
|
|
1041
|
+
let ret;
|
|
1042
|
+
const f = rec.func;
|
|
1043
|
+
try {
|
|
1044
|
+
switch (rec.cproto) {
|
|
1045
|
+
case 2 /* JSCFunctionEnum.constructor */:
|
|
1046
|
+
case 4 /* JSCFunctionEnum.constructor_or_func */:
|
|
1047
|
+
if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
|
|
1048
|
+
if (rec.cproto === 2 /* JSCFunctionEnum.constructor */) {
|
|
1049
|
+
ret = JS_ThrowTypeError(realm, 'must be called with new');
|
|
1050
|
+
break;
|
|
1051
|
+
}
|
|
1052
|
+
this_obj = undefined;
|
|
1053
|
+
}
|
|
1054
|
+
ret = f(realm, this_obj, args);
|
|
1055
|
+
break;
|
|
1056
|
+
case 3 /* JSCFunctionEnum.constructor_magic */:
|
|
1057
|
+
case 5 /* JSCFunctionEnum.constructor_or_func_magic */:
|
|
1058
|
+
if (!(flags & JS_CALL_FLAG_CONSTRUCTOR)) {
|
|
1059
|
+
if (rec.cproto === 3 /* JSCFunctionEnum.constructor_magic */) {
|
|
1060
|
+
ret = JS_ThrowTypeError(realm, 'must be called with new');
|
|
1061
|
+
break;
|
|
1062
|
+
}
|
|
1063
|
+
this_obj = undefined;
|
|
1064
|
+
}
|
|
1065
|
+
ret = f(realm, this_obj, args, rec.magic);
|
|
1066
|
+
break;
|
|
1067
|
+
case 0 /* JSCFunctionEnum.generic */:
|
|
1068
|
+
ret = f(realm, this_obj, args);
|
|
1069
|
+
break;
|
|
1070
|
+
case 1 /* JSCFunctionEnum.generic_magic */:
|
|
1071
|
+
ret = f(realm, this_obj, args, rec.magic);
|
|
1072
|
+
break;
|
|
1073
|
+
case 8 /* JSCFunctionEnum.getter */:
|
|
1074
|
+
ret = f(realm, this_obj);
|
|
1075
|
+
break;
|
|
1076
|
+
case 9 /* JSCFunctionEnum.setter */:
|
|
1077
|
+
ret = f(realm, this_obj, args[0]);
|
|
1078
|
+
break;
|
|
1079
|
+
case 10 /* JSCFunctionEnum.getter_magic */:
|
|
1080
|
+
ret = f(realm, this_obj, rec.magic);
|
|
1081
|
+
break;
|
|
1082
|
+
case 11 /* JSCFunctionEnum.setter_magic */:
|
|
1083
|
+
ret = f(realm, this_obj, args[0], rec.magic);
|
|
1084
|
+
break;
|
|
1085
|
+
case 6 /* JSCFunctionEnum.f_f */: {
|
|
1086
|
+
const d1 = JS_ToFloat64(realm, args[0]);
|
|
1087
|
+
if (JS_IsException(d1)) {
|
|
1088
|
+
ret = JS_EXCEPTION;
|
|
1089
|
+
break;
|
|
1090
|
+
}
|
|
1091
|
+
ret = f(d1);
|
|
1092
|
+
break;
|
|
1093
|
+
}
|
|
1094
|
+
case 7 /* JSCFunctionEnum.f_f_f */: {
|
|
1095
|
+
const d1 = JS_ToFloat64(realm, args[0]);
|
|
1096
|
+
if (JS_IsException(d1)) {
|
|
1097
|
+
ret = JS_EXCEPTION;
|
|
1098
|
+
break;
|
|
1099
|
+
}
|
|
1100
|
+
const d2 = JS_ToFloat64(realm, args[1]);
|
|
1101
|
+
if (JS_IsException(d2)) {
|
|
1102
|
+
ret = JS_EXCEPTION;
|
|
1103
|
+
break;
|
|
1104
|
+
}
|
|
1105
|
+
ret = f(d1, d2);
|
|
1106
|
+
break;
|
|
1107
|
+
}
|
|
1108
|
+
case 12 /* JSCFunctionEnum.iterator_next */: {
|
|
1109
|
+
const pdone = { done: 0 };
|
|
1110
|
+
ret = f(realm, this_obj, args, pdone, rec.magic);
|
|
1111
|
+
if (!JS_IsException(ret) && pdone.done !== 2) {
|
|
1112
|
+
ret = js_create_iterator_result(realm, ret, pdone.done !== 0);
|
|
1113
|
+
}
|
|
1114
|
+
break;
|
|
1115
|
+
}
|
|
1116
|
+
default:
|
|
1117
|
+
throw new JSInternalError('unknown cproto ' + rec.cproto);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
finally {
|
|
1121
|
+
rt.current_stack_frame = sf.prev_frame;
|
|
1122
|
+
rt.stack_depth--;
|
|
1123
|
+
}
|
|
1124
|
+
return ret;
|
|
1125
|
+
}
|
|
1126
|
+
/* call a host function (bound function, generated code, borrowed native,
|
|
1127
|
+
guest wrapper) with the host exception convention */
|
|
1128
|
+
export function js_call_host_function(ctx, func_obj, this_obj, new_target, argv, flags) {
|
|
1129
|
+
const rt = ctx.rt;
|
|
1130
|
+
if (rt.stack_depth >= rt.max_stack_depth)
|
|
1131
|
+
return JS_ThrowStackOverflow(ctx);
|
|
1132
|
+
rt.stack_depth++;
|
|
1133
|
+
try {
|
|
1134
|
+
if (flags & JS_CALL_FLAG_CONSTRUCTOR) {
|
|
1135
|
+
return Reflect.construct(func_obj, argv, (new_target === undefined ? func_obj : new_target));
|
|
1136
|
+
}
|
|
1137
|
+
return Reflect.apply(func_obj, this_obj, argv);
|
|
1138
|
+
}
|
|
1139
|
+
catch (e) {
|
|
1140
|
+
return js_host_exception_to_guest(ctx, e);
|
|
1141
|
+
}
|
|
1142
|
+
finally {
|
|
1143
|
+
rt.stack_depth--;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
export function JS_Call(ctx, func_obj, this_obj, argv) {
|
|
1147
|
+
return hooks.JS_CallInternal(ctx, func_obj, this_obj, undefined, argv, JS_CALL_FLAG_COPY_ARGV);
|
|
1148
|
+
}
|
|
1149
|
+
export function JS_CallFree(ctx, func_obj, this_obj, argv) {
|
|
1150
|
+
return hooks.JS_CallInternal(ctx, func_obj, this_obj, undefined, argv, JS_CALL_FLAG_COPY_ARGV);
|
|
1151
|
+
}
|
|
1152
|
+
export function JS_CallConstructorInternal(ctx, func_obj, new_target, argv, flags) {
|
|
1153
|
+
flags |= JS_CALL_FLAG_CONSTRUCTOR;
|
|
1154
|
+
if (typeof func_obj !== 'function')
|
|
1155
|
+
return JS_ThrowTypeError(ctx, 'not a function');
|
|
1156
|
+
if (!JS_IsConstructor(ctx, func_obj))
|
|
1157
|
+
return JS_ThrowTypeError(ctx, 'not a constructor');
|
|
1158
|
+
/* bytecode functions, C functions and proxies: the 'this' value is
|
|
1159
|
+
created by the callee from new_target */
|
|
1160
|
+
return hooks.JS_CallInternal(ctx, func_obj, new_target, new_target, argv, flags);
|
|
1161
|
+
}
|
|
1162
|
+
export function JS_CallConstructor2(ctx, func_obj, new_target, argv) {
|
|
1163
|
+
return JS_CallConstructorInternal(ctx, func_obj, new_target, argv, JS_CALL_FLAG_COPY_ARGV);
|
|
1164
|
+
}
|
|
1165
|
+
export function JS_CallConstructor(ctx, func_obj, argv) {
|
|
1166
|
+
return JS_CallConstructorInternal(ctx, func_obj, func_obj, argv, JS_CALL_FLAG_COPY_ARGV);
|
|
1167
|
+
}
|
|
1168
|
+
export function JS_Invoke(ctx, this_val, atom, argv) {
|
|
1169
|
+
const func = JS_GetProperty(ctx, this_val, atom);
|
|
1170
|
+
if (JS_IsException(func))
|
|
1171
|
+
return func;
|
|
1172
|
+
return JS_CallFree(ctx, func, this_val, argv);
|
|
1173
|
+
}
|
|
1174
|
+
/* get the function realm: used for the default prototype of new objects */
|
|
1175
|
+
export function JS_GetFunctionRealm(ctx, func_obj) {
|
|
1176
|
+
const m = js_get_meta(func_obj);
|
|
1177
|
+
if (!m)
|
|
1178
|
+
return ctx;
|
|
1179
|
+
switch (m.class_id) {
|
|
1180
|
+
case 12 /* JSClassID.C_FUNCTION */:
|
|
1181
|
+
case 15 /* JSClassID.C_FUNCTION_DATA */:
|
|
1182
|
+
return m.realm ?? ctx;
|
|
1183
|
+
case 13 /* JSClassID.BYTECODE_FUNCTION */:
|
|
1184
|
+
case 16 /* JSClassID.GENERATOR_FUNCTION */:
|
|
1185
|
+
case 48 /* JSClassID.ASYNC_FUNCTION */:
|
|
1186
|
+
case 52 /* JSClassID.ASYNC_GENERATOR_FUNCTION */:
|
|
1187
|
+
return m.func?.function_bytecode.realm ?? m.realm ?? ctx;
|
|
1188
|
+
case 14 /* JSClassID.BOUND_FUNCTION */:
|
|
1189
|
+
return JS_GetFunctionRealm(ctx, m.u.func_obj);
|
|
1190
|
+
case 44 /* JSClassID.PROXY */: {
|
|
1191
|
+
const s = m.u;
|
|
1192
|
+
if (s.is_revoked) {
|
|
1193
|
+
JS_ThrowTypeError(ctx, 'revoked proxy');
|
|
1194
|
+
return ctx;
|
|
1195
|
+
}
|
|
1196
|
+
return JS_GetFunctionRealm(ctx, s.target);
|
|
1197
|
+
}
|
|
1198
|
+
default:
|
|
1199
|
+
return ctx;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
/* GetPrototypeFromConstructor: create an object with the prototype taken
|
|
1203
|
+
from the 'prototype' property of 'ctor' or the default class proto */
|
|
1204
|
+
export function js_create_from_ctor(ctx, ctor, class_id) {
|
|
1205
|
+
const proto = js_proto_from_ctor(ctx, ctor, class_id);
|
|
1206
|
+
if (JS_IsException(proto))
|
|
1207
|
+
return proto;
|
|
1208
|
+
return JS_NewObjectProtoClass(ctx, proto, class_id);
|
|
1209
|
+
}
|
|
1210
|
+
/* GetPrototypeFromConstructor: the prototype to use for an object created
|
|
1211
|
+
by 'ctor' (undefined: the default class prototype) */
|
|
1212
|
+
export function js_proto_from_ctor(ctx, ctor, class_id) {
|
|
1213
|
+
if (JS_IsUndefined(ctor))
|
|
1214
|
+
return ctx.class_proto[class_id];
|
|
1215
|
+
const proto = JS_GetProperty(ctx, ctor, JS_ATOM_prototype);
|
|
1216
|
+
if (JS_IsException(proto))
|
|
1217
|
+
return proto;
|
|
1218
|
+
if (!JS_IsObject(proto)) {
|
|
1219
|
+
const realm = JS_GetFunctionRealm(ctx, ctor);
|
|
1220
|
+
return realm.class_proto[class_id];
|
|
1221
|
+
}
|
|
1222
|
+
return proto;
|
|
1223
|
+
}
|
|
1224
|
+
/* Primitive wrapper objects (Number, String, Boolean, Symbol and BigInt
|
|
1225
|
+
instances) are host wrapper objects re-prototyped to the guest prototype,
|
|
1226
|
+
so that host natives (JSON.stringify, String.prototype.valueOf, ...) see
|
|
1227
|
+
the internal slot. The engine reads the value from the metadata. */
|
|
1228
|
+
export function js_new_primitive_wrapper(ctx, proto, class_id, value) {
|
|
1229
|
+
const obj = Object(value);
|
|
1230
|
+
Object.setPrototypeOf(obj, JS_IsObject(proto) ? proto : null);
|
|
1231
|
+
const m = new JSObjectMeta(class_id);
|
|
1232
|
+
m.u = value;
|
|
1233
|
+
js_meta.set(obj, m);
|
|
1234
|
+
return obj;
|
|
1235
|
+
}
|
|
1236
|
+
export function js_create_wrapper_from_ctor(ctx, ctor, class_id, value) {
|
|
1237
|
+
const proto = js_proto_from_ctor(ctx, ctor, class_id);
|
|
1238
|
+
if (JS_IsException(proto))
|
|
1239
|
+
return proto;
|
|
1240
|
+
return js_new_primitive_wrapper(ctx, proto, class_id, value);
|
|
1241
|
+
}
|
|
1242
|
+
export function JS_SetConstructor2(ctx, func_obj, proto, proto_flags, ctor_flags) {
|
|
1243
|
+
JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_prototype, proto, proto_flags);
|
|
1244
|
+
JS_DefinePropertyValue(ctx, proto, JS_ATOM_constructor, func_obj, ctor_flags);
|
|
1245
|
+
if (typeof func_obj === 'function')
|
|
1246
|
+
js_ensure_meta(func_obj, 12 /* JSClassID.C_FUNCTION */).is_constructor = true;
|
|
1247
|
+
}
|
|
1248
|
+
export function JS_SetConstructor(ctx, func_obj, proto) {
|
|
1249
|
+
JS_SetConstructor2(ctx, func_obj, proto, 0, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
1250
|
+
}
|
|
1251
|
+
export function JS_NewGlobalCConstructor2(ctx, func_obj, name, proto) {
|
|
1252
|
+
JS_DefinePropertyValueStr(ctx, ctx.global_obj, name, func_obj, JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
|
1253
|
+
JS_SetConstructor(ctx, func_obj, proto);
|
|
1254
|
+
return func_obj;
|
|
1255
|
+
}
|
|
1256
|
+
export function JS_NewGlobalCConstructor(ctx, name, func, length, proto) {
|
|
1257
|
+
const func_obj = JS_NewCFunction2(ctx, func, name, length, 4 /* JSCFunctionEnum.constructor_or_func */, 0);
|
|
1258
|
+
return JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
|
|
1259
|
+
}
|
|
1260
|
+
export function JS_NewGlobalCConstructorOnly(ctx, name, func, length, proto) {
|
|
1261
|
+
const func_obj = JS_NewCFunction2(ctx, func, name, length, 2 /* JSCFunctionEnum.constructor */, 0);
|
|
1262
|
+
return JS_NewGlobalCConstructor2(ctx, func_obj, name, proto);
|
|
1263
|
+
}
|
|
1264
|
+
export function JS_NATIVE_DEF(name, length, host, fix = null) {
|
|
1265
|
+
return { name, prop_flags: JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, def_type: 10 /* JSDefKind.NATIVE */, magic: 0,
|
|
1266
|
+
u: { length, host, fix } };
|
|
1267
|
+
}
|
|
1268
|
+
export function JS_NATIVE_GETSET_DEF(name, get, set, fix = null) {
|
|
1269
|
+
return { name, prop_flags: JS_PROP_CONFIGURABLE, def_type: 11 /* JSDefKind.NATIVE_GETSET */, magic: 0, u: { get, set, fix } };
|
|
1270
|
+
}
|
|
1271
|
+
export function JS_CFUNC_DEF(name, length, func) {
|
|
1272
|
+
return { name, prop_flags: JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, def_type: 0 /* JSDefKind.CFUNC */, magic: 0,
|
|
1273
|
+
u: { length, cproto: 0 /* JSCFunctionEnum.generic */, func } };
|
|
1274
|
+
}
|
|
1275
|
+
export function JS_CFUNC_MAGIC_DEF(name, length, func, magic) {
|
|
1276
|
+
return { name, prop_flags: JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, def_type: 0 /* JSDefKind.CFUNC */, magic,
|
|
1277
|
+
u: { length, cproto: 1 /* JSCFunctionEnum.generic_magic */, func } };
|
|
1278
|
+
}
|
|
1279
|
+
export function JS_CFUNC_SPECIAL_DEF(name, length, cproto, func) {
|
|
1280
|
+
return { name, prop_flags: JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, def_type: 0 /* JSDefKind.CFUNC */, magic: 0,
|
|
1281
|
+
u: { length, cproto, func } };
|
|
1282
|
+
}
|
|
1283
|
+
export function JS_ITERATOR_NEXT_DEF(name, length, func, magic) {
|
|
1284
|
+
return { name, prop_flags: JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, def_type: 0 /* JSDefKind.CFUNC */, magic,
|
|
1285
|
+
u: { length, cproto: 12 /* JSCFunctionEnum.iterator_next */, func } };
|
|
1286
|
+
}
|
|
1287
|
+
export function JS_CGETSET_DEF(name, fgetter, fsetter) {
|
|
1288
|
+
return { name, prop_flags: JS_PROP_CONFIGURABLE, def_type: 1 /* JSDefKind.CGETSET */, magic: 0, u: { get: fgetter, set: fsetter } };
|
|
1289
|
+
}
|
|
1290
|
+
export function JS_CGETSET_MAGIC_DEF(name, fgetter, fsetter, magic) {
|
|
1291
|
+
return { name, prop_flags: JS_PROP_CONFIGURABLE, def_type: 2 /* JSDefKind.CGETSET_MAGIC */, magic, u: { get: fgetter, set: fsetter } };
|
|
1292
|
+
}
|
|
1293
|
+
export function JS_CGETSET_ENUMERABLE_DEF(name, fgetter, fsetter) {
|
|
1294
|
+
return { name, prop_flags: JS_PROP_CONFIGURABLE | JS_PROP_ENUMERABLE, def_type: 1 /* JSDefKind.CGETSET */, magic: 0, u: { get: fgetter, set: fsetter } };
|
|
1295
|
+
}
|
|
1296
|
+
export function JS_PROP_STRING_DEF(name, cstr, prop_flags) {
|
|
1297
|
+
return { name, prop_flags, def_type: 3 /* JSDefKind.PROP_STRING */, magic: 0, u: cstr };
|
|
1298
|
+
}
|
|
1299
|
+
export function JS_PROP_INT32_DEF(name, val, prop_flags) {
|
|
1300
|
+
return { name, prop_flags, def_type: 4 /* JSDefKind.PROP_INT32 */, magic: 0, u: val };
|
|
1301
|
+
}
|
|
1302
|
+
export function JS_PROP_INT64_DEF(name, val, prop_flags) {
|
|
1303
|
+
return { name, prop_flags, def_type: 5 /* JSDefKind.PROP_INT64 */, magic: 0, u: val };
|
|
1304
|
+
}
|
|
1305
|
+
export function JS_PROP_DOUBLE_DEF(name, val, prop_flags) {
|
|
1306
|
+
return { name, prop_flags, def_type: 6 /* JSDefKind.PROP_DOUBLE */, magic: 0, u: val };
|
|
1307
|
+
}
|
|
1308
|
+
export function JS_PROP_UNDEFINED_DEF(name, prop_flags) {
|
|
1309
|
+
return { name, prop_flags, def_type: 7 /* JSDefKind.PROP_UNDEFINED */, magic: 0, u: undefined };
|
|
1310
|
+
}
|
|
1311
|
+
export function JS_OBJECT_DEF(name, tab, prop_flags) {
|
|
1312
|
+
return { name, prop_flags, def_type: 8 /* JSDefKind.OBJECT */, magic: 0, u: tab };
|
|
1313
|
+
}
|
|
1314
|
+
export function JS_ALIAS_DEF(name, from) {
|
|
1315
|
+
return { name, prop_flags: JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, def_type: 9 /* JSDefKind.ALIAS */, magic: 0, u: { name: from, base: -1 } };
|
|
1316
|
+
}
|
|
1317
|
+
export function JS_ALIAS_BASE_DEF(name, from, base) {
|
|
1318
|
+
return { name, prop_flags: JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE, def_type: 9 /* JSDefKind.ALIAS */, magic: 0, u: { name: from, base } };
|
|
1319
|
+
}
|
|
1320
|
+
function entry_name_atom(ctx, name) {
|
|
1321
|
+
if (typeof name === 'number')
|
|
1322
|
+
return name;
|
|
1323
|
+
return JS_NewAtom(ctx, name);
|
|
1324
|
+
}
|
|
1325
|
+
function entry_display_name(ctx, atom) {
|
|
1326
|
+
if (ctx.rt.atoms.isSymbol(atom))
|
|
1327
|
+
return '[' + ctx.rt.atoms.toStr(atom) + ']';
|
|
1328
|
+
return ctx.rt.atoms.toStr(atom);
|
|
1329
|
+
}
|
|
1330
|
+
export function JS_InstantiateFunctionListItem(ctx, obj, atom, e) {
|
|
1331
|
+
let val;
|
|
1332
|
+
let prop_flags = e.prop_flags;
|
|
1333
|
+
switch (e.def_type) {
|
|
1334
|
+
case 9 /* JSDefKind.ALIAS */: {
|
|
1335
|
+
/* base: -1 = same object, 0 = global object, 1 = Array.prototype (as in C) */
|
|
1336
|
+
let base_obj = obj;
|
|
1337
|
+
if (e.u.base === 0)
|
|
1338
|
+
base_obj = ctx.global_obj;
|
|
1339
|
+
else if (e.u.base === 1)
|
|
1340
|
+
base_obj = ctx.class_proto[2 /* JSClassID.ARRAY */];
|
|
1341
|
+
const atom1 = JS_NewAtom(ctx, e.u.name);
|
|
1342
|
+
val = JS_GetProperty(ctx, base_obj, atom1);
|
|
1343
|
+
break;
|
|
1344
|
+
}
|
|
1345
|
+
case 0 /* JSDefKind.CFUNC */: {
|
|
1346
|
+
const name = entry_display_name(ctx, atom);
|
|
1347
|
+
val = JS_NewCFunction3(ctx, e.u.func, name, e.u.length, e.u.cproto, e.magic, ctx.function_proto);
|
|
1348
|
+
break;
|
|
1349
|
+
}
|
|
1350
|
+
case 1 /* JSDefKind.CGETSET */:
|
|
1351
|
+
case 2 /* JSDefKind.CGETSET_MAGIC */: {
|
|
1352
|
+
let getter = undefined, setter = undefined;
|
|
1353
|
+
const name = entry_display_name(ctx, atom);
|
|
1354
|
+
if (e.u.get) {
|
|
1355
|
+
getter = JS_NewCFunction3(ctx, e.u.get, 'get ' + name, 0, e.def_type === 2 /* JSDefKind.CGETSET_MAGIC */ ? 10 /* JSCFunctionEnum.getter_magic */ : 8 /* JSCFunctionEnum.getter */, e.magic, ctx.function_proto);
|
|
1356
|
+
}
|
|
1357
|
+
if (e.u.set) {
|
|
1358
|
+
setter = JS_NewCFunction3(ctx, e.u.set, 'set ' + name, 1, e.def_type === 2 /* JSDefKind.CGETSET_MAGIC */ ? 11 /* JSCFunctionEnum.setter_magic */ : 9 /* JSCFunctionEnum.setter */, e.magic, ctx.function_proto);
|
|
1359
|
+
}
|
|
1360
|
+
JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags);
|
|
1361
|
+
return 0;
|
|
1362
|
+
}
|
|
1363
|
+
case 10 /* JSDefKind.NATIVE */: {
|
|
1364
|
+
const name = entry_display_name(ctx, atom);
|
|
1365
|
+
val = hooks.js_borrow_native(ctx, e.u.host, name, e.u.length, e.u.fix);
|
|
1366
|
+
break;
|
|
1367
|
+
}
|
|
1368
|
+
case 11 /* JSDefKind.NATIVE_GETSET */: {
|
|
1369
|
+
const name = entry_display_name(ctx, atom);
|
|
1370
|
+
const getter = e.u.get ? hooks.js_borrow_native(ctx, e.u.get, 'get ' + name, 0, e.u.fix) : undefined;
|
|
1371
|
+
const setter = e.u.set ? hooks.js_borrow_native(ctx, e.u.set, 'set ' + name, 1, null) : undefined;
|
|
1372
|
+
JS_DefinePropertyGetSet(ctx, obj, atom, getter, setter, prop_flags);
|
|
1373
|
+
return 0;
|
|
1374
|
+
}
|
|
1375
|
+
case 3 /* JSDefKind.PROP_STRING */:
|
|
1376
|
+
val = e.u;
|
|
1377
|
+
break;
|
|
1378
|
+
case 4 /* JSDefKind.PROP_INT32 */:
|
|
1379
|
+
case 5 /* JSDefKind.PROP_INT64 */:
|
|
1380
|
+
case 6 /* JSDefKind.PROP_DOUBLE */:
|
|
1381
|
+
val = e.u;
|
|
1382
|
+
break;
|
|
1383
|
+
case 7 /* JSDefKind.PROP_UNDEFINED */:
|
|
1384
|
+
val = undefined;
|
|
1385
|
+
break;
|
|
1386
|
+
case 8 /* JSDefKind.OBJECT */:
|
|
1387
|
+
val = JS_NewObject(ctx);
|
|
1388
|
+
JS_SetPropertyFunctionList(ctx, val, e.u);
|
|
1389
|
+
break;
|
|
1390
|
+
default:
|
|
1391
|
+
throw new JSInternalError('bad def_type');
|
|
1392
|
+
}
|
|
1393
|
+
JS_DefinePropertyValue(ctx, obj, atom, val, prop_flags);
|
|
1394
|
+
return 0;
|
|
1395
|
+
}
|
|
1396
|
+
export function JS_SetPropertyFunctionList(ctx, obj, tab) {
|
|
1397
|
+
for (const e of tab) {
|
|
1398
|
+
const atom = entry_name_atom(ctx, e.name);
|
|
1399
|
+
JS_InstantiateFunctionListItem(ctx, obj, atom, e);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
/* ---------------------------------------------------------------------
|
|
1403
|
+
Properties
|
|
1404
|
+
--------------------------------------------------------------------- */
|
|
1405
|
+
export function is_typed_array(class_id) {
|
|
1406
|
+
return class_id >= 21 /* JSClassID.UINT8C_ARRAY */ && class_id <= 31 /* JSClassID.FLOAT64_ARRAY */;
|
|
1407
|
+
}
|
|
1408
|
+
export function JS_ThrowTypeErrorOrFalse(ctx, flags, msg) {
|
|
1409
|
+
if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
|
|
1410
|
+
JS_ThrowTypeError(ctx, msg);
|
|
1411
|
+
return -1;
|
|
1412
|
+
}
|
|
1413
|
+
return 0;
|
|
1414
|
+
}
|
|
1415
|
+
/* return 1 if the flags are compatible (ValidateAndApplyPropertyDescriptor
|
|
1416
|
+
for non configurable properties when there is no value change) */
|
|
1417
|
+
export function check_define_prop_flags(prop_flags, flags) {
|
|
1418
|
+
const has_accessor = (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) !== 0;
|
|
1419
|
+
if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
|
|
1420
|
+
if ((flags & (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE)) === (JS_PROP_HAS_CONFIGURABLE | JS_PROP_CONFIGURABLE))
|
|
1421
|
+
return false;
|
|
1422
|
+
if ((flags & JS_PROP_HAS_ENUMERABLE) && (flags & JS_PROP_ENUMERABLE) !== (prop_flags & JS_PROP_ENUMERABLE))
|
|
1423
|
+
return false;
|
|
1424
|
+
}
|
|
1425
|
+
if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
|
|
1426
|
+
if (!(prop_flags & JS_PROP_CONFIGURABLE)) {
|
|
1427
|
+
const has_value = (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE)) !== 0;
|
|
1428
|
+
const is_getset = (prop_flags & JS_PROP_TMASK) === JS_PROP_GETSET;
|
|
1429
|
+
if (has_accessor && !is_getset)
|
|
1430
|
+
return false;
|
|
1431
|
+
if (has_value && is_getset)
|
|
1432
|
+
return false;
|
|
1433
|
+
if (!is_getset && !(prop_flags & JS_PROP_WRITABLE)) {
|
|
1434
|
+
if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) === (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE))
|
|
1435
|
+
return false;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
return true;
|
|
1440
|
+
}
|
|
1441
|
+
/* fill 'desc' from a host property descriptor */
|
|
1442
|
+
function js_desc_from_host(d, desc) {
|
|
1443
|
+
let flags = 0;
|
|
1444
|
+
if (d.configurable)
|
|
1445
|
+
flags |= JS_PROP_CONFIGURABLE;
|
|
1446
|
+
if (d.enumerable)
|
|
1447
|
+
flags |= JS_PROP_ENUMERABLE;
|
|
1448
|
+
if ('get' in d || 'set' in d) {
|
|
1449
|
+
flags |= JS_PROP_GETSET;
|
|
1450
|
+
desc.getter = d.get;
|
|
1451
|
+
desc.setter = d.set;
|
|
1452
|
+
desc.value = undefined;
|
|
1453
|
+
}
|
|
1454
|
+
else {
|
|
1455
|
+
if (d.writable)
|
|
1456
|
+
flags |= JS_PROP_WRITABLE;
|
|
1457
|
+
desc.value = d.value;
|
|
1458
|
+
desc.getter = undefined;
|
|
1459
|
+
desc.setter = undefined;
|
|
1460
|
+
}
|
|
1461
|
+
desc.flags = flags;
|
|
1462
|
+
}
|
|
1463
|
+
/* own property lookup: -1 exception, 0 not found, 1 found (desc filled if != null) */
|
|
1464
|
+
export function JS_GetOwnPropertyInternal(ctx, desc, p, prop) {
|
|
1465
|
+
const key = JS_AtomToKey(ctx, prop);
|
|
1466
|
+
if (desc === null && js_meta.get(p) === undefined) {
|
|
1467
|
+
/* existence only: Object.hasOwn is ~40x cheaper than building a descriptor */
|
|
1468
|
+
try {
|
|
1469
|
+
return Object.hasOwn(p, key) ? 1 : 0;
|
|
1470
|
+
}
|
|
1471
|
+
catch (e) {
|
|
1472
|
+
js_host_exception_to_guest(ctx, e);
|
|
1473
|
+
return -1;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
let d;
|
|
1477
|
+
try {
|
|
1478
|
+
d = Reflect.getOwnPropertyDescriptor(p, key);
|
|
1479
|
+
}
|
|
1480
|
+
catch (e) {
|
|
1481
|
+
js_host_exception_to_guest(ctx, e);
|
|
1482
|
+
return -1;
|
|
1483
|
+
}
|
|
1484
|
+
if (d === undefined)
|
|
1485
|
+
return 0;
|
|
1486
|
+
if (desc)
|
|
1487
|
+
js_desc_from_host(d, desc);
|
|
1488
|
+
return 1;
|
|
1489
|
+
}
|
|
1490
|
+
export function JS_GetOwnProperty(ctx, desc, obj, prop) {
|
|
1491
|
+
if (!JS_IsObject(obj)) {
|
|
1492
|
+
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
1493
|
+
return -1;
|
|
1494
|
+
}
|
|
1495
|
+
return JS_GetOwnPropertyInternal(ctx, desc, obj, prop);
|
|
1496
|
+
}
|
|
1497
|
+
export function new_desc() {
|
|
1498
|
+
return { flags: 0, value: undefined, getter: undefined, setter: undefined };
|
|
1499
|
+
}
|
|
1500
|
+
/* prototype of a primitive value (null for undefined/null) */
|
|
1501
|
+
export function JS_GetPrototypePrimitive(ctx, val) {
|
|
1502
|
+
switch (typeof val) {
|
|
1503
|
+
case 'bigint': return ctx.class_proto[33 /* JSClassID.BIG_INT */];
|
|
1504
|
+
case 'number': return ctx.class_proto[4 /* JSClassID.NUMBER */];
|
|
1505
|
+
case 'boolean': return ctx.class_proto[6 /* JSClassID.BOOLEAN */];
|
|
1506
|
+
case 'string': return ctx.class_proto[5 /* JSClassID.STRING */];
|
|
1507
|
+
case 'symbol': return ctx.class_proto[7 /* JSClassID.SYMBOL */];
|
|
1508
|
+
default: return null;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
/* return the prototype (object or null) or JS_EXCEPTION */
|
|
1512
|
+
export function JS_GetPrototype(ctx, obj) {
|
|
1513
|
+
if (JS_IsObject(obj)) {
|
|
1514
|
+
try {
|
|
1515
|
+
return Reflect.getPrototypeOf(obj);
|
|
1516
|
+
}
|
|
1517
|
+
catch (e) {
|
|
1518
|
+
return js_host_exception_to_guest(ctx, e);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
return JS_GetPrototypePrimitive(ctx, obj);
|
|
1522
|
+
}
|
|
1523
|
+
export function JS_GetPrototypeFree(ctx, obj) { return JS_GetPrototype(ctx, obj); }
|
|
1524
|
+
function js_string_own_property(ctx, str, prop) {
|
|
1525
|
+
if (__JS_AtomIsTaggedInt(prop)) {
|
|
1526
|
+
const idx = __JS_AtomToUInt32(prop);
|
|
1527
|
+
if (idx < str.length)
|
|
1528
|
+
return str[idx];
|
|
1529
|
+
return undefined;
|
|
1530
|
+
}
|
|
1531
|
+
if (prop === JS_ATOM_length)
|
|
1532
|
+
return str.length;
|
|
1533
|
+
return undefined;
|
|
1534
|
+
}
|
|
1535
|
+
/* GetProperty. 'this_obj' is the receiver. */
|
|
1536
|
+
export function JS_GetPropertyInternal(ctx, obj, prop, this_obj, throw_ref_error) {
|
|
1537
|
+
let base;
|
|
1538
|
+
switch (typeof obj) {
|
|
1539
|
+
case 'object':
|
|
1540
|
+
case 'function':
|
|
1541
|
+
if (obj === null)
|
|
1542
|
+
return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", prop);
|
|
1543
|
+
base = obj;
|
|
1544
|
+
break;
|
|
1545
|
+
case 'undefined':
|
|
1546
|
+
return JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of undefined", prop);
|
|
1547
|
+
case 'string': {
|
|
1548
|
+
const v = js_string_own_property(ctx, obj, prop);
|
|
1549
|
+
if (v !== undefined)
|
|
1550
|
+
return v;
|
|
1551
|
+
base = ctx.class_proto[5 /* JSClassID.STRING */];
|
|
1552
|
+
break;
|
|
1553
|
+
}
|
|
1554
|
+
default:
|
|
1555
|
+
base = JS_GetPrototypePrimitive(ctx, obj);
|
|
1556
|
+
break;
|
|
1557
|
+
}
|
|
1558
|
+
const key = JS_AtomToKey(ctx, prop);
|
|
1559
|
+
try {
|
|
1560
|
+
if (throw_ref_error && !Reflect.has(base, key))
|
|
1561
|
+
return JS_ThrowReferenceErrorNotDefined(ctx, prop);
|
|
1562
|
+
if (this_obj === obj && base === obj)
|
|
1563
|
+
return base[key];
|
|
1564
|
+
/* primitive base or explicit receiver: the receiver is the original value */
|
|
1565
|
+
return Reflect.get(base, key, this_obj);
|
|
1566
|
+
}
|
|
1567
|
+
catch (e) {
|
|
1568
|
+
return js_host_exception_to_guest(ctx, e);
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
export function JS_GetProperty(ctx, this_obj, prop) {
|
|
1572
|
+
return JS_GetPropertyInternal(ctx, this_obj, prop, this_obj, false);
|
|
1573
|
+
}
|
|
1574
|
+
export function JS_GetPropertyStr(ctx, this_obj, prop) {
|
|
1575
|
+
return JS_GetPropertyInternal(ctx, this_obj, JS_NewAtom(ctx, prop), this_obj, false);
|
|
1576
|
+
}
|
|
1577
|
+
export function JS_GetPropertyUint32(ctx, this_obj, idx) {
|
|
1578
|
+
return JS_GetPropertyInternal(ctx, this_obj, JS_NewAtomUInt32(ctx, idx), this_obj, false);
|
|
1579
|
+
}
|
|
1580
|
+
export function JS_GetPropertyInt64(ctx, this_obj, idx) {
|
|
1581
|
+
return JS_GetPropertyInternal(ctx, this_obj, JS_NewAtomInt64(ctx, idx), this_obj, false);
|
|
1582
|
+
}
|
|
1583
|
+
/* obj[prop] with a JS value as property key */
|
|
1584
|
+
export function JS_GetPropertyValue(ctx, this_obj, prop) {
|
|
1585
|
+
if (JS_IsObject(this_obj) && !JS_IsObject(prop) && typeof prop !== 'undefined') {
|
|
1586
|
+
/* the host performs ToPropertyKey on primitives */
|
|
1587
|
+
try {
|
|
1588
|
+
return this_obj[prop];
|
|
1589
|
+
}
|
|
1590
|
+
catch (e) {
|
|
1591
|
+
return js_host_exception_to_guest(ctx, e);
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
const atom = JS_ValueToAtom(ctx, prop);
|
|
1595
|
+
if (atom === JS_ATOM_NULL)
|
|
1596
|
+
return JS_EXCEPTION;
|
|
1597
|
+
return JS_GetPropertyInternal(ctx, this_obj, atom, this_obj, false);
|
|
1598
|
+
}
|
|
1599
|
+
/* HasProperty: -1 exception */
|
|
1600
|
+
export function JS_HasProperty(ctx, obj, prop) {
|
|
1601
|
+
if (!JS_IsObject(obj))
|
|
1602
|
+
return 0;
|
|
1603
|
+
try {
|
|
1604
|
+
return Reflect.has(obj, JS_AtomToKey(ctx, prop)) ? 1 : 0;
|
|
1605
|
+
}
|
|
1606
|
+
catch (e) {
|
|
1607
|
+
js_host_exception_to_guest(ctx, e);
|
|
1608
|
+
return -1;
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
export function JS_IsExtensible(ctx, obj) {
|
|
1612
|
+
if (!JS_IsObject(obj))
|
|
1613
|
+
return 0;
|
|
1614
|
+
try {
|
|
1615
|
+
return Reflect.isExtensible(obj) ? 1 : 0;
|
|
1616
|
+
}
|
|
1617
|
+
catch (e) {
|
|
1618
|
+
js_host_exception_to_guest(ctx, e);
|
|
1619
|
+
return -1;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
export function JS_PreventExtensions(ctx, obj) {
|
|
1623
|
+
if (!JS_IsObject(obj))
|
|
1624
|
+
return 1;
|
|
1625
|
+
try {
|
|
1626
|
+
return Reflect.preventExtensions(obj) ? 1 : 0;
|
|
1627
|
+
}
|
|
1628
|
+
catch (e) {
|
|
1629
|
+
js_host_exception_to_guest(ctx, e);
|
|
1630
|
+
return -1;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
/* SetPrototypeOf: -1 exception, 0 failed (throw_flag false), 1 ok */
|
|
1634
|
+
export function JS_SetPrototypeInternal(ctx, obj, proto_val, throw_flag) {
|
|
1635
|
+
if (!(proto_val === null || JS_IsObject(proto_val))) {
|
|
1636
|
+
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
1637
|
+
return -1;
|
|
1638
|
+
}
|
|
1639
|
+
if (!JS_IsObject(obj)) {
|
|
1640
|
+
if (obj === undefined || obj === null) {
|
|
1641
|
+
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
1642
|
+
return -1;
|
|
1643
|
+
}
|
|
1644
|
+
return 1;
|
|
1645
|
+
}
|
|
1646
|
+
let ok;
|
|
1647
|
+
try {
|
|
1648
|
+
ok = Reflect.setPrototypeOf(obj, proto_val);
|
|
1649
|
+
}
|
|
1650
|
+
catch (e) {
|
|
1651
|
+
js_host_exception_to_guest(ctx, e);
|
|
1652
|
+
return -1;
|
|
1653
|
+
}
|
|
1654
|
+
if (!ok) {
|
|
1655
|
+
if (throw_flag) {
|
|
1656
|
+
let ext = true;
|
|
1657
|
+
try {
|
|
1658
|
+
ext = Reflect.isExtensible(obj);
|
|
1659
|
+
}
|
|
1660
|
+
catch { /* ignore */ }
|
|
1661
|
+
if (JS_GetClassID(obj) === 44 /* JSClassID.PROXY */)
|
|
1662
|
+
JS_ThrowTypeError(ctx, 'proxy: bad prototype');
|
|
1663
|
+
else if (!ext)
|
|
1664
|
+
JS_ThrowTypeError(ctx, 'object is not extensible');
|
|
1665
|
+
else
|
|
1666
|
+
JS_ThrowTypeError(ctx, 'circular prototype chain');
|
|
1667
|
+
return -1;
|
|
1668
|
+
}
|
|
1669
|
+
return 0;
|
|
1670
|
+
}
|
|
1671
|
+
return 1;
|
|
1672
|
+
}
|
|
1673
|
+
export function JS_SetPrototype(ctx, obj, proto_val) {
|
|
1674
|
+
return JS_SetPrototypeInternal(ctx, obj, proto_val, true);
|
|
1675
|
+
}
|
|
1676
|
+
function js_strict_store(o, k, v) {
|
|
1677
|
+
o[k] = v; /* module code is strict: throws a host TypeError on failure */
|
|
1678
|
+
}
|
|
1679
|
+
/* after a strict store threw a host TypeError: true if the failure is one
|
|
1680
|
+
that a sloppy store would ignore (read-only data property, accessor
|
|
1681
|
+
without setter, or non-extensible receiver), false if the error came
|
|
1682
|
+
from elsewhere (e.g. a typed array element conversion) */
|
|
1683
|
+
function js_store_failed_silently(obj, key) {
|
|
1684
|
+
let o = obj;
|
|
1685
|
+
while (o !== null) {
|
|
1686
|
+
const d = Reflect.getOwnPropertyDescriptor(o, key);
|
|
1687
|
+
if (d !== undefined) {
|
|
1688
|
+
if ('value' in d)
|
|
1689
|
+
return !d.writable;
|
|
1690
|
+
return d.set === undefined;
|
|
1691
|
+
}
|
|
1692
|
+
o = Reflect.getPrototypeOf(o);
|
|
1693
|
+
}
|
|
1694
|
+
return !Reflect.isExtensible(obj);
|
|
1695
|
+
}
|
|
1696
|
+
/* true if 'e' is an error raised by the host engine itself (its prototype
|
|
1697
|
+
chain reaches the host Error.prototype), as opposed to a guest value */
|
|
1698
|
+
export function js_is_host_error(e) {
|
|
1699
|
+
return e instanceof Error;
|
|
1700
|
+
}
|
|
1701
|
+
function js_set_failed(ctx, obj, key, prop, flags) {
|
|
1702
|
+
if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
|
|
1703
|
+
if (JS_GetClassID(obj) === 44 /* JSClassID.PROXY */) {
|
|
1704
|
+
JS_ThrowTypeError(ctx, 'proxy: cannot set property');
|
|
1705
|
+
}
|
|
1706
|
+
else {
|
|
1707
|
+
let has = false;
|
|
1708
|
+
try {
|
|
1709
|
+
has = Reflect.has(obj, key);
|
|
1710
|
+
}
|
|
1711
|
+
catch { /* ignore */ }
|
|
1712
|
+
if (has)
|
|
1713
|
+
JS_ThrowTypeErrorAtom(ctx, "'%s' is read-only", prop);
|
|
1714
|
+
else
|
|
1715
|
+
JS_ThrowTypeError(ctx, 'object is not extensible');
|
|
1716
|
+
}
|
|
1717
|
+
return -1;
|
|
1718
|
+
}
|
|
1719
|
+
return 0;
|
|
1720
|
+
}
|
|
1721
|
+
/* SetProperty: -1 exception, 0 failed silently, 1 ok. 'this_obj' is the receiver. */
|
|
1722
|
+
export function JS_SetPropertyInternal(ctx, obj, prop, val, this_obj, flags) {
|
|
1723
|
+
const key = JS_AtomToKey(ctx, prop);
|
|
1724
|
+
if (JS_IsObject(obj)) {
|
|
1725
|
+
if (this_obj === obj && js_meta.get(obj)?.class_id !== 44 /* JSClassID.PROXY */) {
|
|
1726
|
+
/* plain assignment (proxies use Reflect.set below, which tells a refused
|
|
1727
|
+
trap from an invariant violation): Reflect.set is ~50x slower than an inline-cached
|
|
1728
|
+
store in JSC (and ~600 ns when appending to an array). A strict
|
|
1729
|
+
store throws a host TypeError on failure, which we diagnose with the
|
|
1730
|
+
QuickJS message; guest setters throw guest values, which propagate. */
|
|
1731
|
+
try {
|
|
1732
|
+
js_strict_store(obj, key, val);
|
|
1733
|
+
return 1;
|
|
1734
|
+
}
|
|
1735
|
+
catch (e) {
|
|
1736
|
+
if (js_is_host_error(e) && js_store_failed_silently(obj, key)) {
|
|
1737
|
+
return js_set_failed(ctx, obj, key, prop, flags);
|
|
1738
|
+
}
|
|
1739
|
+
js_host_exception_to_guest(ctx, e);
|
|
1740
|
+
return -1;
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
let ok;
|
|
1744
|
+
try {
|
|
1745
|
+
ok = Reflect.set(obj, key, val, this_obj);
|
|
1746
|
+
}
|
|
1747
|
+
catch (e) {
|
|
1748
|
+
js_host_exception_to_guest(ctx, e);
|
|
1749
|
+
return -1;
|
|
1750
|
+
}
|
|
1751
|
+
if (ok)
|
|
1752
|
+
return 1;
|
|
1753
|
+
return js_set_failed(ctx, obj, key, prop, flags);
|
|
1754
|
+
}
|
|
1755
|
+
if (obj === undefined || obj === null) {
|
|
1756
|
+
JS_ThrowTypeErrorAtom(ctx, obj === null ? "cannot set property '%s' of null" : "cannot set property '%s' of undefined", prop);
|
|
1757
|
+
return -1;
|
|
1758
|
+
}
|
|
1759
|
+
/* primitive: look for a setter in the prototype chain of the primitive */
|
|
1760
|
+
const proto = JS_GetPrototypePrimitive(ctx, obj);
|
|
1761
|
+
let ok;
|
|
1762
|
+
try {
|
|
1763
|
+
ok = Reflect.set(proto, key, val, this_obj);
|
|
1764
|
+
}
|
|
1765
|
+
catch (e) {
|
|
1766
|
+
js_host_exception_to_guest(ctx, e);
|
|
1767
|
+
return -1;
|
|
1768
|
+
}
|
|
1769
|
+
if (ok)
|
|
1770
|
+
return 1;
|
|
1771
|
+
return JS_ThrowTypeErrorOrFalse(ctx, flags, 'cannot set property on a primitive value');
|
|
1772
|
+
}
|
|
1773
|
+
export function JS_SetProperty(ctx, this_obj, prop, val) {
|
|
1774
|
+
return JS_SetPropertyInternal(ctx, this_obj, prop, val, this_obj, JS_PROP_THROW);
|
|
1775
|
+
}
|
|
1776
|
+
export function JS_SetPropertyStr(ctx, this_obj, prop, val) {
|
|
1777
|
+
return JS_SetProperty(ctx, this_obj, JS_NewAtom(ctx, prop), val);
|
|
1778
|
+
}
|
|
1779
|
+
export function JS_SetPropertyUint32(ctx, this_obj, idx, val) {
|
|
1780
|
+
return JS_SetProperty(ctx, this_obj, JS_NewAtomUInt32(ctx, idx), val);
|
|
1781
|
+
}
|
|
1782
|
+
export function JS_SetPropertyInt64(ctx, this_obj, idx, val) {
|
|
1783
|
+
return JS_SetProperty(ctx, this_obj, JS_NewAtomInt64(ctx, idx), val);
|
|
1784
|
+
}
|
|
1785
|
+
/* obj[prop] = val with a JS value as property key */
|
|
1786
|
+
export function JS_SetPropertyValue(ctx, this_obj, prop, val, flags) {
|
|
1787
|
+
if (JS_IsObject(this_obj) && !JS_IsObject(prop) && typeof prop !== 'undefined') {
|
|
1788
|
+
let ok;
|
|
1789
|
+
try {
|
|
1790
|
+
ok = Reflect.set(this_obj, prop, val);
|
|
1791
|
+
}
|
|
1792
|
+
catch (e) {
|
|
1793
|
+
js_host_exception_to_guest(ctx, e);
|
|
1794
|
+
return -1;
|
|
1795
|
+
}
|
|
1796
|
+
if (ok)
|
|
1797
|
+
return 1;
|
|
1798
|
+
const atom = JS_ValueToAtom(ctx, prop);
|
|
1799
|
+
if (atom === JS_ATOM_NULL)
|
|
1800
|
+
return -1;
|
|
1801
|
+
return js_set_failed(ctx, this_obj, JS_AtomToKey(ctx, atom), atom, flags);
|
|
1802
|
+
}
|
|
1803
|
+
const atom = JS_ValueToAtom(ctx, prop);
|
|
1804
|
+
if (atom === JS_ATOM_NULL)
|
|
1805
|
+
return -1;
|
|
1806
|
+
return JS_SetPropertyInternal(ctx, this_obj, atom, val, this_obj, flags);
|
|
1807
|
+
}
|
|
1808
|
+
export function JS_CreateDataPropertyUint32(ctx, this_obj, index, val, flags) {
|
|
1809
|
+
return JS_DefinePropertyValue(ctx, this_obj, JS_NewAtomInt64(ctx, index), val, flags | JS_PROP_C_W_E);
|
|
1810
|
+
}
|
|
1811
|
+
/* build a host property descriptor from the JS_PROP_HAS_* flags */
|
|
1812
|
+
function js_host_desc(val, getter, setter, flags) {
|
|
1813
|
+
const d = {};
|
|
1814
|
+
if (flags & JS_PROP_HAS_VALUE)
|
|
1815
|
+
d.value = val;
|
|
1816
|
+
if (flags & JS_PROP_HAS_GET)
|
|
1817
|
+
d.get = getter;
|
|
1818
|
+
if (flags & JS_PROP_HAS_SET)
|
|
1819
|
+
d.set = setter;
|
|
1820
|
+
if (flags & JS_PROP_HAS_WRITABLE)
|
|
1821
|
+
d.writable = (flags & JS_PROP_WRITABLE) !== 0;
|
|
1822
|
+
if (flags & JS_PROP_HAS_CONFIGURABLE)
|
|
1823
|
+
d.configurable = (flags & JS_PROP_CONFIGURABLE) !== 0;
|
|
1824
|
+
if (flags & JS_PROP_HAS_ENUMERABLE)
|
|
1825
|
+
d.enumerable = (flags & JS_PROP_ENUMERABLE) !== 0;
|
|
1826
|
+
return d;
|
|
1827
|
+
}
|
|
1828
|
+
/* DefineOwnProperty: -1 exception, 0 failed, 1 ok */
|
|
1829
|
+
export function JS_DefineProperty(ctx, this_obj, prop, val, getter, setter, flags) {
|
|
1830
|
+
if (!JS_IsObject(this_obj)) {
|
|
1831
|
+
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
1832
|
+
return -1;
|
|
1833
|
+
}
|
|
1834
|
+
let ok;
|
|
1835
|
+
if (this_obj === ctx.class_proto[1 /* JSClassID.OBJECT */] && prop !== JS_ATOM___proto__ &&
|
|
1836
|
+
((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) || ((flags & JS_PROP_HAS_WRITABLE) && !(flags & JS_PROP_WRITABLE)))) {
|
|
1837
|
+
ctx.plain_object_proto.ok = false;
|
|
1838
|
+
}
|
|
1839
|
+
try {
|
|
1840
|
+
ok = Reflect.defineProperty(this_obj, JS_AtomToKey(ctx, prop), js_host_desc(val, getter, setter, flags));
|
|
1841
|
+
}
|
|
1842
|
+
catch (e) {
|
|
1843
|
+
js_host_exception_to_guest(ctx, e);
|
|
1844
|
+
return -1;
|
|
1845
|
+
}
|
|
1846
|
+
if (ok)
|
|
1847
|
+
return 1;
|
|
1848
|
+
if (JS_GetClassID(this_obj) === 44 /* JSClassID.PROXY */)
|
|
1849
|
+
return JS_ThrowTypeErrorOrFalse(ctx, flags, 'proxy: inconsistent defineProperty');
|
|
1850
|
+
return JS_ThrowTypeErrorOrFalse(ctx, flags, 'property is not configurable');
|
|
1851
|
+
}
|
|
1852
|
+
export function JS_DefinePropertyValue(ctx, this_obj, prop, val, flags) {
|
|
1853
|
+
return JS_DefineProperty(ctx, this_obj, prop, val, undefined, undefined, flags | JS_PROP_HAS_VALUE | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE);
|
|
1854
|
+
}
|
|
1855
|
+
export function JS_DefinePropertyValueValue(ctx, this_obj, prop, val, flags) {
|
|
1856
|
+
const atom = JS_ValueToAtom(ctx, prop);
|
|
1857
|
+
if (atom === JS_ATOM_NULL)
|
|
1858
|
+
return -1;
|
|
1859
|
+
return JS_DefinePropertyValue(ctx, this_obj, atom, val, flags);
|
|
1860
|
+
}
|
|
1861
|
+
export function JS_DefinePropertyValueUint32(ctx, this_obj, idx, val, flags) {
|
|
1862
|
+
return JS_DefinePropertyValue(ctx, this_obj, JS_NewAtomUInt32(ctx, idx), val, flags);
|
|
1863
|
+
}
|
|
1864
|
+
export function JS_DefinePropertyValueInt64(ctx, this_obj, idx, val, flags) {
|
|
1865
|
+
return JS_DefinePropertyValue(ctx, this_obj, JS_NewAtomInt64(ctx, idx), val, flags);
|
|
1866
|
+
}
|
|
1867
|
+
export function JS_DefinePropertyValueStr(ctx, this_obj, prop, val, flags) {
|
|
1868
|
+
return JS_DefinePropertyValue(ctx, this_obj, JS_NewAtom(ctx, prop), val, flags);
|
|
1869
|
+
}
|
|
1870
|
+
export function JS_DefinePropertyGetSet(ctx, this_obj, prop, getter, setter, flags) {
|
|
1871
|
+
return JS_DefineProperty(ctx, this_obj, prop, undefined, getter, setter, flags | JS_PROP_HAS_GET | JS_PROP_HAS_SET | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_ENUMERABLE);
|
|
1872
|
+
}
|
|
1873
|
+
/* delete an own property: -1 exception, 0 not deleted, 1 deleted (or absent) */
|
|
1874
|
+
export function delete_property(ctx, p, atom) {
|
|
1875
|
+
try {
|
|
1876
|
+
return Reflect.deleteProperty(p, JS_AtomToKey(ctx, atom)) ? 1 : 0;
|
|
1877
|
+
}
|
|
1878
|
+
catch (e) {
|
|
1879
|
+
js_host_exception_to_guest(ctx, e);
|
|
1880
|
+
return -1;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
export function JS_DeleteProperty(ctx, obj, prop, flags) {
|
|
1884
|
+
const obj1 = JS_ToObject(ctx, obj);
|
|
1885
|
+
if (JS_IsException(obj1))
|
|
1886
|
+
return -1;
|
|
1887
|
+
const res = delete_property(ctx, obj1, prop);
|
|
1888
|
+
if (res !== 0)
|
|
1889
|
+
return res;
|
|
1890
|
+
if ((flags & JS_PROP_THROW) || ((flags & JS_PROP_THROW_STRICT) && is_strict_mode(ctx))) {
|
|
1891
|
+
JS_ThrowTypeError(ctx, 'could not delete property');
|
|
1892
|
+
return -1;
|
|
1893
|
+
}
|
|
1894
|
+
return 0;
|
|
1895
|
+
}
|
|
1896
|
+
export function JS_DeletePropertyInt64(ctx, obj, idx, flags) {
|
|
1897
|
+
return JS_DeleteProperty(ctx, obj, JS_NewAtomInt64(ctx, idx), flags);
|
|
1898
|
+
}
|
|
1899
|
+
/* own property keys of 'p' filtered by the JS_GPN_* flags */
|
|
1900
|
+
export function JS_GetOwnPropertyNamesInternal(ctx, p, flags) {
|
|
1901
|
+
let keys;
|
|
1902
|
+
try {
|
|
1903
|
+
keys = Reflect.ownKeys(p);
|
|
1904
|
+
}
|
|
1905
|
+
catch (e) {
|
|
1906
|
+
js_host_exception_to_guest(ctx, e);
|
|
1907
|
+
return null;
|
|
1908
|
+
}
|
|
1909
|
+
const need_enum = (flags & (JS_GPN_ENUM_ONLY | JS_GPN_SET_ENUM)) !== 0;
|
|
1910
|
+
const tab = [];
|
|
1911
|
+
for (const k of keys) {
|
|
1912
|
+
if (typeof k === 'symbol') {
|
|
1913
|
+
if (!(flags & JS_GPN_SYMBOL_MASK))
|
|
1914
|
+
continue;
|
|
1915
|
+
}
|
|
1916
|
+
else {
|
|
1917
|
+
if (!(flags & JS_GPN_STRING_MASK))
|
|
1918
|
+
continue;
|
|
1919
|
+
}
|
|
1920
|
+
let is_enumerable = true;
|
|
1921
|
+
if (need_enum) {
|
|
1922
|
+
let d;
|
|
1923
|
+
try {
|
|
1924
|
+
d = Reflect.getOwnPropertyDescriptor(p, k);
|
|
1925
|
+
}
|
|
1926
|
+
catch (e) {
|
|
1927
|
+
js_host_exception_to_guest(ctx, e);
|
|
1928
|
+
return null;
|
|
1929
|
+
}
|
|
1930
|
+
if (d === undefined)
|
|
1931
|
+
continue; /* deleted by a proxy trap */
|
|
1932
|
+
is_enumerable = !!d.enumerable;
|
|
1933
|
+
if ((flags & JS_GPN_ENUM_ONLY) && !is_enumerable)
|
|
1934
|
+
continue;
|
|
1935
|
+
}
|
|
1936
|
+
tab.push({ atom: JS_KeyToAtom(ctx, k), is_enumerable });
|
|
1937
|
+
}
|
|
1938
|
+
return tab;
|
|
1939
|
+
}
|
|
1940
|
+
export function JS_GetOwnPropertyNames(ctx, obj, flags) {
|
|
1941
|
+
if (!JS_IsObject(obj)) {
|
|
1942
|
+
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
1943
|
+
return null;
|
|
1944
|
+
}
|
|
1945
|
+
return JS_GetOwnPropertyNamesInternal(ctx, obj, flags);
|
|
1946
|
+
}
|
|
1947
|
+
/* FromPropertyDescriptor */
|
|
1948
|
+
export function JS_FromPropertyDescriptor(ctx, d) {
|
|
1949
|
+
const obj = JS_NewObject(ctx);
|
|
1950
|
+
if ((d.flags & JS_PROP_TMASK) === JS_PROP_GETSET) {
|
|
1951
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_get, d.getter, JS_PROP_C_W_E);
|
|
1952
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_set, d.setter, JS_PROP_C_W_E);
|
|
1953
|
+
}
|
|
1954
|
+
else {
|
|
1955
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_value, d.value, JS_PROP_C_W_E);
|
|
1956
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_writable, (d.flags & JS_PROP_WRITABLE) !== 0, JS_PROP_C_W_E);
|
|
1957
|
+
}
|
|
1958
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_enumerable, (d.flags & JS_PROP_ENUMERABLE) !== 0, JS_PROP_C_W_E);
|
|
1959
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_configurable, (d.flags & JS_PROP_CONFIGURABLE) !== 0, JS_PROP_C_W_E);
|
|
1960
|
+
return obj;
|
|
1961
|
+
}
|
|
1962
|
+
/* ToPropertyDescriptor: fill d.flags with the JS_PROP_HAS_* flags; -1 on exception */
|
|
1963
|
+
export function js_obj_to_desc(ctx, d, desc) {
|
|
1964
|
+
if (!JS_IsObject(desc)) {
|
|
1965
|
+
JS_ThrowTypeError(ctx, 'property descriptor must be an object');
|
|
1966
|
+
return -1;
|
|
1967
|
+
}
|
|
1968
|
+
let flags = 0;
|
|
1969
|
+
let val = undefined, getter = undefined, setter = undefined;
|
|
1970
|
+
const get_field = (atom) => {
|
|
1971
|
+
const present = JS_HasProperty(ctx, desc, atom);
|
|
1972
|
+
if (present <= 0)
|
|
1973
|
+
return [present, undefined];
|
|
1974
|
+
const v = JS_GetProperty(ctx, desc, atom);
|
|
1975
|
+
if (JS_IsException(v))
|
|
1976
|
+
return [-1, undefined];
|
|
1977
|
+
return [1, v];
|
|
1978
|
+
};
|
|
1979
|
+
let r;
|
|
1980
|
+
r = get_field(JS_ATOM_configurable);
|
|
1981
|
+
if (r[0] < 0)
|
|
1982
|
+
return -1;
|
|
1983
|
+
if (r[0]) {
|
|
1984
|
+
flags |= JS_PROP_HAS_CONFIGURABLE;
|
|
1985
|
+
if (JS_ToBoolFree(ctx, r[1]))
|
|
1986
|
+
flags |= JS_PROP_CONFIGURABLE;
|
|
1987
|
+
}
|
|
1988
|
+
r = get_field(JS_ATOM_enumerable);
|
|
1989
|
+
if (r[0] < 0)
|
|
1990
|
+
return -1;
|
|
1991
|
+
if (r[0]) {
|
|
1992
|
+
flags |= JS_PROP_HAS_ENUMERABLE;
|
|
1993
|
+
if (JS_ToBoolFree(ctx, r[1]))
|
|
1994
|
+
flags |= JS_PROP_ENUMERABLE;
|
|
1995
|
+
}
|
|
1996
|
+
r = get_field(JS_ATOM_value);
|
|
1997
|
+
if (r[0] < 0)
|
|
1998
|
+
return -1;
|
|
1999
|
+
if (r[0]) {
|
|
2000
|
+
flags |= JS_PROP_HAS_VALUE;
|
|
2001
|
+
val = r[1];
|
|
2002
|
+
}
|
|
2003
|
+
r = get_field(JS_ATOM_writable);
|
|
2004
|
+
if (r[0] < 0)
|
|
2005
|
+
return -1;
|
|
2006
|
+
if (r[0]) {
|
|
2007
|
+
flags |= JS_PROP_HAS_WRITABLE;
|
|
2008
|
+
if (JS_ToBoolFree(ctx, r[1]))
|
|
2009
|
+
flags |= JS_PROP_WRITABLE;
|
|
2010
|
+
}
|
|
2011
|
+
r = get_field(JS_ATOM_get);
|
|
2012
|
+
if (r[0] < 0)
|
|
2013
|
+
return -1;
|
|
2014
|
+
if (r[0]) {
|
|
2015
|
+
flags |= JS_PROP_HAS_GET;
|
|
2016
|
+
if (!(JS_IsUndefined(r[1]) || JS_IsFunction(ctx, r[1]))) {
|
|
2017
|
+
JS_ThrowTypeError(ctx, 'invalid getter');
|
|
2018
|
+
return -1;
|
|
2019
|
+
}
|
|
2020
|
+
getter = r[1];
|
|
2021
|
+
}
|
|
2022
|
+
r = get_field(JS_ATOM_set);
|
|
2023
|
+
if (r[0] < 0)
|
|
2024
|
+
return -1;
|
|
2025
|
+
if (r[0]) {
|
|
2026
|
+
flags |= JS_PROP_HAS_SET;
|
|
2027
|
+
if (!(JS_IsUndefined(r[1]) || JS_IsFunction(ctx, r[1]))) {
|
|
2028
|
+
JS_ThrowTypeError(ctx, 'invalid setter');
|
|
2029
|
+
return -1;
|
|
2030
|
+
}
|
|
2031
|
+
setter = r[1];
|
|
2032
|
+
}
|
|
2033
|
+
if ((flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) && (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE))) {
|
|
2034
|
+
JS_ThrowTypeError(ctx, 'cannot have setter/getter and value or writable');
|
|
2035
|
+
return -1;
|
|
2036
|
+
}
|
|
2037
|
+
d.flags = flags;
|
|
2038
|
+
d.value = val;
|
|
2039
|
+
d.getter = getter;
|
|
2040
|
+
d.setter = setter;
|
|
2041
|
+
return 0;
|
|
2042
|
+
}
|
|
2043
|
+
/* 'length' property of an array-like: -1 on exception */
|
|
2044
|
+
export function js_get_length64(ctx, obj) {
|
|
2045
|
+
const len = JS_GetProperty(ctx, obj, JS_ATOM_length);
|
|
2046
|
+
if (JS_IsException(len))
|
|
2047
|
+
return -1;
|
|
2048
|
+
return JS_ToLengthFree(ctx, len);
|
|
2049
|
+
}
|
|
2050
|
+
export const js_get_length32 = js_get_length64;
|
|
2051
|
+
export function js_set_length64(ctx, obj, len) {
|
|
2052
|
+
return JS_SetProperty(ctx, obj, JS_ATOM_length, len);
|
|
2053
|
+
}
|
|
2054
|
+
/* ---------------------------------------------------------------------
|
|
2055
|
+
Global variables
|
|
2056
|
+
--------------------------------------------------------------------- */
|
|
2057
|
+
export const DEFINE_GLOBAL_LEX_VAR = 1 << 7;
|
|
2058
|
+
export const DEFINE_GLOBAL_FUNC_VAR = 1 << 6;
|
|
2059
|
+
function js_global_own_desc(ctx, key) {
|
|
2060
|
+
try {
|
|
2061
|
+
return Reflect.getOwnPropertyDescriptor(ctx.global_obj, key);
|
|
2062
|
+
}
|
|
2063
|
+
catch (e) {
|
|
2064
|
+
js_host_exception_to_guest(ctx, e);
|
|
2065
|
+
return null;
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
export function JS_CheckDefineGlobalVar(ctx, prop, flags) {
|
|
2069
|
+
const key = JS_AtomToKey(ctx, prop);
|
|
2070
|
+
const d = js_global_own_desc(ctx, key);
|
|
2071
|
+
if (d === null)
|
|
2072
|
+
return -1;
|
|
2073
|
+
if (flags & DEFINE_GLOBAL_LEX_VAR) {
|
|
2074
|
+
if (d && !d.configurable) {
|
|
2075
|
+
JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
|
|
2076
|
+
return -1;
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
else {
|
|
2080
|
+
if (!d && !Reflect.isExtensible(ctx.global_obj)) {
|
|
2081
|
+
JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'", prop);
|
|
2082
|
+
return -1;
|
|
2083
|
+
}
|
|
2084
|
+
if (flags & DEFINE_GLOBAL_FUNC_VAR) {
|
|
2085
|
+
if (d && !d.configurable &&
|
|
2086
|
+
(('get' in d || 'set' in d) || !(d.writable && d.enumerable))) {
|
|
2087
|
+
JS_ThrowTypeErrorAtom(ctx, "cannot define variable '%s'", prop);
|
|
2088
|
+
return -1;
|
|
2089
|
+
}
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
/* check if there already is a lexical declaration */
|
|
2093
|
+
if (key in ctx.global_var_obj) {
|
|
2094
|
+
JS_ThrowSyntaxErrorAtom(ctx, "redeclaration of '%s'", prop);
|
|
2095
|
+
return -1;
|
|
2096
|
+
}
|
|
2097
|
+
return 0;
|
|
2098
|
+
}
|
|
2099
|
+
/* def_flags is (0, DEFINE_GLOBAL_LEX_VAR) | JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE */
|
|
2100
|
+
export function JS_DefineGlobalVar(ctx, prop, def_flags) {
|
|
2101
|
+
const key = JS_AtomToKey(ctx, prop);
|
|
2102
|
+
if (def_flags & DEFINE_GLOBAL_LEX_VAR) {
|
|
2103
|
+
const gvo = ctx.global_var_obj;
|
|
2104
|
+
if (key in gvo)
|
|
2105
|
+
return 0;
|
|
2106
|
+
Reflect.defineProperty(gvo, key, {
|
|
2107
|
+
value: JS_UNINITIALIZED, writable: (def_flags & JS_PROP_WRITABLE) !== 0,
|
|
2108
|
+
enumerable: true, configurable: true,
|
|
2109
|
+
});
|
|
2110
|
+
return 0;
|
|
2111
|
+
}
|
|
2112
|
+
const d = js_global_own_desc(ctx, key);
|
|
2113
|
+
if (d === null)
|
|
2114
|
+
return -1;
|
|
2115
|
+
if (d)
|
|
2116
|
+
return 0;
|
|
2117
|
+
if (!Reflect.isExtensible(ctx.global_obj))
|
|
2118
|
+
return 0;
|
|
2119
|
+
try {
|
|
2120
|
+
Reflect.defineProperty(ctx.global_obj, key, {
|
|
2121
|
+
value: undefined, writable: true, enumerable: true,
|
|
2122
|
+
configurable: (def_flags & JS_PROP_CONFIGURABLE) !== 0,
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
catch (e) {
|
|
2126
|
+
js_host_exception_to_guest(ctx, e);
|
|
2127
|
+
return -1;
|
|
2128
|
+
}
|
|
2129
|
+
return 0;
|
|
2130
|
+
}
|
|
2131
|
+
/* 'def_flags' is 0 or JS_PROP_CONFIGURABLE. */
|
|
2132
|
+
export function JS_DefineGlobalFunction(ctx, prop, func, def_flags) {
|
|
2133
|
+
const d = js_global_own_desc(ctx, JS_AtomToKey(ctx, prop));
|
|
2134
|
+
if (d === null)
|
|
2135
|
+
return -1;
|
|
2136
|
+
let flags = JS_PROP_HAS_VALUE | JS_PROP_THROW;
|
|
2137
|
+
if (!d || d.configurable) {
|
|
2138
|
+
flags |= JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | def_flags | JS_PROP_HAS_CONFIGURABLE | JS_PROP_HAS_WRITABLE | JS_PROP_HAS_ENUMERABLE;
|
|
2139
|
+
}
|
|
2140
|
+
if (JS_DefineProperty(ctx, ctx.global_obj, prop, func, undefined, undefined, flags) < 0)
|
|
2141
|
+
return -1;
|
|
2142
|
+
return 0;
|
|
2143
|
+
}
|
|
2144
|
+
export function JS_GetGlobalVar(ctx, prop, throw_ref_error) {
|
|
2145
|
+
const key = JS_AtomToKey(ctx, prop);
|
|
2146
|
+
const gvo = ctx.global_var_obj;
|
|
2147
|
+
if (key in gvo) {
|
|
2148
|
+
const v = gvo[key];
|
|
2149
|
+
if (v === JS_UNINITIALIZED)
|
|
2150
|
+
return JS_ThrowReferenceErrorUninitialized(ctx, prop);
|
|
2151
|
+
return v;
|
|
2152
|
+
}
|
|
2153
|
+
const g = ctx.global_obj;
|
|
2154
|
+
try {
|
|
2155
|
+
if (!Reflect.has(g, key)) {
|
|
2156
|
+
if (throw_ref_error)
|
|
2157
|
+
return JS_ThrowReferenceErrorNotDefined(ctx, prop);
|
|
2158
|
+
return undefined;
|
|
2159
|
+
}
|
|
2160
|
+
return g[key];
|
|
2161
|
+
}
|
|
2162
|
+
catch (e) {
|
|
2163
|
+
return js_host_exception_to_guest(ctx, e);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
/* construct a reference to a global variable: returns [obj, prop] or null on exception */
|
|
2167
|
+
export function JS_GetGlobalVarRef(ctx, prop) {
|
|
2168
|
+
const key = JS_AtomToKey(ctx, prop);
|
|
2169
|
+
const gvo = ctx.global_var_obj;
|
|
2170
|
+
let obj;
|
|
2171
|
+
if (key in gvo) {
|
|
2172
|
+
const d = Reflect.getOwnPropertyDescriptor(gvo, key);
|
|
2173
|
+
if (d.value === JS_UNINITIALIZED) {
|
|
2174
|
+
JS_ThrowReferenceErrorUninitialized(ctx, prop);
|
|
2175
|
+
return null;
|
|
2176
|
+
}
|
|
2177
|
+
if (!d.writable) {
|
|
2178
|
+
JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
|
|
2179
|
+
return null;
|
|
2180
|
+
}
|
|
2181
|
+
obj = gvo;
|
|
2182
|
+
}
|
|
2183
|
+
else {
|
|
2184
|
+
const ret = JS_HasProperty(ctx, ctx.global_obj, prop);
|
|
2185
|
+
if (ret < 0)
|
|
2186
|
+
return null;
|
|
2187
|
+
obj = ret ? ctx.global_obj : undefined;
|
|
2188
|
+
}
|
|
2189
|
+
return [obj, JS_AtomToValue(ctx, prop)];
|
|
2190
|
+
}
|
|
2191
|
+
/* use for strict variable access: test if the variable exists */
|
|
2192
|
+
export function JS_CheckGlobalVar(ctx, prop) {
|
|
2193
|
+
if (JS_AtomToKey(ctx, prop) in ctx.global_var_obj)
|
|
2194
|
+
return 1;
|
|
2195
|
+
return JS_HasProperty(ctx, ctx.global_obj, prop);
|
|
2196
|
+
}
|
|
2197
|
+
/* flag = 0: normal variable write
|
|
2198
|
+
flag = 1: initialize lexical variable
|
|
2199
|
+
flag = 2: normal variable write, strict check was done before */
|
|
2200
|
+
export function JS_SetGlobalVar(ctx, prop, val, flag) {
|
|
2201
|
+
const key = JS_AtomToKey(ctx, prop);
|
|
2202
|
+
const gvo = ctx.global_var_obj;
|
|
2203
|
+
if (key in gvo) {
|
|
2204
|
+
if (flag !== 1) {
|
|
2205
|
+
const d = Reflect.getOwnPropertyDescriptor(gvo, key);
|
|
2206
|
+
if (d.value === JS_UNINITIALIZED) {
|
|
2207
|
+
JS_ThrowReferenceErrorUninitialized(ctx, prop);
|
|
2208
|
+
return -1;
|
|
2209
|
+
}
|
|
2210
|
+
if (!d.writable)
|
|
2211
|
+
return JS_ThrowTypeErrorReadOnly(ctx, JS_PROP_THROW, prop);
|
|
2212
|
+
}
|
|
2213
|
+
Reflect.defineProperty(gvo, key, { value: val });
|
|
2214
|
+
return 0;
|
|
2215
|
+
}
|
|
2216
|
+
let flags = JS_PROP_THROW_STRICT;
|
|
2217
|
+
if (is_strict_mode(ctx))
|
|
2218
|
+
flags |= JS_PROP_NO_ADD;
|
|
2219
|
+
if (flag === 2 || (flags & JS_PROP_NO_ADD)) {
|
|
2220
|
+
/* strict mode: the variable must exist */
|
|
2221
|
+
const ret = JS_HasProperty(ctx, ctx.global_obj, prop);
|
|
2222
|
+
if (ret < 0)
|
|
2223
|
+
return -1;
|
|
2224
|
+
if (!ret) {
|
|
2225
|
+
if (flag !== 2) {
|
|
2226
|
+
JS_ThrowReferenceErrorNotDefined(ctx, prop);
|
|
2227
|
+
return -1;
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
return JS_SetPropertyInternal(ctx, ctx.global_obj, prop, val, ctx.global_obj, flags);
|
|
2232
|
+
}
|
|
2233
|
+
/* ---------------------------------------------------------------------
|
|
2234
|
+
Conversions
|
|
2235
|
+
--------------------------------------------------------------------- */
|
|
2236
|
+
export const HINT_STRING = 0;
|
|
2237
|
+
export const HINT_NUMBER = 1;
|
|
2238
|
+
export const HINT_NONE = 2;
|
|
2239
|
+
export const HINT_FORCE_ORDINARY = 1 << 4; /* don't try Symbol.toPrimitive */
|
|
2240
|
+
export function JS_ToPrimitiveFree(ctx, val, hint) {
|
|
2241
|
+
if (!JS_IsObject(val))
|
|
2242
|
+
return val;
|
|
2243
|
+
if (!(hint & HINT_FORCE_ORDINARY)) {
|
|
2244
|
+
const method = JS_GetProperty(ctx, val, JS_ATOM_Symbol_toPrimitive);
|
|
2245
|
+
if (JS_IsException(method))
|
|
2246
|
+
return JS_EXCEPTION;
|
|
2247
|
+
if (!(method === undefined || method === null)) {
|
|
2248
|
+
let atom;
|
|
2249
|
+
switch (hint) {
|
|
2250
|
+
case HINT_STRING:
|
|
2251
|
+
atom = JS_ATOM_string;
|
|
2252
|
+
break;
|
|
2253
|
+
case HINT_NUMBER:
|
|
2254
|
+
atom = JS_ATOM_number;
|
|
2255
|
+
break;
|
|
2256
|
+
default:
|
|
2257
|
+
atom = JS_ATOM_default;
|
|
2258
|
+
break;
|
|
2259
|
+
}
|
|
2260
|
+
const arg = JS_AtomToString(ctx, atom);
|
|
2261
|
+
const ret = JS_CallFree(ctx, method, val, [arg]);
|
|
2262
|
+
if (JS_IsException(ret))
|
|
2263
|
+
return ret;
|
|
2264
|
+
if (JS_IsObject(ret))
|
|
2265
|
+
return JS_ThrowTypeError(ctx, 'toPrimitive');
|
|
2266
|
+
return ret;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
hint &= ~HINT_FORCE_ORDINARY;
|
|
2270
|
+
if (hint !== HINT_STRING)
|
|
2271
|
+
hint = HINT_NUMBER;
|
|
2272
|
+
for (let i = 0; i < 2; i++) {
|
|
2273
|
+
const name = ((i ^ hint) === 0) ? JS_ATOM_toString : JS_ATOM_valueOf;
|
|
2274
|
+
const method = JS_GetProperty(ctx, val, name);
|
|
2275
|
+
if (JS_IsException(method))
|
|
2276
|
+
return JS_EXCEPTION;
|
|
2277
|
+
if (JS_IsFunction(ctx, method)) {
|
|
2278
|
+
const ret = JS_CallFree(ctx, method, val, []);
|
|
2279
|
+
if (JS_IsException(ret))
|
|
2280
|
+
return ret;
|
|
2281
|
+
if (!JS_IsObject(ret))
|
|
2282
|
+
return ret;
|
|
2283
|
+
}
|
|
2284
|
+
}
|
|
2285
|
+
return JS_ThrowTypeError(ctx, 'toPrimitive');
|
|
2286
|
+
}
|
|
2287
|
+
const JS_ATOM_default = 22; /* 'default' keyword atom */
|
|
2288
|
+
export function JS_ToPrimitive(ctx, val, hint) {
|
|
2289
|
+
return JS_ToPrimitiveFree(ctx, val, hint);
|
|
2290
|
+
}
|
|
2291
|
+
export function JS_ToBoolFree(ctx, val) {
|
|
2292
|
+
switch (typeof val) {
|
|
2293
|
+
case 'boolean': return val;
|
|
2294
|
+
case 'number': return !(val === 0 || Number.isNaN(val));
|
|
2295
|
+
case 'string': return val.length > 0;
|
|
2296
|
+
case 'bigint': return val !== 0n;
|
|
2297
|
+
case 'undefined': return false;
|
|
2298
|
+
case 'object':
|
|
2299
|
+
if (val === null)
|
|
2300
|
+
return false;
|
|
2301
|
+
if (JS_IsObject(val))
|
|
2302
|
+
return true;
|
|
2303
|
+
return true;
|
|
2304
|
+
}
|
|
2305
|
+
return true;
|
|
2306
|
+
}
|
|
2307
|
+
export const JS_ToBool = JS_ToBoolFree;
|
|
2308
|
+
/* StringToNumber */
|
|
2309
|
+
export function js_atof(ctx, str) {
|
|
2310
|
+
return Number(str);
|
|
2311
|
+
}
|
|
2312
|
+
/* ToNumber: returns JS_EXCEPTION on error */
|
|
2313
|
+
/* ToNumber: returns JS_EXCEPTION on error */
|
|
2314
|
+
export function JS_ToNumberFree(ctx, val) {
|
|
2315
|
+
switch (typeof val) {
|
|
2316
|
+
case 'number': return val;
|
|
2317
|
+
case 'boolean': return val ? 1 : 0;
|
|
2318
|
+
case 'undefined': return NaN;
|
|
2319
|
+
case 'string': return js_atof(ctx, val);
|
|
2320
|
+
case 'bigint': return JS_ThrowTypeError(ctx, 'cannot convert bigint to number');
|
|
2321
|
+
case 'symbol': return JS_ThrowTypeError(ctx, 'cannot convert symbol to number');
|
|
2322
|
+
case 'object':
|
|
2323
|
+
case 'function':
|
|
2324
|
+
if (val === null)
|
|
2325
|
+
return 0;
|
|
2326
|
+
if (JS_IsObject(val)) {
|
|
2327
|
+
const prim = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
|
|
2328
|
+
if (JS_IsException(prim))
|
|
2329
|
+
return prim;
|
|
2330
|
+
return JS_ToNumberFree(ctx, prim);
|
|
2331
|
+
}
|
|
2332
|
+
break;
|
|
2333
|
+
}
|
|
2334
|
+
return JS_ThrowTypeError(ctx, 'cannot convert to number');
|
|
2335
|
+
}
|
|
2336
|
+
export const JS_ToNumber = JS_ToNumberFree;
|
|
2337
|
+
/* ToNumeric: number or bigint */
|
|
2338
|
+
export function JS_ToNumericFree(ctx, val) {
|
|
2339
|
+
if (typeof val === 'bigint')
|
|
2340
|
+
return val;
|
|
2341
|
+
if (JS_IsObject(val)) {
|
|
2342
|
+
const prim = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
|
|
2343
|
+
if (JS_IsException(prim))
|
|
2344
|
+
return prim;
|
|
2345
|
+
if (typeof prim === 'bigint')
|
|
2346
|
+
return prim;
|
|
2347
|
+
return JS_ToNumberFree(ctx, prim);
|
|
2348
|
+
}
|
|
2349
|
+
return JS_ToNumberFree(ctx, val);
|
|
2350
|
+
}
|
|
2351
|
+
export const JS_ToNumeric = JS_ToNumericFree;
|
|
2352
|
+
/* return a number or JS_EXCEPTION */
|
|
2353
|
+
export function JS_ToFloat64(ctx, val) {
|
|
2354
|
+
if (typeof val === 'number')
|
|
2355
|
+
return val;
|
|
2356
|
+
const r = JS_ToNumberFree(ctx, val);
|
|
2357
|
+
if (JS_IsException(r))
|
|
2358
|
+
return r;
|
|
2359
|
+
return r;
|
|
2360
|
+
}
|
|
2361
|
+
/* return the int32 value or throws; on exception returns JS_EXCEPTION */
|
|
2362
|
+
export function JS_ToInt32Free(ctx, val) {
|
|
2363
|
+
if (typeof val === 'number')
|
|
2364
|
+
return val | 0;
|
|
2365
|
+
const r = JS_ToNumberFree(ctx, val);
|
|
2366
|
+
if (JS_IsException(r))
|
|
2367
|
+
return r;
|
|
2368
|
+
return r | 0;
|
|
2369
|
+
}
|
|
2370
|
+
export const JS_ToInt32 = JS_ToInt32Free;
|
|
2371
|
+
export function JS_ToUint32Free(ctx, val) {
|
|
2372
|
+
if (typeof val === 'number')
|
|
2373
|
+
return val >>> 0;
|
|
2374
|
+
const r = JS_ToNumberFree(ctx, val);
|
|
2375
|
+
if (JS_IsException(r))
|
|
2376
|
+
return r;
|
|
2377
|
+
return r >>> 0;
|
|
2378
|
+
}
|
|
2379
|
+
export const JS_ToUint32 = JS_ToUint32Free;
|
|
2380
|
+
/* ToInt32 with clamping (used by typed arrays / string functions) */
|
|
2381
|
+
export function JS_ToInt32Clamp(ctx, val, min_val, max_val, neg_offset) {
|
|
2382
|
+
const r = JS_ToFloat64(ctx, val);
|
|
2383
|
+
if (JS_IsException(r))
|
|
2384
|
+
return r;
|
|
2385
|
+
let d = r;
|
|
2386
|
+
if (Number.isNaN(d))
|
|
2387
|
+
return min_val < 0 ? 0 : min_val;
|
|
2388
|
+
d = Math.trunc(d);
|
|
2389
|
+
if (d < 0) {
|
|
2390
|
+
d += neg_offset;
|
|
2391
|
+
if (d < min_val)
|
|
2392
|
+
d = min_val;
|
|
2393
|
+
}
|
|
2394
|
+
else if (d > max_val)
|
|
2395
|
+
d = max_val;
|
|
2396
|
+
return d;
|
|
2397
|
+
}
|
|
2398
|
+
/* ToInt32 with saturation */
|
|
2399
|
+
export function JS_ToInt32Sat(ctx, val) {
|
|
2400
|
+
const r = JS_ToFloat64(ctx, val);
|
|
2401
|
+
if (JS_IsException(r))
|
|
2402
|
+
return r;
|
|
2403
|
+
const d = r;
|
|
2404
|
+
if (Number.isNaN(d))
|
|
2405
|
+
return 0;
|
|
2406
|
+
if (d < -2147483648)
|
|
2407
|
+
return -2147483648;
|
|
2408
|
+
if (d > 2147483647)
|
|
2409
|
+
return 2147483647;
|
|
2410
|
+
return Math.trunc(d);
|
|
2411
|
+
}
|
|
2412
|
+
export function JS_ToInt64Sat(ctx, val) {
|
|
2413
|
+
const r = JS_ToFloat64(ctx, val);
|
|
2414
|
+
if (JS_IsException(r))
|
|
2415
|
+
return r;
|
|
2416
|
+
const d = r;
|
|
2417
|
+
if (Number.isNaN(d))
|
|
2418
|
+
return 0;
|
|
2419
|
+
if (d < -9223372036854775808)
|
|
2420
|
+
return -9223372036854775808;
|
|
2421
|
+
if (d >= 9223372036854775807)
|
|
2422
|
+
return 9223372036854775807;
|
|
2423
|
+
return Math.trunc(d);
|
|
2424
|
+
}
|
|
2425
|
+
export function JS_ToInt64Clamp(ctx, val, min_val, max_val, neg_offset) {
|
|
2426
|
+
const r = JS_ToFloat64(ctx, val);
|
|
2427
|
+
if (JS_IsException(r))
|
|
2428
|
+
return r;
|
|
2429
|
+
let d = r;
|
|
2430
|
+
if (Number.isNaN(d))
|
|
2431
|
+
return min_val < 0 ? 0 : min_val;
|
|
2432
|
+
d = Math.trunc(d);
|
|
2433
|
+
if (d < 0) {
|
|
2434
|
+
d += neg_offset;
|
|
2435
|
+
if (d < min_val)
|
|
2436
|
+
d = min_val;
|
|
2437
|
+
}
|
|
2438
|
+
else if (d > max_val)
|
|
2439
|
+
d = max_val;
|
|
2440
|
+
return d;
|
|
2441
|
+
}
|
|
2442
|
+
/* ToInteger (truncation); returns JS_EXCEPTION on error */
|
|
2443
|
+
export function JS_ToInt64Free(ctx, val) {
|
|
2444
|
+
const r = JS_ToFloat64(ctx, val);
|
|
2445
|
+
if (JS_IsException(r))
|
|
2446
|
+
return r;
|
|
2447
|
+
const d = r;
|
|
2448
|
+
if (Number.isNaN(d))
|
|
2449
|
+
return 0;
|
|
2450
|
+
if (!Number.isFinite(d))
|
|
2451
|
+
return d > 0 ? 9223372036854775807 : -9223372036854775808;
|
|
2452
|
+
return Math.trunc(d);
|
|
2453
|
+
}
|
|
2454
|
+
export const JS_ToInt64 = JS_ToInt64Free;
|
|
2455
|
+
/* ToIndex: returns -1 and throws on error */
|
|
2456
|
+
export function JS_ToIndex(ctx, val) {
|
|
2457
|
+
if (val === undefined)
|
|
2458
|
+
return 0;
|
|
2459
|
+
const r = JS_ToFloat64(ctx, val);
|
|
2460
|
+
if (JS_IsException(r))
|
|
2461
|
+
return -1;
|
|
2462
|
+
let d = r;
|
|
2463
|
+
if (Number.isNaN(d))
|
|
2464
|
+
d = 0;
|
|
2465
|
+
d = Math.trunc(d);
|
|
2466
|
+
if (d < 0 || d > 9007199254740991) {
|
|
2467
|
+
JS_ThrowRangeError(ctx, 'invalid array index');
|
|
2468
|
+
return -1;
|
|
2469
|
+
}
|
|
2470
|
+
return d === 0 ? 0 : d;
|
|
2471
|
+
}
|
|
2472
|
+
/* ToLength: returns -1 on exception */
|
|
2473
|
+
export function JS_ToLengthFree(ctx, val) {
|
|
2474
|
+
const r = JS_ToFloat64(ctx, val);
|
|
2475
|
+
if (JS_IsException(r))
|
|
2476
|
+
return -1;
|
|
2477
|
+
let d = r;
|
|
2478
|
+
if (Number.isNaN(d) || d <= 0)
|
|
2479
|
+
return 0;
|
|
2480
|
+
d = Math.trunc(d);
|
|
2481
|
+
if (d > 9007199254740991)
|
|
2482
|
+
d = 9007199254740991;
|
|
2483
|
+
return d;
|
|
2484
|
+
}
|
|
2485
|
+
/* ToUint32 with RangeError if not a valid array length (ArraySetLength
|
|
2486
|
+
semantics: ToUint32 and ToNumber are both evaluated). Return -1 on exception */
|
|
2487
|
+
export function JS_ToArrayLengthFree(ctx, val, is_array_ctor) {
|
|
2488
|
+
let d;
|
|
2489
|
+
if (typeof val === 'number') {
|
|
2490
|
+
d = val;
|
|
2491
|
+
}
|
|
2492
|
+
else {
|
|
2493
|
+
const r = JS_ToNumberFree(ctx, val);
|
|
2494
|
+
if (JS_IsException(r))
|
|
2495
|
+
return -1;
|
|
2496
|
+
d = r;
|
|
2497
|
+
if (!is_array_ctor) {
|
|
2498
|
+
/* the spec evaluates ToNumber a second time */
|
|
2499
|
+
const r2 = JS_ToNumberFree(ctx, val);
|
|
2500
|
+
if (JS_IsException(r2))
|
|
2501
|
+
return -1;
|
|
2502
|
+
if (r2 !== d && !(Number.isNaN(r2) && Number.isNaN(d))) {
|
|
2503
|
+
JS_ThrowRangeError(ctx, 'invalid array length');
|
|
2504
|
+
return -1;
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
const len = d >>> 0;
|
|
2509
|
+
if (len !== d) {
|
|
2510
|
+
JS_ThrowRangeError(ctx, 'invalid array length');
|
|
2511
|
+
return -1;
|
|
2512
|
+
}
|
|
2513
|
+
return len;
|
|
2514
|
+
}
|
|
2515
|
+
export function JS_ToUint8ClampFree(ctx, val) {
|
|
2516
|
+
const r = JS_ToFloat64(ctx, val);
|
|
2517
|
+
if (JS_IsException(r))
|
|
2518
|
+
return r;
|
|
2519
|
+
const d = r;
|
|
2520
|
+
if (Number.isNaN(d) || d <= 0)
|
|
2521
|
+
return 0;
|
|
2522
|
+
if (d >= 255)
|
|
2523
|
+
return 255;
|
|
2524
|
+
/* round half to even */
|
|
2525
|
+
const f = Math.floor(d);
|
|
2526
|
+
const diff = d - f;
|
|
2527
|
+
if (diff > 0.5)
|
|
2528
|
+
return f + 1;
|
|
2529
|
+
if (diff < 0.5)
|
|
2530
|
+
return f;
|
|
2531
|
+
return (f % 2 === 0) ? f : f + 1;
|
|
2532
|
+
}
|
|
2533
|
+
/* ToBigInt */
|
|
2534
|
+
/* ToBigInt */
|
|
2535
|
+
export function JS_ToBigIntFree(ctx, val) {
|
|
2536
|
+
switch (typeof val) {
|
|
2537
|
+
case 'bigint': return val;
|
|
2538
|
+
case 'boolean': return val ? 1n : 0n;
|
|
2539
|
+
case 'string': {
|
|
2540
|
+
const r = js_string_to_bigint(val);
|
|
2541
|
+
if (r === null)
|
|
2542
|
+
return JS_ThrowSyntaxError(ctx, 'invalid bigint literal');
|
|
2543
|
+
return r;
|
|
2544
|
+
}
|
|
2545
|
+
case 'number':
|
|
2546
|
+
return JS_ThrowTypeError(ctx, 'cannot convert number to bigint');
|
|
2547
|
+
case 'undefined':
|
|
2548
|
+
return JS_ThrowTypeError(ctx, 'cannot convert undefined to bigint');
|
|
2549
|
+
case 'symbol':
|
|
2550
|
+
return JS_ThrowTypeError(ctx, 'cannot convert symbol to bigint');
|
|
2551
|
+
case 'object':
|
|
2552
|
+
case 'function':
|
|
2553
|
+
if (val === null)
|
|
2554
|
+
return JS_ThrowTypeError(ctx, 'cannot convert null to bigint');
|
|
2555
|
+
if (JS_IsObject(val)) {
|
|
2556
|
+
const prim = JS_ToPrimitiveFree(ctx, val, HINT_NUMBER);
|
|
2557
|
+
if (JS_IsException(prim))
|
|
2558
|
+
return prim;
|
|
2559
|
+
return JS_ToBigIntFree(ctx, prim);
|
|
2560
|
+
}
|
|
2561
|
+
break;
|
|
2562
|
+
}
|
|
2563
|
+
return JS_ThrowTypeError(ctx, 'cannot convert to bigint');
|
|
2564
|
+
}
|
|
2565
|
+
export const JS_ToBigInt = JS_ToBigIntFree;
|
|
2566
|
+
export function js_string_to_bigint(str) {
|
|
2567
|
+
const s = str.trim();
|
|
2568
|
+
if (s === '')
|
|
2569
|
+
return 0n;
|
|
2570
|
+
try {
|
|
2571
|
+
if (/^[+-]?\d+$/.test(s) || /^0[xX][0-9a-fA-F]+$/.test(s) || /^0[oO][0-7]+$/.test(s) || /^0[bB][01]+$/.test(s)) {
|
|
2572
|
+
return BigInt(s);
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
catch { /* fallthrough */ }
|
|
2576
|
+
return null;
|
|
2577
|
+
}
|
|
2578
|
+
export function JS_NewBigInt64(ctx, v) { return BigInt.asIntN(64, BigInt(v)); }
|
|
2579
|
+
export function JS_NewBigUint64(ctx, v) { return BigInt.asUintN(64, BigInt(v)); }
|
|
2580
|
+
export function JS_ToBigInt64(ctx, val) {
|
|
2581
|
+
const r = JS_ToBigIntFree(ctx, val);
|
|
2582
|
+
if (JS_IsException(r))
|
|
2583
|
+
return r;
|
|
2584
|
+
return BigInt.asIntN(64, r);
|
|
2585
|
+
}
|
|
2586
|
+
/* number to string with a radix */
|
|
2587
|
+
export function js_number_to_string(d, radix) {
|
|
2588
|
+
if (radix === 10)
|
|
2589
|
+
return String(d);
|
|
2590
|
+
return d.toString(radix);
|
|
2591
|
+
}
|
|
2592
|
+
export function js_dtoa(d) { return String(d); }
|
|
2593
|
+
/* ToString */
|
|
2594
|
+
export function JS_ToStringInternal(ctx, val, is_ToPropertyKey) {
|
|
2595
|
+
switch (typeof val) {
|
|
2596
|
+
case 'string': return val;
|
|
2597
|
+
case 'number': return js_number_to_string(val, 10);
|
|
2598
|
+
case 'boolean': return val ? 'true' : 'false';
|
|
2599
|
+
case 'undefined': return 'undefined';
|
|
2600
|
+
case 'bigint': return val.toString();
|
|
2601
|
+
case 'symbol':
|
|
2602
|
+
if (is_ToPropertyKey)
|
|
2603
|
+
return val;
|
|
2604
|
+
return JS_ThrowTypeError(ctx, 'cannot convert symbol to string');
|
|
2605
|
+
case 'object':
|
|
2606
|
+
case 'function':
|
|
2607
|
+
if (val === null)
|
|
2608
|
+
return 'null';
|
|
2609
|
+
if (JS_IsObject(val)) {
|
|
2610
|
+
const prim = JS_ToPrimitiveFree(ctx, val, HINT_STRING);
|
|
2611
|
+
if (JS_IsException(prim))
|
|
2612
|
+
return prim;
|
|
2613
|
+
return JS_ToStringInternal(ctx, prim, is_ToPropertyKey);
|
|
2614
|
+
}
|
|
2615
|
+
if (val === JS_EXCEPTION)
|
|
2616
|
+
return '[exception]';
|
|
2617
|
+
if (val === JS_UNINITIALIZED)
|
|
2618
|
+
return '[uninitialized]';
|
|
2619
|
+
return '[catch offset]';
|
|
2620
|
+
}
|
|
2621
|
+
return JS_ThrowTypeError(ctx, 'cannot convert to string');
|
|
2622
|
+
}
|
|
2623
|
+
export function JS_ToString(ctx, val) {
|
|
2624
|
+
return JS_ToStringInternal(ctx, val, false);
|
|
2625
|
+
}
|
|
2626
|
+
export const JS_ToStringFree = JS_ToString;
|
|
2627
|
+
export function JS_ToCString(ctx, val) {
|
|
2628
|
+
const r = JS_ToString(ctx, val);
|
|
2629
|
+
if (JS_IsException(r))
|
|
2630
|
+
return null;
|
|
2631
|
+
return r;
|
|
2632
|
+
}
|
|
2633
|
+
export function JS_ToPropertyKey(ctx, val) {
|
|
2634
|
+
return JS_ToStringInternal(ctx, val, true);
|
|
2635
|
+
}
|
|
2636
|
+
/* return a quoted string with JSON-like escapes */
|
|
2637
|
+
export function JS_ToQuotedString(ctx, val) {
|
|
2638
|
+
const r = JS_ToString(ctx, val);
|
|
2639
|
+
if (JS_IsException(r))
|
|
2640
|
+
return r;
|
|
2641
|
+
return js_quote_string(r);
|
|
2642
|
+
}
|
|
2643
|
+
export function js_quote_string(s) {
|
|
2644
|
+
let out = '"';
|
|
2645
|
+
for (let i = 0; i < s.length; i++) {
|
|
2646
|
+
const c = s.charCodeAt(i);
|
|
2647
|
+
switch (c) {
|
|
2648
|
+
case 0x09:
|
|
2649
|
+
out += '\\t';
|
|
2650
|
+
break;
|
|
2651
|
+
case 0x0a:
|
|
2652
|
+
out += '\\n';
|
|
2653
|
+
break;
|
|
2654
|
+
case 0x0d:
|
|
2655
|
+
out += '\\r';
|
|
2656
|
+
break;
|
|
2657
|
+
case 0x08:
|
|
2658
|
+
out += '\\b';
|
|
2659
|
+
break;
|
|
2660
|
+
case 0x0c:
|
|
2661
|
+
out += '\\f';
|
|
2662
|
+
break;
|
|
2663
|
+
case 0x5c:
|
|
2664
|
+
out += '\\\\';
|
|
2665
|
+
break;
|
|
2666
|
+
case 0x22:
|
|
2667
|
+
out += '\\"';
|
|
2668
|
+
break;
|
|
2669
|
+
default:
|
|
2670
|
+
if (c < 32 || (c >= 0xd800 && c <= 0xdfff && !is_paired_surrogate(s, i))) {
|
|
2671
|
+
out += '\\u' + c.toString(16).padStart(4, '0');
|
|
2672
|
+
}
|
|
2673
|
+
else {
|
|
2674
|
+
out += s[i];
|
|
2675
|
+
}
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
return out + '"';
|
|
2679
|
+
}
|
|
2680
|
+
function is_paired_surrogate(s, i) {
|
|
2681
|
+
const c = s.charCodeAt(i);
|
|
2682
|
+
if (c >= 0xd800 && c <= 0xdbff) {
|
|
2683
|
+
const c2 = s.charCodeAt(i + 1);
|
|
2684
|
+
return c2 >= 0xdc00 && c2 <= 0xdfff;
|
|
2685
|
+
}
|
|
2686
|
+
if (c >= 0xdc00 && c <= 0xdfff) {
|
|
2687
|
+
if (i === 0)
|
|
2688
|
+
return false;
|
|
2689
|
+
const c1 = s.charCodeAt(i - 1);
|
|
2690
|
+
return c1 >= 0xd800 && c1 <= 0xdbff;
|
|
2691
|
+
}
|
|
2692
|
+
return true;
|
|
2693
|
+
}
|
|
2694
|
+
/* string wrapper objects expose 'length' and the character indices as own
|
|
2695
|
+
properties (the string exotic object of the specification) */
|
|
2696
|
+
/* ToObject */
|
|
2697
|
+
export function JS_ToObject(ctx, val) {
|
|
2698
|
+
switch (typeof val) {
|
|
2699
|
+
case 'object':
|
|
2700
|
+
case 'function':
|
|
2701
|
+
if (JS_IsObject(val))
|
|
2702
|
+
return val;
|
|
2703
|
+
return JS_ThrowTypeError(ctx, 'cannot convert to object');
|
|
2704
|
+
case 'undefined':
|
|
2705
|
+
return JS_ThrowTypeError(ctx, 'cannot convert to object');
|
|
2706
|
+
case 'symbol': return js_new_primitive_wrapper(ctx, ctx.class_proto[7 /* JSClassID.SYMBOL */], 7 /* JSClassID.SYMBOL */, val);
|
|
2707
|
+
case 'number': return js_new_primitive_wrapper(ctx, ctx.class_proto[4 /* JSClassID.NUMBER */], 4 /* JSClassID.NUMBER */, val);
|
|
2708
|
+
case 'boolean': return js_new_primitive_wrapper(ctx, ctx.class_proto[6 /* JSClassID.BOOLEAN */], 6 /* JSClassID.BOOLEAN */, val);
|
|
2709
|
+
case 'bigint': return js_new_primitive_wrapper(ctx, ctx.class_proto[33 /* JSClassID.BIG_INT */], 33 /* JSClassID.BIG_INT */, val);
|
|
2710
|
+
case 'string': return js_new_primitive_wrapper(ctx, ctx.class_proto[5 /* JSClassID.STRING */], 5 /* JSClassID.STRING */, val);
|
|
2711
|
+
}
|
|
2712
|
+
return JS_ThrowTypeError(ctx, 'cannot convert to object');
|
|
2713
|
+
}
|
|
2714
|
+
export const JS_ToObjectFree = JS_ToObject;
|
|
2715
|
+
/* "this" value of a primitive wrapper: the primitive, JS_EXCEPTION if the
|
|
2716
|
+
object is not a wrapper of the given class */
|
|
2717
|
+
export function JS_ThisObjectData(ctx, this_val, class_id) {
|
|
2718
|
+
if (JS_IsObject(this_val)) {
|
|
2719
|
+
const m = js_meta.get(this_val);
|
|
2720
|
+
if (m && m.class_id === class_id)
|
|
2721
|
+
return m.u;
|
|
2722
|
+
return JS_EXCEPTION;
|
|
2723
|
+
}
|
|
2724
|
+
return this_val;
|
|
2725
|
+
}
|
|
2726
|
+
/* ---------------------------------------------------------------------
|
|
2727
|
+
Comparisons and operators
|
|
2728
|
+
--------------------------------------------------------------------- */
|
|
2729
|
+
export function js_same_value(ctx, op1, op2) {
|
|
2730
|
+
return Object.is(op1, op2);
|
|
2731
|
+
}
|
|
2732
|
+
export function js_same_value_zero(ctx, op1, op2) {
|
|
2733
|
+
if (typeof op1 === 'number' && typeof op2 === 'number')
|
|
2734
|
+
return op1 === op2 || (Number.isNaN(op1) && Number.isNaN(op2));
|
|
2735
|
+
return op1 === op2;
|
|
2736
|
+
}
|
|
2737
|
+
export function js_strict_eq2(ctx, op1, op2, eq_mode) {
|
|
2738
|
+
switch (eq_mode) {
|
|
2739
|
+
case 0 /* JSStrictEqMode.STRICT */: return op1 === op2; /* host semantics match (NaN !== NaN, +0 === -0) */
|
|
2740
|
+
case 1 /* JSStrictEqMode.SAME_VALUE */: return Object.is(op1, op2);
|
|
2741
|
+
case 2 /* JSStrictEqMode.SAME_VALUE_ZERO */: return js_same_value_zero(ctx, op1, op2);
|
|
2742
|
+
}
|
|
2743
|
+
}
|
|
2744
|
+
export function js_strict_eq(ctx, op1, op2) { return op1 === op2; }
|
|
2745
|
+
/* abstract equality: returns -1 on exception */
|
|
2746
|
+
export function js_loose_eq(ctx, op1, op2) {
|
|
2747
|
+
for (;;) {
|
|
2748
|
+
const o1 = JS_IsObject(op1), o2 = JS_IsObject(op2);
|
|
2749
|
+
if (o1 && o2)
|
|
2750
|
+
return op1 === op2 ? 1 : 0;
|
|
2751
|
+
if (!o1 && !o2 && typeof op1 === typeof op2)
|
|
2752
|
+
return op1 === op2 ? 1 : 0;
|
|
2753
|
+
const n1 = (op1 === undefined || op1 === null), n2 = (op2 === undefined || op2 === null);
|
|
2754
|
+
/* undefined == null */
|
|
2755
|
+
if (n1 && n2)
|
|
2756
|
+
return 1;
|
|
2757
|
+
if (n1 || n2)
|
|
2758
|
+
return 0;
|
|
2759
|
+
const t1 = typeof op1, t2 = typeof op2;
|
|
2760
|
+
if (t1 === 'number' && t2 === 'string') {
|
|
2761
|
+
op2 = js_atof(ctx, op2);
|
|
2762
|
+
continue;
|
|
2763
|
+
}
|
|
2764
|
+
if (t1 === 'string' && t2 === 'number') {
|
|
2765
|
+
op1 = js_atof(ctx, op1);
|
|
2766
|
+
continue;
|
|
2767
|
+
}
|
|
2768
|
+
if (t1 === 'bigint' && t2 === 'string') {
|
|
2769
|
+
const b = js_string_to_bigint(op2);
|
|
2770
|
+
if (b === null)
|
|
2771
|
+
return 0;
|
|
2772
|
+
return op1 === b ? 1 : 0;
|
|
2773
|
+
}
|
|
2774
|
+
if (t1 === 'string' && t2 === 'bigint') {
|
|
2775
|
+
const b = js_string_to_bigint(op1);
|
|
2776
|
+
if (b === null)
|
|
2777
|
+
return 0;
|
|
2778
|
+
return op2 === b ? 1 : 0;
|
|
2779
|
+
}
|
|
2780
|
+
if (t1 === 'boolean') {
|
|
2781
|
+
op1 = op1 ? 1 : 0;
|
|
2782
|
+
continue;
|
|
2783
|
+
}
|
|
2784
|
+
if (t2 === 'boolean') {
|
|
2785
|
+
op2 = op2 ? 1 : 0;
|
|
2786
|
+
continue;
|
|
2787
|
+
}
|
|
2788
|
+
if (o1 && !o2) {
|
|
2789
|
+
const p = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
|
|
2790
|
+
if (JS_IsException(p))
|
|
2791
|
+
return -1;
|
|
2792
|
+
op1 = p;
|
|
2793
|
+
continue;
|
|
2794
|
+
}
|
|
2795
|
+
if (o2 && !o1) {
|
|
2796
|
+
const p = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
|
|
2797
|
+
if (JS_IsException(p))
|
|
2798
|
+
return -1;
|
|
2799
|
+
op2 = p;
|
|
2800
|
+
continue;
|
|
2801
|
+
}
|
|
2802
|
+
if (t1 === 'bigint' && t2 === 'number')
|
|
2803
|
+
return bigint_num_eq(op1, op2) ? 1 : 0;
|
|
2804
|
+
if (t1 === 'number' && t2 === 'bigint')
|
|
2805
|
+
return bigint_num_eq(op2, op1) ? 1 : 0;
|
|
2806
|
+
return 0;
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
function bigint_num_eq(a, b) {
|
|
2810
|
+
if (!Number.isFinite(b) || !Number.isInteger(b))
|
|
2811
|
+
return false;
|
|
2812
|
+
return a === BigInt(b);
|
|
2813
|
+
}
|
|
2814
|
+
/* relational comparison: returns -1 on exception, else 0/1 */
|
|
2815
|
+
export function js_relational_op(ctx, op, op1, op2) {
|
|
2816
|
+
if (JS_IsObject(op1)) {
|
|
2817
|
+
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NUMBER);
|
|
2818
|
+
if (JS_IsException(op1))
|
|
2819
|
+
return -1;
|
|
2820
|
+
}
|
|
2821
|
+
if (JS_IsObject(op2)) {
|
|
2822
|
+
op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NUMBER);
|
|
2823
|
+
if (JS_IsException(op2))
|
|
2824
|
+
return -1;
|
|
2825
|
+
}
|
|
2826
|
+
let res;
|
|
2827
|
+
if (typeof op1 === 'string' && typeof op2 === 'string') {
|
|
2828
|
+
switch (op) {
|
|
2829
|
+
case 0 /* JSRelOp.LT */:
|
|
2830
|
+
res = op1 < op2;
|
|
2831
|
+
break;
|
|
2832
|
+
case 1 /* JSRelOp.LTE */:
|
|
2833
|
+
res = op1 <= op2;
|
|
2834
|
+
break;
|
|
2835
|
+
case 2 /* JSRelOp.GT */:
|
|
2836
|
+
res = op1 > op2;
|
|
2837
|
+
break;
|
|
2838
|
+
default:
|
|
2839
|
+
res = op1 >= op2;
|
|
2840
|
+
break;
|
|
2841
|
+
}
|
|
2842
|
+
return res ? 1 : 0;
|
|
2843
|
+
}
|
|
2844
|
+
if (typeof op1 === 'symbol' || typeof op2 === 'symbol') {
|
|
2845
|
+
JS_ThrowTypeError(ctx, 'cannot convert symbol to number');
|
|
2846
|
+
return -1;
|
|
2847
|
+
}
|
|
2848
|
+
let n1, n2;
|
|
2849
|
+
if (typeof op1 === 'bigint' && typeof op2 === 'string') {
|
|
2850
|
+
const b = js_string_to_bigint(op2);
|
|
2851
|
+
if (b === null)
|
|
2852
|
+
return 0;
|
|
2853
|
+
n1 = op1;
|
|
2854
|
+
n2 = b;
|
|
2855
|
+
}
|
|
2856
|
+
else if (typeof op1 === 'string' && typeof op2 === 'bigint') {
|
|
2857
|
+
const b = js_string_to_bigint(op1);
|
|
2858
|
+
if (b === null)
|
|
2859
|
+
return 0;
|
|
2860
|
+
n1 = b;
|
|
2861
|
+
n2 = op2;
|
|
2862
|
+
}
|
|
2863
|
+
else {
|
|
2864
|
+
n1 = JS_ToNumericFree(ctx, op1);
|
|
2865
|
+
if (JS_IsException(n1))
|
|
2866
|
+
return -1;
|
|
2867
|
+
n2 = JS_ToNumericFree(ctx, op2);
|
|
2868
|
+
if (JS_IsException(n2))
|
|
2869
|
+
return -1;
|
|
2870
|
+
}
|
|
2871
|
+
/* host relational ops handle number/bigint mixes correctly */
|
|
2872
|
+
const a = n1, b = n2;
|
|
2873
|
+
switch (op) {
|
|
2874
|
+
case 0 /* JSRelOp.LT */:
|
|
2875
|
+
res = a < b;
|
|
2876
|
+
break;
|
|
2877
|
+
case 1 /* JSRelOp.LTE */:
|
|
2878
|
+
res = a <= b;
|
|
2879
|
+
break;
|
|
2880
|
+
case 2 /* JSRelOp.GT */:
|
|
2881
|
+
res = a > b;
|
|
2882
|
+
break;
|
|
2883
|
+
default:
|
|
2884
|
+
res = a >= b;
|
|
2885
|
+
break;
|
|
2886
|
+
}
|
|
2887
|
+
return res ? 1 : 0;
|
|
2888
|
+
}
|
|
2889
|
+
/* return -1 if exception, else 0/1 */
|
|
2890
|
+
export function JS_OrdinaryIsInstanceOf(ctx, val, obj) {
|
|
2891
|
+
if (!JS_IsFunction(ctx, obj))
|
|
2892
|
+
return 0;
|
|
2893
|
+
const m = js_get_meta(obj);
|
|
2894
|
+
if (m && m.class_id === 14 /* JSClassID.BOUND_FUNCTION */) {
|
|
2895
|
+
return JS_IsInstanceOf(ctx, val, m.u.func_obj);
|
|
2896
|
+
}
|
|
2897
|
+
if (!JS_IsObject(val))
|
|
2898
|
+
return 0;
|
|
2899
|
+
const proto = JS_GetProperty(ctx, obj, JS_ATOM_prototype);
|
|
2900
|
+
if (JS_IsException(proto))
|
|
2901
|
+
return -1;
|
|
2902
|
+
if (!JS_IsObject(proto)) {
|
|
2903
|
+
JS_ThrowTypeError(ctx, 'operand \'prototype\' property is not an object');
|
|
2904
|
+
return -1;
|
|
2905
|
+
}
|
|
2906
|
+
let obj1 = val;
|
|
2907
|
+
let depth = 0;
|
|
2908
|
+
for (;;) {
|
|
2909
|
+
const proto1 = JS_GetPrototype(ctx, obj1);
|
|
2910
|
+
if (JS_IsException(proto1))
|
|
2911
|
+
return -1;
|
|
2912
|
+
if (proto1 === null || proto1 === undefined)
|
|
2913
|
+
return 0;
|
|
2914
|
+
if (proto1 === proto)
|
|
2915
|
+
return 1;
|
|
2916
|
+
obj1 = proto1;
|
|
2917
|
+
if (++depth > 100000) {
|
|
2918
|
+
JS_ThrowInternalError(ctx, 'prototype chain too deep');
|
|
2919
|
+
return -1;
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
export function JS_IsInstanceOf(ctx, val, obj) {
|
|
2924
|
+
if (!JS_IsObject(obj)) {
|
|
2925
|
+
JS_ThrowTypeError(ctx, 'invalid \'instanceof\' right operand');
|
|
2926
|
+
return -1;
|
|
2927
|
+
}
|
|
2928
|
+
const method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_hasInstance);
|
|
2929
|
+
if (JS_IsException(method))
|
|
2930
|
+
return -1;
|
|
2931
|
+
if (!(method === undefined || method === null)) {
|
|
2932
|
+
const ret = JS_CallFree(ctx, method, obj, [val]);
|
|
2933
|
+
if (JS_IsException(ret))
|
|
2934
|
+
return -1;
|
|
2935
|
+
return JS_ToBoolFree(ctx, ret) ? 1 : 0;
|
|
2936
|
+
}
|
|
2937
|
+
if (!JS_IsFunction(ctx, obj)) {
|
|
2938
|
+
JS_ThrowTypeError(ctx, 'invalid \'instanceof\' right operand');
|
|
2939
|
+
return -1;
|
|
2940
|
+
}
|
|
2941
|
+
return JS_OrdinaryIsInstanceOf(ctx, val, obj);
|
|
2942
|
+
}
|
|
2943
|
+
export function js_operator_typeof(ctx, op1) {
|
|
2944
|
+
switch (typeof op1) {
|
|
2945
|
+
case 'bigint': return JS_ATOM_bigint;
|
|
2946
|
+
case 'number': return JS_ATOM_number;
|
|
2947
|
+
case 'undefined': return JS_ATOM_undefined;
|
|
2948
|
+
case 'boolean': return JS_ATOM_boolean;
|
|
2949
|
+
case 'string': return JS_ATOM_string;
|
|
2950
|
+
case 'symbol': return JS_ATOM_symbol;
|
|
2951
|
+
case 'function': return JS_ATOM_function;
|
|
2952
|
+
case 'object':
|
|
2953
|
+
if (op1 instanceof JSSpecial)
|
|
2954
|
+
return JS_ATOM_undefined;
|
|
2955
|
+
return JS_ATOM_object;
|
|
2956
|
+
}
|
|
2957
|
+
return JS_ATOM_undefined;
|
|
2958
|
+
}
|
|
2959
|
+
/* 'in' operator: -1 on exception */
|
|
2960
|
+
export function js_operator_in(ctx, op1, op2) {
|
|
2961
|
+
if (!JS_IsObject(op2)) {
|
|
2962
|
+
JS_ThrowTypeError(ctx, 'invalid \'in\' operand');
|
|
2963
|
+
return -1;
|
|
2964
|
+
}
|
|
2965
|
+
const atom = JS_ValueToAtom(ctx, op1);
|
|
2966
|
+
if (atom === JS_ATOM_NULL)
|
|
2967
|
+
return -1;
|
|
2968
|
+
return JS_HasProperty(ctx, op2, atom);
|
|
2969
|
+
}
|
|
2970
|
+
export function js_binary_arith_slow(ctx, op, op1, op2) {
|
|
2971
|
+
const n1 = JS_ToNumericFree(ctx, op1);
|
|
2972
|
+
if (JS_IsException(n1))
|
|
2973
|
+
return n1;
|
|
2974
|
+
const n2 = JS_ToNumericFree(ctx, op2);
|
|
2975
|
+
if (JS_IsException(n2))
|
|
2976
|
+
return n2;
|
|
2977
|
+
const b1 = typeof n1 === 'bigint', b2 = typeof n2 === 'bigint';
|
|
2978
|
+
if (b1 !== b2)
|
|
2979
|
+
return JS_ThrowTypeError(ctx, 'both operands must be bigint');
|
|
2980
|
+
if (b1) {
|
|
2981
|
+
const a = n1, b = n2;
|
|
2982
|
+
try {
|
|
2983
|
+
switch (op) {
|
|
2984
|
+
case 0 /* JSArithOp.ADD */: return a + b;
|
|
2985
|
+
case 1 /* JSArithOp.SUB */: return a - b;
|
|
2986
|
+
case 2 /* JSArithOp.MUL */: return a * b;
|
|
2987
|
+
case 3 /* JSArithOp.DIV */:
|
|
2988
|
+
if (b === 0n)
|
|
2989
|
+
return JS_ThrowRangeError(ctx, 'division by zero');
|
|
2990
|
+
return a / b;
|
|
2991
|
+
case 4 /* JSArithOp.MOD */:
|
|
2992
|
+
if (b === 0n)
|
|
2993
|
+
return JS_ThrowRangeError(ctx, 'division by zero');
|
|
2994
|
+
return a % b;
|
|
2995
|
+
case 5 /* JSArithOp.POW */:
|
|
2996
|
+
if (b < 0n)
|
|
2997
|
+
return JS_ThrowRangeError(ctx, 'invalid bigint exponent');
|
|
2998
|
+
return a ** b;
|
|
2999
|
+
case 6 /* JSArithOp.SHL */: return a << b;
|
|
3000
|
+
case 7 /* JSArithOp.SAR */: return a >> b;
|
|
3001
|
+
case 8 /* JSArithOp.SHR */: return JS_ThrowTypeError(ctx, 'BigInts have no unsigned right shift, use >> instead');
|
|
3002
|
+
case 9 /* JSArithOp.AND */: return a & b;
|
|
3003
|
+
case 10 /* JSArithOp.OR */: return a | b;
|
|
3004
|
+
case 11 /* JSArithOp.XOR */: return a ^ b;
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
catch (e) {
|
|
3008
|
+
return JS_ThrowRangeError(ctx, String(e.message));
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
const a = n1, b = n2;
|
|
3012
|
+
switch (op) {
|
|
3013
|
+
case 0 /* JSArithOp.ADD */: return a + b;
|
|
3014
|
+
case 1 /* JSArithOp.SUB */: return a - b;
|
|
3015
|
+
case 2 /* JSArithOp.MUL */: return a * b;
|
|
3016
|
+
case 3 /* JSArithOp.DIV */: return a / b;
|
|
3017
|
+
case 4 /* JSArithOp.MOD */: return a % b;
|
|
3018
|
+
case 5 /* JSArithOp.POW */: return js_pow(a, b);
|
|
3019
|
+
case 6 /* JSArithOp.SHL */: return a << (b & 31);
|
|
3020
|
+
case 7 /* JSArithOp.SAR */: return a >> (b & 31);
|
|
3021
|
+
case 8 /* JSArithOp.SHR */: return a >>> (b & 31);
|
|
3022
|
+
case 9 /* JSArithOp.AND */: return a & b;
|
|
3023
|
+
case 10 /* JSArithOp.OR */: return a | b;
|
|
3024
|
+
case 11 /* JSArithOp.XOR */: return a ^ b;
|
|
3025
|
+
}
|
|
3026
|
+
return undefined;
|
|
3027
|
+
}
|
|
3028
|
+
export function js_pow(a, b) {
|
|
3029
|
+
/* Math.pow follows the spec */
|
|
3030
|
+
return Math.pow(a, b);
|
|
3031
|
+
}
|
|
3032
|
+
/* '+' operator with string concatenation */
|
|
3033
|
+
export function js_add_slow(ctx, op1, op2) {
|
|
3034
|
+
if (JS_IsObject(op1)) {
|
|
3035
|
+
op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE);
|
|
3036
|
+
if (JS_IsException(op1))
|
|
3037
|
+
return op1;
|
|
3038
|
+
}
|
|
3039
|
+
if (JS_IsObject(op2)) {
|
|
3040
|
+
op2 = JS_ToPrimitiveFree(ctx, op2, HINT_NONE);
|
|
3041
|
+
if (JS_IsException(op2))
|
|
3042
|
+
return op2;
|
|
3043
|
+
}
|
|
3044
|
+
if (typeof op1 === 'string' || typeof op2 === 'string') {
|
|
3045
|
+
const s1 = JS_ToString(ctx, op1);
|
|
3046
|
+
if (JS_IsException(s1))
|
|
3047
|
+
return s1;
|
|
3048
|
+
const s2 = JS_ToString(ctx, op2);
|
|
3049
|
+
if (JS_IsException(s2))
|
|
3050
|
+
return s2;
|
|
3051
|
+
return s1 + s2;
|
|
3052
|
+
}
|
|
3053
|
+
return js_binary_arith_slow(ctx, 0 /* JSArithOp.ADD */, op1, op2);
|
|
3054
|
+
}
|
|
3055
|
+
export function js_unary_arith_slow(ctx, op, op1) {
|
|
3056
|
+
if (op === 1 /* JSUnaryOp.PLUS */)
|
|
3057
|
+
return JS_ToNumberFree(ctx, op1);
|
|
3058
|
+
const n = JS_ToNumericFree(ctx, op1);
|
|
3059
|
+
if (JS_IsException(n))
|
|
3060
|
+
return n;
|
|
3061
|
+
if (typeof n === 'bigint') {
|
|
3062
|
+
switch (op) {
|
|
3063
|
+
case 0 /* JSUnaryOp.NEG */: return -n;
|
|
3064
|
+
case 2 /* JSUnaryOp.INC */: return n + 1n;
|
|
3065
|
+
case 3 /* JSUnaryOp.DEC */: return n - 1n;
|
|
3066
|
+
case 4 /* JSUnaryOp.NOT */: return ~n;
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
const a = n;
|
|
3070
|
+
switch (op) {
|
|
3071
|
+
case 0 /* JSUnaryOp.NEG */: return -a;
|
|
3072
|
+
case 2 /* JSUnaryOp.INC */: return a + 1;
|
|
3073
|
+
case 3 /* JSUnaryOp.DEC */: return a - 1;
|
|
3074
|
+
case 4 /* JSUnaryOp.NOT */: return ~a;
|
|
3075
|
+
}
|
|
3076
|
+
return undefined;
|
|
3077
|
+
}
|
|
3078
|
+
/* ---------------------------------------------------------------------
|
|
3079
|
+
Iterators
|
|
3080
|
+
--------------------------------------------------------------------- */
|
|
3081
|
+
export function js_create_iterator_result(ctx, val, done) {
|
|
3082
|
+
const obj = JS_NewObject(ctx);
|
|
3083
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_value, val, JS_PROP_C_W_E);
|
|
3084
|
+
JS_DefinePropertyValue(ctx, obj, JS_ATOM_done, done, JS_PROP_C_W_E);
|
|
3085
|
+
return obj;
|
|
3086
|
+
}
|
|
3087
|
+
export const JS_CreateIterResultObject = js_create_iterator_result;
|
|
3088
|
+
export function JS_GetIterator2(ctx, obj, method) {
|
|
3089
|
+
const enum_obj = JS_Call(ctx, method, obj, []);
|
|
3090
|
+
if (JS_IsException(enum_obj))
|
|
3091
|
+
return enum_obj;
|
|
3092
|
+
if (!JS_IsObject(enum_obj))
|
|
3093
|
+
return JS_ThrowTypeErrorNotAnObject(ctx);
|
|
3094
|
+
return enum_obj;
|
|
3095
|
+
}
|
|
3096
|
+
/* hook set by the async builtins: create an AsyncFromSyncIterator */
|
|
3097
|
+
export const async_hooks = { JS_CreateAsyncFromSyncIterator: null };
|
|
3098
|
+
export function JS_GetIterator(ctx, obj, is_async) {
|
|
3099
|
+
let method;
|
|
3100
|
+
if (is_async) {
|
|
3101
|
+
method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_asyncIterator);
|
|
3102
|
+
if (JS_IsException(method))
|
|
3103
|
+
return method;
|
|
3104
|
+
if (method === undefined || method === null) {
|
|
3105
|
+
method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
|
|
3106
|
+
if (JS_IsException(method))
|
|
3107
|
+
return method;
|
|
3108
|
+
const sync_iter = JS_GetIterator2(ctx, obj, method);
|
|
3109
|
+
if (JS_IsException(sync_iter))
|
|
3110
|
+
return sync_iter;
|
|
3111
|
+
return async_hooks.JS_CreateAsyncFromSyncIterator(ctx, sync_iter);
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
else {
|
|
3115
|
+
method = JS_GetProperty(ctx, obj, JS_ATOM_Symbol_iterator);
|
|
3116
|
+
if (JS_IsException(method))
|
|
3117
|
+
return method;
|
|
3118
|
+
}
|
|
3119
|
+
if (!JS_IsFunction(ctx, method))
|
|
3120
|
+
return JS_ThrowTypeError(ctx, 'value is not iterable');
|
|
3121
|
+
return JS_GetIterator2(ctx, obj, method);
|
|
3122
|
+
}
|
|
3123
|
+
/* return the result object of the next() call or JS_EXCEPTION */
|
|
3124
|
+
export function JS_IteratorNext2(ctx, enum_obj, method, argv, pdone) {
|
|
3125
|
+
const obj = JS_Call(ctx, method, enum_obj, argv);
|
|
3126
|
+
if (JS_IsException(obj)) {
|
|
3127
|
+
pdone.done = 0;
|
|
3128
|
+
return obj;
|
|
3129
|
+
}
|
|
3130
|
+
if (!JS_IsObject(obj)) {
|
|
3131
|
+
pdone.done = 0;
|
|
3132
|
+
return JS_ThrowTypeError(ctx, 'iterator must return an object');
|
|
3133
|
+
}
|
|
3134
|
+
const done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
|
|
3135
|
+
if (JS_IsException(done_val)) {
|
|
3136
|
+
pdone.done = 0;
|
|
3137
|
+
return done_val;
|
|
3138
|
+
}
|
|
3139
|
+
pdone.done = JS_ToBoolFree(ctx, done_val) ? 1 : 0;
|
|
3140
|
+
return obj;
|
|
3141
|
+
}
|
|
3142
|
+
/* return the 'value' of the next() call; pdone.done is set */
|
|
3143
|
+
export function JS_IteratorNext(ctx, enum_obj, method, argv, pdone) {
|
|
3144
|
+
const obj = JS_IteratorNext2(ctx, enum_obj, method, argv, pdone);
|
|
3145
|
+
if (JS_IsException(obj))
|
|
3146
|
+
return obj;
|
|
3147
|
+
if (pdone.done)
|
|
3148
|
+
return undefined;
|
|
3149
|
+
const value = JS_GetProperty(ctx, obj, JS_ATOM_value);
|
|
3150
|
+
if (JS_IsException(value)) {
|
|
3151
|
+
pdone.done = 0;
|
|
3152
|
+
return value;
|
|
3153
|
+
}
|
|
3154
|
+
return value;
|
|
3155
|
+
}
|
|
3156
|
+
/* return < 0 in case of exception */
|
|
3157
|
+
export function JS_IteratorClose(ctx, enum_obj, is_exception_pending) {
|
|
3158
|
+
let ex_obj = undefined;
|
|
3159
|
+
if (is_exception_pending)
|
|
3160
|
+
ex_obj = JS_GetException(ctx);
|
|
3161
|
+
let res = 0;
|
|
3162
|
+
const method = JS_GetProperty(ctx, enum_obj, JS_ATOM_return);
|
|
3163
|
+
if (JS_IsException(method)) {
|
|
3164
|
+
res = -1;
|
|
3165
|
+
}
|
|
3166
|
+
else if (!(method === undefined || method === null)) {
|
|
3167
|
+
const ret = JS_CallFree(ctx, method, enum_obj, []);
|
|
3168
|
+
if (!is_exception_pending) {
|
|
3169
|
+
if (JS_IsException(ret))
|
|
3170
|
+
res = -1;
|
|
3171
|
+
else if (!JS_IsObject(ret)) {
|
|
3172
|
+
JS_ThrowTypeErrorNotAnObject(ctx);
|
|
3173
|
+
res = -1;
|
|
3174
|
+
}
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
if (is_exception_pending) {
|
|
3178
|
+
JS_Throw(ctx, ex_obj);
|
|
3179
|
+
return -1;
|
|
3180
|
+
}
|
|
3181
|
+
return res;
|
|
3182
|
+
}
|
|
3183
|
+
/* obtain the next element of the iterator 'enum_obj' (used by the interpreter) */
|
|
3184
|
+
export function JS_IteratorGetCompleteValue(ctx, obj, pdone) {
|
|
3185
|
+
const done_val = JS_GetProperty(ctx, obj, JS_ATOM_done);
|
|
3186
|
+
if (JS_IsException(done_val))
|
|
3187
|
+
return done_val;
|
|
3188
|
+
const done = JS_ToBoolFree(ctx, done_val);
|
|
3189
|
+
const value = JS_GetProperty(ctx, obj, JS_ATOM_value);
|
|
3190
|
+
if (JS_IsException(value))
|
|
3191
|
+
return value;
|
|
3192
|
+
pdone.done = done ? 1 : 0;
|
|
3193
|
+
return value;
|
|
3194
|
+
}
|
|
3195
|
+
/* build an array from an iterable or array-like (used by apply/spread) */
|
|
3196
|
+
/* build an argument list from an iterable or array-like (used by apply/spread) */
|
|
3197
|
+
export function build_arg_list(ctx, array_arg) {
|
|
3198
|
+
if (!JS_IsObject(array_arg)) {
|
|
3199
|
+
JS_ThrowTypeError(ctx, 'not a object');
|
|
3200
|
+
return null;
|
|
3201
|
+
}
|
|
3202
|
+
const len = js_get_length64(ctx, array_arg);
|
|
3203
|
+
if (len < 0)
|
|
3204
|
+
return null;
|
|
3205
|
+
if (len > 65536 * 16) {
|
|
3206
|
+
JS_ThrowRangeError(ctx, 'too many arguments');
|
|
3207
|
+
return null;
|
|
3208
|
+
}
|
|
3209
|
+
const tab = new Array(len);
|
|
3210
|
+
const fast = js_get_fast_array(ctx, array_arg);
|
|
3211
|
+
if (fast && fast.length === len) {
|
|
3212
|
+
/* holes read as undefined, like the generic path */
|
|
3213
|
+
for (let i = 0; i < len; i++)
|
|
3214
|
+
tab[i] = fast[i];
|
|
3215
|
+
return tab;
|
|
3216
|
+
}
|
|
3217
|
+
for (let i = 0; i < len; i++) {
|
|
3218
|
+
const v = JS_GetPropertyUint32(ctx, array_arg, i);
|
|
3219
|
+
if (JS_IsException(v))
|
|
3220
|
+
return null;
|
|
3221
|
+
tab[i] = v;
|
|
3222
|
+
}
|
|
3223
|
+
return tab;
|
|
3224
|
+
}
|
|
3225
|
+
/* for-in enumeration: snapshot of the enumerable string keys (own keys
|
|
3226
|
+
first, then the prototype chain), as EnumerateObjectProperties */
|
|
3227
|
+
export function build_for_in_iterator(ctx, obj) {
|
|
3228
|
+
const it = new JSForInState();
|
|
3229
|
+
if (!JS_IsObject(obj)) {
|
|
3230
|
+
if (obj === undefined || obj === null) {
|
|
3231
|
+
it.obj = undefined;
|
|
3232
|
+
return it;
|
|
3233
|
+
}
|
|
3234
|
+
obj = JS_ToObject(ctx, obj);
|
|
3235
|
+
if (JS_IsException(obj))
|
|
3236
|
+
return obj;
|
|
3237
|
+
}
|
|
3238
|
+
it.obj = obj;
|
|
3239
|
+
try {
|
|
3240
|
+
/* the host for-in implements the specification algorithm, including
|
|
3241
|
+
proxy traps and shadowing */
|
|
3242
|
+
let own = 0;
|
|
3243
|
+
const own_keys = new Set(Object.keys(obj));
|
|
3244
|
+
for (const k in obj) {
|
|
3245
|
+
it.keys.push(k);
|
|
3246
|
+
if (own_keys.has(k))
|
|
3247
|
+
own++;
|
|
3248
|
+
}
|
|
3249
|
+
it.own_count = own;
|
|
3250
|
+
}
|
|
3251
|
+
catch (e) {
|
|
3252
|
+
return js_host_exception_to_guest(ctx, e);
|
|
3253
|
+
}
|
|
3254
|
+
return it;
|
|
3255
|
+
}
|
|
3256
|
+
/* return the next key or undefined when done. pdone.done = 1 when finished. -1 exception */
|
|
3257
|
+
export function js_for_in_next(ctx, enum_obj, pdone) {
|
|
3258
|
+
const it = enum_obj;
|
|
3259
|
+
const obj = it.obj;
|
|
3260
|
+
for (;;) {
|
|
3261
|
+
if (it.idx >= it.keys.length || obj === undefined) {
|
|
3262
|
+
pdone.done = 1;
|
|
3263
|
+
return undefined;
|
|
3264
|
+
}
|
|
3265
|
+
const idx = it.idx++;
|
|
3266
|
+
const key = it.keys[idx];
|
|
3267
|
+
/* check if the property was deleted (own keys: own property lookup,
|
|
3268
|
+
prototype keys: prototype chain lookup, as in C) */
|
|
3269
|
+
let ret;
|
|
3270
|
+
try {
|
|
3271
|
+
if (idx < it.own_count)
|
|
3272
|
+
ret = Reflect.getOwnPropertyDescriptor(obj, key) !== undefined ? 1 : 0;
|
|
3273
|
+
else
|
|
3274
|
+
ret = Reflect.has(obj, key) ? 1 : 0;
|
|
3275
|
+
}
|
|
3276
|
+
catch (e) {
|
|
3277
|
+
js_host_exception_to_guest(ctx, e);
|
|
3278
|
+
return JS_EXCEPTION;
|
|
3279
|
+
}
|
|
3280
|
+
if (!ret)
|
|
3281
|
+
continue;
|
|
3282
|
+
pdone.done = 0;
|
|
3283
|
+
return key;
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3286
|
+
/* ---------------------------------------------------------------------
|
|
3287
|
+
Jobs (Promises)
|
|
3288
|
+
--------------------------------------------------------------------- */
|
|
3289
|
+
export function JS_EnqueueJob(ctx, job_func, argv) {
|
|
3290
|
+
ctx.rt.job_list.push({ job_func, ctx, argv: argv.slice() });
|
|
3291
|
+
return 0;
|
|
3292
|
+
}
|
|
3293
|
+
export function JS_IsJobPending(rt) { return rt.job_list.length > 0; }
|
|
3294
|
+
/* return < 0 if exception, 0 if no job pending, 1 if a job was executed
|
|
3295
|
+
successfully. The context of the job is returned in pctx */
|
|
3296
|
+
export function JS_ExecutePendingJob(rt, pctx) {
|
|
3297
|
+
if (rt.job_list.length === 0) {
|
|
3298
|
+
pctx.ctx = null;
|
|
3299
|
+
return 0;
|
|
3300
|
+
}
|
|
3301
|
+
const e = rt.job_list.shift();
|
|
3302
|
+
pctx.ctx = e.ctx;
|
|
3303
|
+
const res = e.job_func(e.ctx, e.argv);
|
|
3304
|
+
if (JS_IsException(res))
|
|
3305
|
+
return -1;
|
|
3306
|
+
return 1;
|
|
3307
|
+
}
|
|
3308
|
+
/* ---------------------------------------------------------------------
|
|
3309
|
+
Eval
|
|
3310
|
+
--------------------------------------------------------------------- */
|
|
3311
|
+
export function JS_EvalThis(ctx, this_obj, input, filename, eval_flags) {
|
|
3312
|
+
return hooks.JS_EvalInternal(ctx, this_obj, input, filename, eval_flags, -1);
|
|
3313
|
+
}
|
|
3314
|
+
export function JS_Eval(ctx, input, filename, eval_flags) {
|
|
3315
|
+
return JS_EvalThis(ctx, ctx.global_obj, input, filename, eval_flags);
|
|
3316
|
+
}
|
|
3317
|
+
/* run the function object produced by JS_EVAL_FLAG_COMPILE_ONLY */
|
|
3318
|
+
export function JS_EvalFunction(ctx, fun_obj) {
|
|
3319
|
+
return JS_Call(ctx, fun_obj, ctx.global_obj, []);
|
|
3320
|
+
}
|
|
3321
|
+
export function JS_RunGC(_rt) { }
|
|
3322
|
+
/* ---------------------------------------------------------------------
|
|
3323
|
+
Misc helpers
|
|
3324
|
+
--------------------------------------------------------------------- */
|
|
3325
|
+
export function JS_NewString(ctx, s) { return s; }
|
|
3326
|
+
export function JS_NewStringLen(ctx, s) { return s; }
|
|
3327
|
+
export function JS_NewAtomString(ctx, s) { return s; }
|
|
3328
|
+
export function JS_NewBool(ctx, v) { return v; }
|
|
3329
|
+
export function JS_NewInt32(ctx, v) { return v | 0; }
|
|
3330
|
+
export function JS_NewUint32(ctx, v) { return v >>> 0; }
|
|
3331
|
+
export function JS_NewInt64(ctx, v) { return v; }
|
|
3332
|
+
export function JS_NewFloat64(ctx, v) { return v; }
|
|
3333
|
+
export function JS_NewCatchOffsetValue(v) { return v; }
|
|
3334
|
+
export function JS_IsLiveObject(_rt, obj) { return JS_IsObject(obj); }
|
|
3335
|
+
/* used by the interpreter: name of a class id */
|
|
3336
|
+
export function JS_GetClassName(ctx, class_id) {
|
|
3337
|
+
return ctx.rt.atoms.toStr(ctx.rt.class_array[class_id]?.class_name ?? JS_ATOM_Object);
|
|
3338
|
+
}
|
|
3339
|
+
/* Object.prototype.toString tag helper */
|
|
3340
|
+
export function js_object_class_name(ctx, obj) {
|
|
3341
|
+
switch (JS_GetClassID(obj)) {
|
|
3342
|
+
case 2 /* JSClassID.ARRAY */: return 'Array';
|
|
3343
|
+
case 3 /* JSClassID.ERROR */: return 'Error';
|
|
3344
|
+
case 8 /* JSClassID.ARGUMENTS */:
|
|
3345
|
+
case 9 /* JSClassID.MAPPED_ARGUMENTS */: return 'Arguments';
|
|
3346
|
+
case 6 /* JSClassID.BOOLEAN */: return 'Boolean';
|
|
3347
|
+
case 4 /* JSClassID.NUMBER */: return 'Number';
|
|
3348
|
+
case 5 /* JSClassID.STRING */: return 'String';
|
|
3349
|
+
case 10 /* JSClassID.DATE */: return 'Date';
|
|
3350
|
+
case 18 /* JSClassID.REGEXP */: return 'RegExp';
|
|
3351
|
+
default:
|
|
3352
|
+
if (JS_IsFunction(ctx, obj))
|
|
3353
|
+
return 'Function';
|
|
3354
|
+
return 'Object';
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
/* copy the enumerable own properties of 'source' into 'target' (object spread) */
|
|
3358
|
+
export function JS_CopyDataProperties(ctx, target, source, excluded, setprop) {
|
|
3359
|
+
if (!JS_IsObject(source))
|
|
3360
|
+
return 0;
|
|
3361
|
+
const tab = JS_GetOwnPropertyNamesInternal(ctx, source, JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK);
|
|
3362
|
+
if (!tab)
|
|
3363
|
+
return -1;
|
|
3364
|
+
for (const e of tab) {
|
|
3365
|
+
if (JS_IsObject(excluded)) {
|
|
3366
|
+
const ret = JS_GetOwnPropertyInternal(ctx, null, excluded, e.atom);
|
|
3367
|
+
if (ret < 0)
|
|
3368
|
+
return -1;
|
|
3369
|
+
if (ret)
|
|
3370
|
+
continue;
|
|
3371
|
+
}
|
|
3372
|
+
/* check enumerability (proxies may change it) */
|
|
3373
|
+
const desc = new_desc();
|
|
3374
|
+
const ret = JS_GetOwnPropertyInternal(ctx, desc, source, e.atom);
|
|
3375
|
+
if (ret < 0)
|
|
3376
|
+
return -1;
|
|
3377
|
+
if (!ret || !(desc.flags & JS_PROP_ENUMERABLE))
|
|
3378
|
+
continue;
|
|
3379
|
+
const val = JS_GetProperty(ctx, source, e.atom);
|
|
3380
|
+
if (JS_IsException(val))
|
|
3381
|
+
return -1;
|
|
3382
|
+
let r;
|
|
3383
|
+
if (setprop)
|
|
3384
|
+
r = JS_SetProperty(ctx, target, e.atom, val);
|
|
3385
|
+
else
|
|
3386
|
+
r = JS_DefinePropertyValue(ctx, target, e.atom, val, JS_PROP_C_W_E);
|
|
3387
|
+
if (r < 0)
|
|
3388
|
+
return -1;
|
|
3389
|
+
}
|
|
3390
|
+
return 0;
|
|
3391
|
+
}
|
|
3392
|
+
/* JSON-less value dump for debugging / qjs print */
|
|
3393
|
+
export function JS_DumpValue(ctx, val) {
|
|
3394
|
+
const s = JS_ToString(ctx, val);
|
|
3395
|
+
if (JS_IsException(s)) {
|
|
3396
|
+
JS_GetException(ctx);
|
|
3397
|
+
return '[exception]';
|
|
3398
|
+
}
|
|
3399
|
+
return s;
|
|
3400
|
+
}
|
|
3401
|
+
/* mark an error object as already carrying its backtrace (the interpreter
|
|
3402
|
+
adds the backtrace of errors created without one at throw time) */
|
|
3403
|
+
export function JS_SetErrorBacktraceDone(obj) {
|
|
3404
|
+
const m = js_get_meta(obj);
|
|
3405
|
+
if (m)
|
|
3406
|
+
m.has_backtrace = true;
|
|
3407
|
+
}
|
|
3408
|
+
//# sourceMappingURL=quickjs.js.map
|