Skip to main content

oxide_core/builtins/
mod.rs

1//! The realm's builtins, as natives. One file per builtin object.
2//!
3//! Every native reads its receiver and arguments through [`CallSite`]. A
4//! conversion that may run JavaScript (`ToString` of an object, `ToNumber`
5//! through `valueOf`) goes through the re-entrant [`call`](crate::vm::call); a
6//! native that holds a value across an allocation roots it first (the rooting
7//! rule, enforced by `gc-stress`). Natives that call back into JavaScript for
8//! their own work (`sort` with a comparator, `replace` with a function) use the
9//! same re-entrant call.
10
11pub mod agent;
12mod array;
13mod atomics;
14mod base64;
15mod bigint;
16mod boolean;
17mod buffer;
18mod case;
19mod collection;
20mod date;
21mod error;
22mod function;
23mod generator;
24mod global;
25mod iterator;
26mod iterator_helpers;
27mod json;
28mod math;
29mod number;
30mod object;
31mod promise;
32mod proxy;
33mod reflect;
34mod regexp;
35mod string;
36mod symbol;
37pub(crate) mod test262;
38mod typed_array;
39mod uri;
40
41use crate::heap::HeapError;
42use crate::heap::object::ObjectKind;
43use crate::heap::string::StringRepr;
44use crate::runtime::{Intrinsic, Names};
45use crate::shape::PropertyFlags;
46use crate::value::{ObjectId, StringId, Value};
47use crate::vm::error::{self as vm_error, ErrorKind};
48use crate::vm::native::CallSite;
49use crate::vm::{Cx, Throw, ops};
50
51/// A native's entry point.
52pub(crate) type NativeFn = fn(&mut Cx<'_>, CallSite) -> Result<Value, Throw>;
53
54impl Native {
55    /// Whether QuickJS runs it without a stack frame of its own, so that a
56    /// backtrace does not list it: a promise resolving function (a class
57    /// with its own call handler) or a `JS_NewCFunctionData` closure.
58    pub(crate) const fn frameless(self) -> bool {
59        matches!(
60            self,
61            Native::PromiseResolveFunction
62                | Native::PromiseRejectFunction
63                | Native::PromiseCapabilityExecutor
64                | Native::PromiseThenFinally
65                | Native::PromiseCatchFinally
66                | Native::PromiseValueThunk
67                | Native::PromiseThrower
68                | Native::PromiseAllResolveElement
69                | Native::PromiseAllSettledResolveElement
70                | Native::PromiseAllSettledRejectElement
71                | Native::PromiseAnyRejectElement
72                | Native::ProxyRevoke
73                | Native::AsyncFromSyncUnwrap
74                | Native::AsyncFromSyncCloseRejected
75                | Native::ModuleAsyncRejected
76                | Native::ModuleImportRejected
77        )
78    }
79}
80
81macro_rules! natives {
82    ($($(#[$doc:meta])* $name:ident => $function:path, $js:expr, $length:expr $(, $constructor:ident)?;)*) => {
83        /// A host function, stored by index in its function record.
84        #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
85        #[repr(u16)]
86        pub enum Native {
87            $($(#[$doc])* $name,)*
88        }
89
90        impl Native {
91            /// Every native, in index order.
92            pub const ALL: &'static [Native] = &[$(Native::$name,)*];
93
94            #[inline]
95            pub(crate) fn function(self) -> NativeFn {
96                match self {
97                    $(Native::$name => $function,)*
98                }
99            }
100
101            /// Whether `new` may call it.
102            pub const fn is_constructor(self) -> bool {
103                match self {
104                    $(Native::$name => natives!(@constructor $($constructor)?),)*
105                }
106            }
107
108            /// Its `name` property (a getter's without the `get `).
109            pub const fn js_name(self) -> &'static str {
110                match self {
111                    $(Native::$name => $js,)*
112                }
113            }
114
115            /// Its `length` property.
116            pub const fn length(self) -> u32 {
117                match self {
118                    $(Native::$name => $length,)*
119                }
120            }
121        }
122    };
123    (@constructor constructor) => { true };
124    (@constructor) => { false };
125}
126
127natives! {
128    /// qjs's `print`: the arguments' strings joined by a space, then a
129    /// newline.
130    Print => global::print, "print", 1;
131    /// `Function.prototype.call`. The loop rewrites a call of it into a call of
132    /// its receiver; the native runs only where no call site is rewritten.
133    FunctionCall => function::call, "call", 1;
134    /// `Function.prototype.apply`, rewritten by the loop as `call` is.
135    FunctionApply => function::apply, "apply", 2;
136    /// `%Function.prototype%` itself, which returns `undefined`.
137    FunctionPrototype => function::prototype, "", 0;
138    FunctionConstructor => function::constructor, "Function", 1, constructor;
139    FunctionToString => function::to_string, "toString", 0;
140    FunctionBind => function::bind, "bind", 1;
141    FunctionHasInstance => function::has_instance, "[Symbol.hasInstance]", 1;
142    FunctionFileName => function::file_name, "fileName", 0;
143    FunctionLineNumber => function::line_number, "lineNumber", 0;
144    FunctionColumnNumber => function::column_number, "columnNumber", 0;
145    ThrowTypeError => function::throw_type_error, "", 0;
146
147    ParseInt => global::parse_int, "parseInt", 2;
148    ParseFloat => global::parse_float, "parseFloat", 1;
149    Eval => crate::vm::compile::eval, "eval", 1;
150    IsNaN => global::is_nan, "isNaN", 1;
151    IsFinite => global::is_finite, "isFinite", 1;
152
153    ObjectConstructor => object::constructor, "Object", 1, constructor;
154    ObjectToString => object::to_string, "toString", 0;
155    ObjectToLocaleString => object::to_locale_string, "toLocaleString", 0;
156    ObjectValueOf => object::value_of, "valueOf", 0;
157    ObjectHasOwnProperty => object::has_own_property, "hasOwnProperty", 1;
158    ObjectIsPrototypeOf => object::is_prototype_of, "isPrototypeOf", 1;
159    ObjectPropertyIsEnumerable => object::property_is_enumerable, "propertyIsEnumerable", 1;
160    ObjectProtoGetter => object::proto_getter, "__proto__", 0;
161    ObjectProtoSetter => object::proto_setter, "__proto__", 1;
162    ObjectDefineGetter => object::define_getter, "__defineGetter__", 2;
163    ObjectDefineSetter => object::define_setter, "__defineSetter__", 2;
164    ObjectLookupGetter => object::lookup_getter, "__lookupGetter__", 1;
165    ObjectLookupSetter => object::lookup_setter, "__lookupSetter__", 1;
166    ObjectAssign => object::assign, "assign", 2;
167    ObjectCreate => object::create, "create", 2;
168    ObjectDefineProperties => object::define_properties, "defineProperties", 2;
169    ObjectDefineProperty => object::define_property, "defineProperty", 3;
170    ObjectEntries => object::entries, "entries", 1;
171    ObjectFreeze => object::freeze, "freeze", 1;
172    ObjectFromEntries => object::from_entries, "fromEntries", 1;
173    ObjectGetOwnPropertyDescriptor => object::get_own_property_descriptor, "getOwnPropertyDescriptor", 2;
174    ObjectGetOwnPropertyDescriptors => object::get_own_property_descriptors, "getOwnPropertyDescriptors", 1;
175    ObjectGetOwnPropertyNames => object::get_own_property_names, "getOwnPropertyNames", 1;
176    ObjectGetOwnPropertySymbols => object::get_own_property_symbols, "getOwnPropertySymbols", 1;
177    ObjectGetPrototypeOf => object::get_prototype_of, "getPrototypeOf", 1;
178    ObjectGroupBy => object::group_by, "groupBy", 2;
179    ObjectHasOwn => object::has_own, "hasOwn", 2;
180    ObjectIs => object::is, "is", 2;
181    ObjectIsExtensible => object::is_extensible, "isExtensible", 1;
182    ObjectIsFrozen => object::is_frozen, "isFrozen", 1;
183    ObjectIsSealed => object::is_sealed, "isSealed", 1;
184    ObjectKeys => object::keys, "keys", 1;
185    ObjectPreventExtensions => object::prevent_extensions, "preventExtensions", 1;
186    ObjectSeal => object::seal, "seal", 1;
187    ObjectSetPrototypeOf => object::set_prototype_of, "setPrototypeOf", 2;
188    ObjectValues => object::values, "values", 1;
189
190    ReflectApply => reflect::apply, "apply", 3;
191    ReflectConstruct => reflect::construct, "construct", 2;
192    ReflectDefineProperty => reflect::define_property, "defineProperty", 3;
193    ReflectDeleteProperty => reflect::delete_property, "deleteProperty", 2;
194    ReflectGet => reflect::get, "get", 2;
195    ReflectGetOwnPropertyDescriptor => reflect::get_own_property_descriptor, "getOwnPropertyDescriptor", 2;
196    ReflectGetPrototypeOf => reflect::get_prototype_of, "getPrototypeOf", 1;
197    ReflectHas => reflect::has, "has", 2;
198    ReflectIsExtensible => reflect::is_extensible, "isExtensible", 1;
199    ReflectOwnKeys => reflect::own_keys, "ownKeys", 1;
200    ReflectPreventExtensions => reflect::prevent_extensions, "preventExtensions", 1;
201    ReflectSet => reflect::set, "set", 3;
202    ReflectSetPrototypeOf => reflect::set_prototype_of, "setPrototypeOf", 2;
203
204    ProxyConstructor => proxy::constructor, "Proxy", 2, constructor;
205    ProxyRevocable => proxy::revocable, "revocable", 2;
206    ProxyRevoke => proxy::revoke, "", 0;
207
208    SymbolConstructor => symbol::constructor, "Symbol", 0, constructor;
209    SymbolFor => symbol::for_, "for", 1;
210    SymbolKeyFor => symbol::key_for, "keyFor", 1;
211    SymbolToString => symbol::to_string, "toString", 0;
212    SymbolValueOf => symbol::value_of, "valueOf", 0;
213    SymbolDescription => symbol::description, "description", 0;
214    SymbolToPrimitive => symbol::value_of, "[Symbol.toPrimitive]", 1;
215
216    ArrayConstructor => array::constructor, "Array", 1, constructor;
217    ArrayFrom => array::from, "from", 1;
218    ArrayIsArray => array::is_array, "isArray", 1;
219    ArrayOf => array::of, "of", 0;
220    ArrayAt => array::at, "at", 1;
221    ArrayConcat => array::concat, "concat", 1;
222    ArrayCopyWithin => array::copy_within, "copyWithin", 2;
223    ArrayFill => array::fill, "fill", 1;
224    ArrayFind => array::find_, "find", 1;
225    ArrayFindIndex => array::find_index, "findIndex", 1;
226    ArrayFindLast => array::find_last, "findLast", 1;
227    ArrayFindLastIndex => array::find_last_index, "findLastIndex", 1;
228    ArrayLastIndexOf => array::last_index_of, "lastIndexOf", 1;
229    ArrayPop => array::pop, "pop", 0;
230    ArrayPush => array::push, "push", 1;
231    ArrayReverse => array::reverse, "reverse", 0;
232    ArrayShift => array::shift, "shift", 0;
233    ArrayUnshift => array::unshift, "unshift", 1;
234    ArraySlice => array::slice, "slice", 2;
235    ArraySort => array::sort, "sort", 1;
236    ArraySplice => array::splice, "splice", 2;
237    ArrayIncludes => array::includes, "includes", 1;
238    ArrayIndexOf => array::index_of, "indexOf", 1;
239    ArrayJoin => array::join, "join", 1;
240    ArrayToString => array::to_string, "toString", 0;
241    ArrayToLocaleString => array::to_locale_string, "toLocaleString", 0;
242    ArrayEvery => array::every, "every", 1;
243    ArraySome => array::some, "some", 1;
244    ArrayForEach => array::for_each, "forEach", 1;
245    ArrayMap => array::map, "map", 1;
246    ArrayFilter => array::filter, "filter", 1;
247    ArrayReduce => array::reduce, "reduce", 1;
248    ArrayReduceRight => array::reduce_right, "reduceRight", 1;
249    ArrayFlat => array::flat, "flat", 0;
250    ArrayFlatMap => array::flat_map, "flatMap", 1;
251    ArrayToReversed => array::to_reversed, "toReversed", 0;
252    ArrayToSorted => array::to_sorted, "toSorted", 1;
253    ArrayToSpliced => array::to_spliced, "toSpliced", 2;
254    ArrayWith => array::with, "with", 2;
255    ArrayValues => iterator::values, "values", 0;
256    ArrayKeys => iterator::keys, "keys", 0;
257    ArrayEntries => iterator::entries, "entries", 0;
258    ArrayIteratorNext => iterator::array_iterator_next, "next", 0;
259    IteratorPrototypeIterator => iterator::iterator_prototype_iterator, "[Symbol.iterator]", 0;
260    StringIterator => iterator::string_iterator, "[Symbol.iterator]", 0;
261    StringIteratorNext => iterator::string_iterator_next, "next", 0;
262
263    StringConstructor => string::constructor, "String", 1, constructor;
264    StringFromCharCode => string::from_char_code, "fromCharCode", 1;
265    StringFromCodePoint => string::from_code_point, "fromCodePoint", 1;
266    StringRaw => string::raw, "raw", 1;
267    StringAt => string::at, "at", 1;
268    StringCharAt => string::char_at, "charAt", 1;
269    StringCharCodeAt => string::char_code_at, "charCodeAt", 1;
270    StringCodePointAt => string::code_point_at, "codePointAt", 1;
271    StringConcat => string::concat, "concat", 1;
272    StringEndsWith => string::ends_with, "endsWith", 1;
273    StringIncludes => string::includes, "includes", 1;
274    StringIndexOf => string::index_of, "indexOf", 1;
275    StringIsWellFormed => string::is_well_formed, "isWellFormed", 0;
276    StringLastIndexOf => string::last_index_of, "lastIndexOf", 1;
277    StringLocaleCompare => string::locale_compare, "localeCompare", 1;
278    StringMatch => string::match_, "match", 1;
279    StringMatchAll => string::match_all, "matchAll", 1;
280    StringNormalize => string::normalize, "normalize", 0;
281    StringPadEnd => string::pad_end, "padEnd", 1;
282    StringPadStart => string::pad_start, "padStart", 1;
283    StringRepeat => string::repeat, "repeat", 1;
284    StringReplace => string::replace, "replace", 2;
285    StringReplaceAll => string::replace_all, "replaceAll", 2;
286    StringSearch => string::search, "search", 1;
287    StringSlice => string::slice, "slice", 2;
288    StringSplit => string::split, "split", 2;
289    StringStartsWith => string::starts_with, "startsWith", 1;
290    StringSubstr => string::substr, "substr", 2;
291    StringSubstring => string::substring, "substring", 2;
292    StringToLocaleLowerCase => string::to_lower_case, "toLocaleLowerCase", 0;
293    StringToLocaleUpperCase => string::to_upper_case, "toLocaleUpperCase", 0;
294    StringToLowerCase => string::to_lower_case, "toLowerCase", 0;
295    StringToString => string::value_of, "toString", 0;
296    StringToUpperCase => string::to_upper_case, "toUpperCase", 0;
297    StringToWellFormed => string::to_well_formed, "toWellFormed", 0;
298    StringTrim => string::trim, "trim", 0;
299    StringTrimEnd => string::trim_end, "trimEnd", 0;
300    StringTrimStart => string::trim_start, "trimStart", 0;
301    StringValueOf => string::value_of, "valueOf", 0;
302    StringAnchor => string::anchor, "anchor", 1;
303    StringBig => string::big, "big", 0;
304    StringBlink => string::blink, "blink", 0;
305    StringBold => string::bold, "bold", 0;
306    StringFixed => string::fixed, "fixed", 0;
307    StringFontcolor => string::fontcolor, "fontcolor", 1;
308    StringFontsize => string::fontsize, "fontsize", 1;
309    StringItalics => string::italics, "italics", 0;
310    StringLink => string::link, "link", 1;
311    StringSmall => string::small, "small", 0;
312    StringStrike => string::strike, "strike", 0;
313    StringSub => string::sub, "sub", 0;
314    StringSup => string::sup, "sup", 0;
315
316    NumberConstructor => number::constructor, "Number", 1, constructor;
317    NumberToString => number::to_string, "toString", 1;
318    NumberToLocaleString => number::to_locale_string, "toLocaleString", 0;
319    NumberValueOf => number::value_of, "valueOf", 0;
320    NumberToFixed => number::to_fixed, "toFixed", 1;
321    NumberToExponential => number::to_exponential, "toExponential", 1;
322    NumberToPrecision => number::to_precision, "toPrecision", 1;
323    NumberIsFinite => number::is_finite, "isFinite", 1;
324    NumberIsInteger => number::is_integer, "isInteger", 1;
325    NumberIsNaN => number::is_nan, "isNaN", 1;
326    NumberIsSafeInteger => number::is_safe_integer, "isSafeInteger", 1;
327
328    BooleanConstructor => boolean::constructor, "Boolean", 1, constructor;
329    BooleanToString => boolean::to_string, "toString", 0;
330    BooleanValueOf => boolean::value_of, "valueOf", 0;
331
332    BigIntConstructor => bigint::constructor, "BigInt", 1, constructor;
333    BigIntAsIntN => bigint::as_int_n, "asIntN", 2;
334    BigIntAsUintN => bigint::as_uint_n, "asUintN", 2;
335    BigIntToLocaleString => bigint::to_locale_string, "toLocaleString", 0;
336    BigIntToString => bigint::to_string, "toString", 0;
337    BigIntValueOf => bigint::value_of, "valueOf", 0;
338
339    DecodeUri => uri::decode_uri, "decodeURI", 1;
340    DecodeUriComponent => uri::decode_uri_component, "decodeURIComponent", 1;
341    EncodeUri => uri::encode_uri, "encodeURI", 1;
342    EncodeUriComponent => uri::encode_uri_component, "encodeURIComponent", 1;
343    Escape => uri::escape, "escape", 1;
344    Unescape => uri::unescape, "unescape", 1;
345
346    MathAbs => math::abs, "abs", 1;
347    MathAcos => math::acos, "acos", 1;
348    MathAcosh => math::acosh, "acosh", 1;
349    MathAsin => math::asin, "asin", 1;
350    MathAsinh => math::asinh, "asinh", 1;
351    MathAtan => math::atan, "atan", 1;
352    MathAtanh => math::atanh, "atanh", 1;
353    MathAtan2 => math::atan2, "atan2", 2;
354    MathCbrt => math::cbrt, "cbrt", 1;
355    MathCeil => math::ceil, "ceil", 1;
356    MathClz32 => math::clz32, "clz32", 1;
357    MathCos => math::cos, "cos", 1;
358    MathCosh => math::cosh, "cosh", 1;
359    MathExp => math::exp, "exp", 1;
360    MathExpm1 => math::expm1, "expm1", 1;
361    MathFloor => math::floor, "floor", 1;
362    MathFround => math::fround, "fround", 1;
363    MathF16round => math::f16round, "f16round", 1;
364    MathHypot => math::hypot, "hypot", 2;
365    MathImul => math::imul, "imul", 2;
366    MathLog => math::log, "log", 1;
367    MathLog1p => math::log1p, "log1p", 1;
368    MathLog10 => math::log10, "log10", 1;
369    MathLog2 => math::log2, "log2", 1;
370    MathMax => math::max, "max", 2;
371    MathMin => math::min, "min", 2;
372    MathPow => math::pow, "pow", 2;
373    MathRandom => math::random, "random", 0;
374    MathRound => math::round, "round", 1;
375    MathSign => math::sign, "sign", 1;
376    MathSin => math::sin, "sin", 1;
377    MathSinh => math::sinh, "sinh", 1;
378    MathSqrt => math::sqrt, "sqrt", 1;
379    MathSumPrecise => math::sum_precise, "sumPrecise", 1;
380    MathTan => math::tan, "tan", 1;
381    MathTanh => math::tanh, "tanh", 1;
382    MathTrunc => math::trunc, "trunc", 1;
383
384    RegExpConstructor => regexp::constructor, "RegExp", 2, constructor;
385    RegExpEscape => regexp::escape, "escape", 1;
386    RegExpCompile => regexp::compile, "compile", 2;
387    RegExpExec => regexp::exec, "exec", 1;
388    RegExpTest => regexp::test, "test", 1;
389    RegExpToString => regexp::to_string, "toString", 0;
390    RegExpSource => regexp::source, "source", 0;
391    RegExpFlags => regexp::flags, "flags", 0;
392    RegExpHasIndices => regexp::has_indices, "hasIndices", 0;
393    RegExpGlobal => regexp::global, "global", 0;
394    RegExpIgnoreCase => regexp::ignore_case, "ignoreCase", 0;
395    RegExpMultiline => regexp::multiline, "multiline", 0;
396    RegExpDotAll => regexp::dot_all, "dotAll", 0;
397    RegExpUnicode => regexp::unicode, "unicode", 0;
398    RegExpUnicodeSets => regexp::unicode_sets, "unicodeSets", 0;
399    RegExpSticky => regexp::sticky, "sticky", 0;
400    RegExpSymbolMatch => regexp::symbol_match, "[Symbol.match]", 1;
401    RegExpSymbolMatchAll => regexp::symbol_match_all, "[Symbol.matchAll]", 1;
402    RegExpSymbolReplace => regexp::symbol_replace, "[Symbol.replace]", 2;
403    RegExpSymbolSearch => regexp::symbol_search, "[Symbol.search]", 1;
404    RegExpSymbolSplit => regexp::symbol_split, "[Symbol.split]", 2;
405    RegExpStringIteratorNext => regexp::string_iterator_next, "next", 0;
406
407    ErrorConstructor => error::error, "Error", 1, constructor;
408    EvalErrorConstructor => error::eval_error, "EvalError", 1, constructor;
409    RangeErrorConstructor => error::range_error, "RangeError", 1, constructor;
410    ReferenceErrorConstructor => error::reference_error, "ReferenceError", 1, constructor;
411    SyntaxErrorConstructor => error::syntax_error, "SyntaxError", 1, constructor;
412    TypeErrorConstructor => error::type_error, "TypeError", 1, constructor;
413    InternalErrorConstructor => error::internal_error, "InternalError", 1, constructor;
414    UriErrorConstructor => error::uri_error, "URIError", 1, constructor;
415    AggregateErrorConstructor => error::aggregate_error, "AggregateError", 2, constructor;
416    ErrorToString => error::to_string, "toString", 0;
417    ErrorIsError => error::is_error, "isError", 1;
418
419    PromiseConstructor => promise::constructor, "Promise", 1, constructor;
420    PromiseResolveFunction => promise::resolve_function, "", 1;
421    PromiseRejectFunction => promise::reject_function, "", 1;
422    PromiseCapabilityExecutor => promise::capability_executor, "", 2;
423    PromiseThen => promise::then, "then", 2;
424    PromiseCatch => promise::catch, "catch", 1;
425    PromiseFinally => promise::finally, "finally", 1;
426    PromiseThenFinally => promise::then_finally, "", 1;
427    PromiseCatchFinally => promise::catch_finally, "", 1;
428    PromiseValueThunk => promise::value_thunk, "", 0;
429    PromiseThrower => promise::thrower, "", 0;
430    PromiseResolveStatic => promise::resolve_static, "resolve", 1;
431    PromiseRejectStatic => promise::reject_static, "reject", 1;
432    PromiseWithResolvers => promise::with_resolvers, "withResolvers", 0;
433    PromiseTry => promise::try_, "try", 1;
434    PromiseAll => promise::all, "all", 1;
435    PromiseAllSettled => promise::all_settled, "allSettled", 1;
436    PromiseAny => promise::any, "any", 1;
437    PromiseRace => promise::race, "race", 1;
438    PromiseAllResolveElement => promise::all_resolve_element, "", 1;
439    PromiseAllSettledResolveElement => promise::all_settled_resolve_element, "", 1;
440    PromiseAllSettledRejectElement => promise::all_settled_reject_element, "", 1;
441    PromiseAnyRejectElement => promise::any_reject_element, "", 1;
442    SpeciesGetter => promise::species_getter, "[Symbol.species]", 0;
443
444    GeneratorFunctionConstructor => generator::generator_function_constructor, "GeneratorFunction", 1, constructor;
445    AsyncFunctionConstructor => generator::async_function_constructor, "AsyncFunction", 1, constructor;
446    AsyncGeneratorFunctionConstructor => generator::async_generator_function_constructor, "AsyncGeneratorFunction", 1, constructor;
447    GeneratorNext => generator::next, "next", 1;
448    GeneratorReturn => generator::return_, "return", 1;
449    GeneratorThrow => generator::throw, "throw", 1;
450    AsyncIteratorPrototypeAsyncIterator => generator::async_iterator_prototype_async_iterator, "[Symbol.asyncIterator]", 0;
451    AsyncFromSyncNext => generator::async_from_sync_next, "next", 1;
452    AsyncFromSyncReturn => generator::async_from_sync_return, "return", 1;
453    AsyncFromSyncThrow => generator::async_from_sync_throw, "throw", 1;
454    AsyncFromSyncUnwrap => generator::async_from_sync_unwrap, "", 1;
455    AsyncFromSyncCloseRejected => generator::async_from_sync_close_rejected, "", 1;
456    AsyncGeneratorNext => crate::vm::async_generator::next, "next", 1;
457    AsyncGeneratorReturn => crate::vm::async_generator::return_, "return", 1;
458    AsyncGeneratorThrow => crate::vm::async_generator::throw, "throw", 1;
459
460    DateConstructor => date::constructor, "Date", 7, constructor;
461    DateNow => date::now_, "now", 0;
462    DateParse => date::parse, "parse", 1;
463    DateUtc => date::utc, "UTC", 7;
464    DateValueOf => date::value_of, "valueOf", 0;
465    DateGetTime => date::value_of, "getTime", 0;
466    DateToString => date::to_string, "toString", 0;
467    DateToDateString => date::to_date_string, "toDateString", 0;
468    DateToTimeString => date::to_time_string, "toTimeString", 0;
469    DateToUtcString => date::to_utc_string, "toUTCString", 0;
470    DateToIsoString => date::to_iso_string, "toISOString", 0;
471    DateToLocaleString => date::to_locale_string, "toLocaleString", 0;
472    DateToLocaleDateString => date::to_locale_date_string, "toLocaleDateString", 0;
473    DateToLocaleTimeString => date::to_locale_time_string, "toLocaleTimeString", 0;
474    DateToPrimitive => date::to_primitive, "[Symbol.toPrimitive]", 1;
475    DateGetTimezoneOffset => date::get_timezone_offset, "getTimezoneOffset", 0;
476    DateGetYear => date::get_year, "getYear", 0;
477    DateGetFullYear => date::get_full_year, "getFullYear", 0;
478    DateGetUtcFullYear => date::get_utc_full_year, "getUTCFullYear", 0;
479    DateGetMonth => date::get_month, "getMonth", 0;
480    DateGetUtcMonth => date::get_utc_month, "getUTCMonth", 0;
481    DateGetDate => date::get_date, "getDate", 0;
482    DateGetUtcDate => date::get_utc_date, "getUTCDate", 0;
483    DateGetHours => date::get_hours, "getHours", 0;
484    DateGetUtcHours => date::get_utc_hours, "getUTCHours", 0;
485    DateGetMinutes => date::get_minutes, "getMinutes", 0;
486    DateGetUtcMinutes => date::get_utc_minutes, "getUTCMinutes", 0;
487    DateGetSeconds => date::get_seconds, "getSeconds", 0;
488    DateGetUtcSeconds => date::get_utc_seconds, "getUTCSeconds", 0;
489    DateGetMilliseconds => date::get_milliseconds, "getMilliseconds", 0;
490    DateGetUtcMilliseconds => date::get_utc_milliseconds, "getUTCMilliseconds", 0;
491    DateGetDay => date::get_day, "getDay", 0;
492    DateGetUtcDay => date::get_utc_day, "getUTCDay", 0;
493    DateSetMilliseconds => date::set_milliseconds, "setMilliseconds", 1;
494    DateSetUtcMilliseconds => date::set_utc_milliseconds, "setUTCMilliseconds", 1;
495    DateSetSeconds => date::set_seconds, "setSeconds", 2;
496    DateSetUtcSeconds => date::set_utc_seconds, "setUTCSeconds", 2;
497    DateSetMinutes => date::set_minutes, "setMinutes", 3;
498    DateSetUtcMinutes => date::set_utc_minutes, "setUTCMinutes", 3;
499    DateSetHours => date::set_hours, "setHours", 4;
500    DateSetUtcHours => date::set_utc_hours, "setUTCHours", 4;
501    DateSetDate => date::set_date, "setDate", 1;
502    DateSetUtcDate => date::set_utc_date, "setUTCDate", 1;
503    DateSetMonth => date::set_month, "setMonth", 2;
504    DateSetUtcMonth => date::set_utc_month, "setUTCMonth", 2;
505    DateSetFullYear => date::set_full_year, "setFullYear", 3;
506    DateSetUtcFullYear => date::set_utc_full_year, "setUTCFullYear", 3;
507    DateSetTime => date::set_time, "setTime", 1;
508    DateSetYear => date::set_year, "setYear", 1;
509    DateToJson => date::to_json, "toJSON", 1;
510
511    JsonIsRawJson => json::is_raw_json, "isRawJSON", 1;
512    JsonParse => json::parse, "parse", 2;
513    JsonRawJson => json::raw_json, "rawJSON", 1;
514    JsonStringify => json::stringify, "stringify", 3;
515
516    MapConstructor => collection::map_constructor, "Map", 0, constructor;
517    MapGroupBy => collection::group_by, "groupBy", 2;
518    MapSet => collection::map_set, "set", 2;
519    MapGet => collection::map_get, "get", 1;
520    MapGetOrInsert => collection::map_get_or_insert, "getOrInsert", 2;
521    MapGetOrInsertComputed => collection::map_get_or_insert_computed, "getOrInsertComputed", 2;
522    MapHas => collection::map_has, "has", 1;
523    MapDelete => collection::map_delete, "delete", 1;
524    MapClear => collection::map_clear, "clear", 0;
525    MapSize => collection::map_size, "size", 0;
526    MapForEach => collection::map_for_each, "forEach", 1;
527    MapValues => collection::map_values, "values", 0;
528    MapKeys => collection::map_keys, "keys", 0;
529    MapEntries => collection::map_entries, "entries", 0;
530    MapIteratorNext => collection::map_iterator_next, "next", 0;
531    SetConstructor => collection::set_constructor, "Set", 0, constructor;
532    SetAdd => collection::set_add, "add", 1;
533    SetHas => collection::set_has, "has", 1;
534    SetDelete => collection::set_delete, "delete", 1;
535    SetClear => collection::set_clear, "clear", 0;
536    SetSize => collection::set_size, "size", 0;
537    SetForEach => collection::set_for_each, "forEach", 1;
538    SetIsDisjointFrom => collection::set_is_disjoint_from, "isDisjointFrom", 1;
539    SetIsSubsetOf => collection::set_is_subset_of, "isSubsetOf", 1;
540    SetIsSupersetOf => collection::set_is_superset_of, "isSupersetOf", 1;
541    SetIntersection => collection::set_intersection, "intersection", 1;
542    SetDifference => collection::set_difference, "difference", 1;
543    SetSymmetricDifference => collection::set_symmetric_difference, "symmetricDifference", 1;
544    SetUnion => collection::set_union, "union", 1;
545    SetValues => collection::set_values, "values", 0;
546    SetEntries => collection::set_entries, "entries", 0;
547    SetIteratorNext => collection::set_iterator_next, "next", 0;
548    WeakMapConstructor => collection::weak_map_constructor, "WeakMap", 0, constructor;
549    WeakMapSet => collection::weak_map_set, "set", 2;
550    WeakMapGet => collection::weak_map_get, "get", 1;
551    WeakMapGetOrInsert => collection::weak_map_get_or_insert, "getOrInsert", 2;
552    WeakMapGetOrInsertComputed => collection::weak_map_get_or_insert_computed, "getOrInsertComputed", 2;
553    WeakMapHas => collection::weak_map_has, "has", 1;
554    WeakMapDelete => collection::weak_map_delete, "delete", 1;
555    WeakSetConstructor => collection::weak_set_constructor, "WeakSet", 0, constructor;
556    WeakSetAdd => collection::weak_set_add, "add", 1;
557    WeakSetHas => collection::weak_set_has, "has", 1;
558    WeakSetDelete => collection::weak_set_delete, "delete", 1;
559    WeakRefConstructor => collection::weak_ref_constructor, "WeakRef", 1, constructor;
560    WeakRefDeref => collection::weak_ref_deref, "deref", 0;
561    FinalizationRegistryConstructor => collection::finalization_registry_constructor, "FinalizationRegistry", 1, constructor;
562    FinalizationRegistryRegister => collection::finalization_registry_register, "register", 2;
563    FinalizationRegistryUnregister => collection::finalization_registry_unregister, "unregister", 1;
564
565    IteratorConstructor => iterator_helpers::constructor, "Iterator", 0, constructor;
566    IteratorConstructorGetter => iterator_helpers::constructor_getter, "constructor", 0;
567    IteratorConstructorSetter => iterator_helpers::constructor_setter, "constructor", 1;
568    IteratorToStringTagGetter => iterator_helpers::to_string_tag_getter, "[Symbol.toStringTag]", 0;
569    IteratorToStringTagSetter => iterator_helpers::to_string_tag_setter, "[Symbol.toStringTag]", 1;
570    IteratorFrom => iterator_helpers::from, "from", 1;
571    IteratorConcat => iterator_helpers::concat, "concat", 0;
572    WrapForValidNext => iterator_helpers::wrap_next, "next", 0;
573    WrapForValidReturn => iterator_helpers::wrap_return, "return", 0;
574    IteratorDrop => iterator_helpers::drop, "drop", 1;
575    IteratorFilter => iterator_helpers::filter, "filter", 1;
576    IteratorFlatMap => iterator_helpers::flat_map, "flatMap", 1;
577    IteratorMap => iterator_helpers::map, "map", 1;
578    IteratorTake => iterator_helpers::take, "take", 1;
579    IteratorEvery => iterator_helpers::every, "every", 1;
580    IteratorFind => iterator_helpers::find, "find", 1;
581    IteratorForEach => iterator_helpers::for_each, "forEach", 1;
582    IteratorSome => iterator_helpers::some, "some", 1;
583    IteratorReduce => iterator_helpers::reduce, "reduce", 1;
584    IteratorToArray => iterator_helpers::to_array, "toArray", 0;
585    IteratorHelperNext => iterator_helpers::helper_next, "next", 0;
586    IteratorHelperReturn => iterator_helpers::helper_return, "return", 0;
587
588    ArrayBufferConstructor => buffer::array_buffer_constructor, "ArrayBuffer", 1, constructor;
589    ArrayBufferIsView => buffer::is_view, "isView", 1;
590    ArrayBufferByteLength => buffer::byte_length, "byteLength", 0;
591    ArrayBufferMaxByteLength => buffer::max_byte_length, "maxByteLength", 0;
592    ArrayBufferResizable => buffer::resizable, "resizable", 0;
593    ArrayBufferDetached => buffer::detached, "detached", 0;
594    ArrayBufferResize => buffer::resize, "resize", 1;
595    ArrayBufferSlice => buffer::slice, "slice", 2;
596    ArrayBufferTransfer => buffer::transfer, "transfer", 0;
597    ArrayBufferTransferToFixedLength => buffer::transfer_to_fixed_length, "transferToFixedLength", 0;
598    SharedArrayBufferConstructor => buffer::shared_array_buffer_constructor, "SharedArrayBuffer", 1, constructor;
599    SharedArrayBufferByteLength => buffer::shared_byte_length, "byteLength", 0;
600    SharedArrayBufferGrowable => buffer::growable, "growable", 0;
601    SharedArrayBufferMaxByteLength => buffer::shared_max_byte_length, "maxByteLength", 0;
602    SharedArrayBufferGrow => buffer::grow, "grow", 1;
603    SharedArrayBufferSlice => buffer::shared_slice, "slice", 2;
604    DataViewConstructor => buffer::data_view_constructor, "DataView", 1, constructor;
605    DataViewBuffer => buffer::data_view_buffer, "buffer", 0;
606    DataViewByteLength => buffer::data_view_byte_length, "byteLength", 0;
607    DataViewByteOffset => buffer::data_view_byte_offset, "byteOffset", 0;
608    DataViewGetInt8 => buffer::get_int8, "getInt8", 1;
609    DataViewSetInt8 => buffer::set_int8, "setInt8", 2;
610    DataViewGetUint8 => buffer::get_uint8, "getUint8", 1;
611    DataViewSetUint8 => buffer::set_uint8, "setUint8", 2;
612    DataViewGetInt16 => buffer::get_int16, "getInt16", 1;
613    DataViewSetInt16 => buffer::set_int16, "setInt16", 2;
614    DataViewGetUint16 => buffer::get_uint16, "getUint16", 1;
615    DataViewSetUint16 => buffer::set_uint16, "setUint16", 2;
616    DataViewGetInt32 => buffer::get_int32, "getInt32", 1;
617    DataViewSetInt32 => buffer::set_int32, "setInt32", 2;
618    DataViewGetUint32 => buffer::get_uint32, "getUint32", 1;
619    DataViewSetUint32 => buffer::set_uint32, "setUint32", 2;
620    DataViewGetFloat16 => buffer::get_float16, "getFloat16", 1;
621    DataViewSetFloat16 => buffer::set_float16, "setFloat16", 2;
622    DataViewGetFloat32 => buffer::get_float32, "getFloat32", 1;
623    DataViewSetFloat32 => buffer::set_float32, "setFloat32", 2;
624    DataViewGetFloat64 => buffer::get_float64, "getFloat64", 1;
625    DataViewSetFloat64 => buffer::set_float64, "setFloat64", 2;
626    DataViewGetBigInt64 => buffer::get_big_int64, "getBigInt64", 1;
627    DataViewSetBigInt64 => buffer::set_big_int64, "setBigInt64", 2;
628    DataViewGetBigUint64 => buffer::get_big_uint64, "getBigUint64", 1;
629    DataViewSetBigUint64 => buffer::set_big_uint64, "setBigUint64", 2;
630    TypedArrayConstructor => typed_array::abstract_constructor, "TypedArray", 0, constructor;
631    TypedArrayFrom => typed_array::from, "from", 1;
632    TypedArrayOf => typed_array::of, "of", 0;
633    TypedArrayBuffer => typed_array::buffer_getter, "buffer", 0;
634    TypedArrayByteLength => typed_array::byte_length, "byteLength", 0;
635    TypedArrayByteOffset => typed_array::byte_offset, "byteOffset", 0;
636    TypedArrayLength => typed_array::length, "length", 0;
637    TypedArrayToStringTag => typed_array::to_string_tag_getter, "[Symbol.toStringTag]", 0;
638    TypedArrayAt => typed_array::at, "at", 1;
639    TypedArrayCopyWithin => typed_array::copy_within, "copyWithin", 2;
640    TypedArrayEntries => typed_array::entries, "entries", 0;
641    TypedArrayEvery => typed_array::every, "every", 1;
642    TypedArrayFill => typed_array::fill, "fill", 1;
643    TypedArrayFilter => typed_array::filter, "filter", 1;
644    TypedArrayFind => typed_array::find, "find", 1;
645    TypedArrayFindIndex => typed_array::find_index, "findIndex", 1;
646    TypedArrayFindLast => typed_array::find_last, "findLast", 1;
647    TypedArrayFindLastIndex => typed_array::find_last_index, "findLastIndex", 1;
648    TypedArrayForEach => typed_array::for_each, "forEach", 1;
649    TypedArrayIncludes => typed_array::includes, "includes", 1;
650    TypedArrayIndexOf => typed_array::index_of, "indexOf", 1;
651    TypedArrayJoin => typed_array::join, "join", 1;
652    TypedArrayKeys => typed_array::keys, "keys", 0;
653    TypedArrayLastIndexOf => typed_array::last_index_of, "lastIndexOf", 1;
654    TypedArrayMap => typed_array::map, "map", 1;
655    TypedArrayReduce => typed_array::reduce, "reduce", 1;
656    TypedArrayReduceRight => typed_array::reduce_right, "reduceRight", 1;
657    TypedArrayReverse => typed_array::reverse, "reverse", 0;
658    TypedArraySet => typed_array::set_method, "set", 1;
659    TypedArraySlice => typed_array::slice, "slice", 2;
660    TypedArraySome => typed_array::some, "some", 1;
661    TypedArraySort => typed_array::sort, "sort", 1;
662    TypedArraySubarray => typed_array::subarray, "subarray", 2;
663    TypedArrayToLocaleString => typed_array::to_locale_string, "toLocaleString", 0;
664    TypedArrayToReversed => typed_array::to_reversed, "toReversed", 0;
665    TypedArrayToSorted => typed_array::to_sorted, "toSorted", 1;
666    TypedArrayValues => typed_array::values, "values", 0;
667    TypedArrayWith => typed_array::with, "with", 2;
668    Int8ArrayConstructor => typed_array::int8_array, "Int8Array", 3, constructor;
669    Uint8ArrayConstructor => typed_array::uint8_array, "Uint8Array", 3, constructor;
670    Uint8ClampedArrayConstructor => typed_array::uint8_clamped_array, "Uint8ClampedArray", 3, constructor;
671    Int16ArrayConstructor => typed_array::int16_array, "Int16Array", 3, constructor;
672    Uint16ArrayConstructor => typed_array::uint16_array, "Uint16Array", 3, constructor;
673    Int32ArrayConstructor => typed_array::int32_array, "Int32Array", 3, constructor;
674    Uint32ArrayConstructor => typed_array::uint32_array, "Uint32Array", 3, constructor;
675    Float16ArrayConstructor => typed_array::float16_array, "Float16Array", 3, constructor;
676    Float32ArrayConstructor => typed_array::float32_array, "Float32Array", 3, constructor;
677    Float64ArrayConstructor => typed_array::float64_array, "Float64Array", 3, constructor;
678    BigInt64ArrayConstructor => typed_array::big_int64_array, "BigInt64Array", 3, constructor;
679    BigUint64ArrayConstructor => typed_array::big_uint64_array, "BigUint64Array", 3, constructor;
680    Uint8ArrayFromBase64 => typed_array::from_base64, "fromBase64", 1;
681    Uint8ArrayFromHex => typed_array::from_hex, "fromHex", 1;
682    Uint8ArrayToBase64 => typed_array::to_base64, "toBase64", 0;
683    Uint8ArraySetFromBase64 => typed_array::set_from_base64, "setFromBase64", 1;
684    Uint8ArrayToHex => typed_array::to_hex, "toHex", 0;
685    Uint8ArraySetFromHex => typed_array::set_from_hex, "setFromHex", 1;
686    AtomicsAdd => atomics::add, "add", 3;
687    AtomicsAnd => atomics::and, "and", 3;
688    AtomicsCompareExchange => atomics::compare_exchange, "compareExchange", 4;
689    AtomicsExchange => atomics::exchange, "exchange", 3;
690    AtomicsIsLockFree => atomics::is_lock_free, "isLockFree", 1;
691    AtomicsLoad => atomics::load, "load", 2;
692    AtomicsNotify => atomics::notify, "notify", 3;
693    AtomicsOr => atomics::or, "or", 3;
694    AtomicsStore => atomics::store, "store", 3;
695    AtomicsSub => atomics::sub, "sub", 3;
696    AtomicsWait => atomics::wait, "wait", 4;
697    AtomicsXor => atomics::xor, "xor", 3;
698    AtomicsPause => atomics::pause, "pause", 0;
699
700    AgentStart => agent::start, "start", 1;
701    AgentBroadcast => agent::broadcast, "broadcast", 2;
702    AgentGetReport => agent::get_report, "getReport", 0;
703    AgentSleep => agent::sleep, "sleep", 1;
704    AgentMonotonicNow => agent::monotonic_now, "monotonicNow", 0;
705    AgentReceiveBroadcast => agent::receive_broadcast, "receiveBroadcast", 1;
706    AgentReport => agent::report, "report", 1;
707    AgentLeaving => agent::leaving, "leaving", 0;
708
709    ModuleAsyncFulfilled => crate::vm::module::module_async_fulfilled, "", 1;
710    ModuleAsyncRejected => crate::vm::module::module_async_rejected, "", 1;
711    ModuleImportFulfilled => crate::vm::module::module_import_fulfilled, "", 1;
712    ModuleImportJob => crate::vm::module::module_import_job, "", 0;
713    ModuleImportRejected => crate::vm::module::module_import_rejected, "", 1;
714
715    Test262CreateRealm => test262::create_realm, "createRealm", 0;
716    Test262Gc => test262::gc, "gc", 0;
717    Test262EvalScript => test262::eval_script, "evalScript", 1;
718    Test262DetachArrayBuffer => test262::detach_array_buffer, "detachArrayBuffer", 1;
719    Test262CodePointRange => test262::code_point_range, "codePointRange", 2;
720
721    ConsoleLog => global::print, "log", 1;
722    Load => crate::vm::compile::load, "load", 1;
723    Read => crate::vm::compile::read, "read", 1;
724    LoadScript => crate::vm::compile::load_script, "__loadScript", 1;
725    PerformanceNow => global::performance_now, "now", 0;
726
727    /// An embedder's function (`NativeCx::new_host_function`); its name
728    /// and length are its own properties.
729    HostFunction => crate::vm::native::host_call, "", 0;
730    /// An embedder's function that `new` may call.
731    HostConstructor => crate::vm::native::host_call, "", 0, constructor;
732}
733
734impl Native {
735    #[inline]
736    pub(crate) const fn index(self) -> u32 {
737        self as u32
738    }
739
740    #[inline]
741    pub(crate) fn from_index(index: u32) -> Option<Native> {
742        Native::ALL.get(index as usize).copied()
743    }
744
745    /// The constructor of an error kind.
746    pub(crate) const fn error(kind: ErrorKind) -> Native {
747        match kind {
748            ErrorKind::Error => Native::ErrorConstructor,
749            ErrorKind::Eval => Native::EvalErrorConstructor,
750            ErrorKind::Range => Native::RangeErrorConstructor,
751            ErrorKind::Reference => Native::ReferenceErrorConstructor,
752            ErrorKind::Syntax => Native::SyntaxErrorConstructor,
753            ErrorKind::Type => Native::TypeErrorConstructor,
754            ErrorKind::Internal => Native::InternalErrorConstructor,
755            ErrorKind::Uri => Native::UriErrorConstructor,
756            ErrorKind::Aggregate => Native::AggregateErrorConstructor,
757        }
758    }
759}
760
761// ---- helpers for the natives ----
762
763/// A relative index (`slice`'s): negative counts from `length`, clamped to
764/// `0..=length`.
765pub(crate) fn relative(index: f64, length: usize) -> usize {
766    let length = length as f64;
767    let index = if index < 0.0 {
768        (length + index).max(0.0)
769    } else {
770        index.min(length)
771    };
772    index as usize
773}
774
775/// A string value from UTF-16 units. A single unit is an atom, so `charAt`
776/// and one-character slices do not allocate.
777pub(crate) fn string_units(cx: &mut Cx<'_>, units: &[u16]) -> Result<Value, Throw> {
778    if units.len() > string::MAX_STRING {
779        return Err(vm_error::string_too_long(cx));
780    }
781    let result = if units.len() == 1 {
782        cx.heap.intern_units(units)
783    } else if units.is_empty() {
784        return Ok(Value::string(cx.realm.names.empty));
785    } else {
786        cx.heap.alloc_string_units(units)
787    };
788    result
789        .map(Value::string)
790        .map_err(|error| vm_error::heap_error(cx, error))
791}
792
793/// A string value from a representation already canonical.
794pub(crate) fn string_repr(cx: &mut Cx<'_>, repr: StringRepr) -> Result<Value, Throw> {
795    if repr.len() <= 1 {
796        let units: Vec<u16> = repr.units().collect();
797        return string_units(cx, &units);
798    }
799    cx.heap
800        .alloc_string_repr(repr)
801        .map(Value::string)
802        .map_err(|error| vm_error::heap_error(cx, error))
803}
804
805/// A string value from Rust text.
806pub(crate) fn string_text(cx: &mut Cx<'_>, text: &str) -> Result<Value, Throw> {
807    if text.is_ascii() {
808        return string_repr(cx, StringRepr::OneByte(text.as_bytes().into()));
809    }
810    let units: Vec<u16> = text.encode_utf16().collect();
811    string_units(cx, &units)
812}
813
814/// `ToString(value)` as a string id. A string made by the conversion is
815/// rooted until the native returns (`native::call` cuts the root stack).
816pub(crate) fn to_string_id(cx: &mut Cx<'_>, value: Value) -> Result<StringId, Throw> {
817    if let Some(id) = value.as_string() {
818        return Ok(id);
819    }
820    let string = ops::to_string(cx, value)?;
821    cx.heap.roots().push(string);
822    Ok(string.as_string().expect("a string"))
823}
824
825/// The receiver of a `String.prototype` method as a string
826/// (`RequireObjectCoercible` then `ToString`).
827pub(crate) fn this_string(cx: &mut Cx<'_>, site: &CallSite) -> Result<StringId, Throw> {
828    let this = site.this(cx);
829    if let Some(id) = this.as_string() {
830        return Ok(id);
831    }
832    if this.is_undefined() || this.is_null() {
833        return Err(vm_error::type_error(cx, "null or undefined are forbidden"));
834    }
835    to_string_id(cx, this)
836}
837
838/// The receiver as an object (`ToObject(this)`), wrapped and rooted when it
839/// is a primitive.
840pub(crate) fn this_object(cx: &mut Cx<'_>, site: &CallSite) -> Result<ObjectId, Throw> {
841    let this = site.this(cx);
842    if let Some(object) = this.as_object() {
843        return Ok(object);
844    }
845    let object = crate::vm::object::to_object(cx, this)?;
846    cx.heap.roots().push(Value::object(object));
847    Ok(object)
848}
849
850// ---- installation ----
851
852fn hidden() -> PropertyFlags {
853    PropertyFlags::data(true, false, true)
854}
855
856/// Defines data property `name` of `object`; `value` is rooted for the call.
857fn define(
858    cx: &mut Cx<'_>,
859    object: ObjectId,
860    name: &str,
861    value: Value,
862    flags: PropertyFlags,
863) -> Result<(), HeapError> {
864    let key = cx.heap.property_key(name)?;
865    define_key(cx, object, key, value, flags)
866}
867
868fn define_key(
869    cx: &mut Cx<'_>,
870    object: ObjectId,
871    key: crate::PropertyKey,
872    value: Value,
873    flags: PropertyFlags,
874) -> Result<(), HeapError> {
875    let mark = cx.heap.roots().mark();
876    cx.heap.roots().push(value);
877    let result = cx.heap.add_property(object, key, flags, value);
878    cx.heap.roots().truncate(mark);
879    result
880}
881
882/// Defines a function's `length` and then `name` (non-writable,
883/// non-enumerable, configurable), as every function has them.
884pub(crate) fn define_name_length(
885    heap: &mut crate::Heap,
886    names: &Names,
887    function: ObjectId,
888    name: Value,
889    length: u32,
890) -> Result<(), HeapError> {
891    let flags = PropertyFlags::data(false, false, true);
892    let mark = heap.roots().mark();
893    heap.roots().push(name);
894    let result = heap
895        .add_property(
896            function,
897            Names::key(names.length),
898            flags,
899            Value::int32(length as i32),
900        )
901        .and_then(|()| heap.add_property(function, Names::key(names.name), flags, name));
902    heap.roots().truncate(mark);
903    result
904}
905
906/// A native function object named `name`, with its `length`, left on the
907/// root stack.
908fn native_named(
909    cx: &mut Cx<'_>,
910    native: Native,
911    name: &str,
912    data: Option<ObjectId>,
913) -> Result<ObjectId, HeapError> {
914    let prototype = cx.realm.intrinsic(Intrinsic::FunctionPrototype);
915    let function = cx
916        .heap
917        .alloc_native_closure(Some(prototype), native.index(), data)?;
918    cx.heap.roots().push(Value::object(function));
919    if native.is_constructor() {
920        cx.heap
921            .set_object_flag(function, crate::heap::object::flags::CONSTRUCTOR);
922    }
923    let name = if name.is_empty() {
924        cx.realm.names.empty
925    } else {
926        cx.heap.intern(name)?
927    };
928    let names = cx.realm.names;
929    define_name_length(
930        cx.heap,
931        &names,
932        function,
933        Value::string(name),
934        native.length(),
935    )?;
936    Ok(function)
937}
938
939/// A native function object with its table name and length, left on the
940/// root stack.
941fn native_function(cx: &mut Cx<'_>, native: Native) -> Result<ObjectId, HeapError> {
942    native_named(cx, native, native.js_name(), None)
943}
944
945/// A native closure over `data` (an object whose internal slots the native
946/// reads through [`CallSite::data`]), named by the table, for natives made
947/// at run time (a promise's resolving functions, a revoker).
948pub(crate) fn native_closure(
949    cx: &mut Cx<'_>,
950    native: Native,
951    data: ObjectId,
952) -> Result<ObjectId, Throw> {
953    let mark = cx.heap.roots().mark();
954    cx.heap.roots().push(Value::object(data));
955    let result = native_named(cx, native, native.js_name(), Some(data));
956    cx.heap.roots().truncate(mark);
957    result.map_err(|error| vm_error::heap_error(cx, error))
958}
959
960/// A data object for [`native_closure`] holding `slots`.
961pub(crate) fn native_data(cx: &mut Cx<'_>, slots: &[Value]) -> Result<ObjectId, Throw> {
962    cx.heap
963        .alloc_internal(
964            ObjectKind::Builtin,
965            crate::heap::object::InternalTag::NativeData,
966            None,
967            0,
968            slots,
969            Default::default(),
970            0,
971        )
972        .map_err(|error| vm_error::heap_error(cx, error))
973}
974
975/// Defines each native as a non-enumerable method of `object` under its
976/// table name.
977fn methods(cx: &mut Cx<'_>, object: ObjectId, list: &[Native]) -> Result<(), HeapError> {
978    for &native in list {
979        let function = native_function(cx, native)?;
980        define(
981            cx,
982            object,
983            native.js_name(),
984            Value::object(function),
985            hidden(),
986        )?;
987    }
988    Ok(())
989}
990
991/// Defines a method keyed by a well-known symbol; its name is the table's
992/// (`[Symbol.iterator]`).
993fn symbol_method(
994    cx: &mut Cx<'_>,
995    object: ObjectId,
996    symbol: crate::SymbolId,
997    native: Native,
998    flags: PropertyFlags,
999) -> Result<(), HeapError> {
1000    let function = native_function(cx, native)?;
1001    define_key(
1002        cx,
1003        object,
1004        crate::PropertyKey::symbol(symbol),
1005        Value::object(function),
1006        flags,
1007    )
1008}
1009
1010/// Defines accessor `name` of `object` (non-enumerable, configurable) with
1011/// a getter native and an optional setter native, named `get name` and
1012/// `set name`.
1013fn accessor(
1014    cx: &mut Cx<'_>,
1015    object: ObjectId,
1016    key: crate::PropertyKey,
1017    name: &str,
1018    getter: Option<Native>,
1019    setter: Option<Native>,
1020) -> Result<(), HeapError> {
1021    let get = match getter {
1022        Some(native) => Value::object(native_named(cx, native, &format!("get {name}"), None)?),
1023        None => Value::UNDEFINED,
1024    };
1025    let set = match setter {
1026        Some(native) => Value::object(native_named(cx, native, &format!("set {name}"), None)?),
1027        None => Value::UNDEFINED,
1028    };
1029    cx.heap
1030        .add_accessor(object, key, PropertyFlags::accessor(false, true), get, set)
1031}
1032
1033/// [`accessor`] keyed by a string.
1034fn getter(cx: &mut Cx<'_>, object: ObjectId, name: &str, native: Native) -> Result<(), HeapError> {
1035    let key = cx.heap.property_key(name)?;
1036    accessor(cx, object, key, name, Some(native), None)
1037}
1038
1039/// A constructor function, defined on the global object as its table name.
1040/// Its `prototype` link comes last ([`link_constructor`]), after its static
1041/// members and the prototype's methods, as QuickJS's `JS_NewCConstructor`
1042/// orders them.
1043fn install_constructor(cx: &mut Cx<'_>, native: Native) -> Result<ObjectId, HeapError> {
1044    let function = native_function(cx, native)?;
1045    let global = cx.realm.global();
1046    define(
1047        cx,
1048        global,
1049        native.js_name(),
1050        Value::object(function),
1051        hidden(),
1052    )?;
1053    Ok(function)
1054}
1055
1056/// Defines `function.prototype` (non-writable) and then
1057/// `prototype.constructor` (QuickJS's `JS_SetConstructor2`), each the last
1058/// string-keyed property of its object.
1059fn link_constructor(
1060    cx: &mut Cx<'_>,
1061    function: ObjectId,
1062    prototype: ObjectId,
1063) -> Result<(), HeapError> {
1064    let names = cx.realm.names;
1065    cx.heap.add_property(
1066        function,
1067        Names::key(names.prototype),
1068        PropertyFlags::data(false, false, false),
1069        Value::object(prototype),
1070    )?;
1071    cx.heap.add_property(
1072        prototype,
1073        Names::key(names.constructor),
1074        hidden(),
1075        Value::object(function),
1076    )
1077}
1078
1079/// An ordinary object inheriting from `prototype`, rooted.
1080fn plain_object(
1081    cx: &mut Cx<'_>,
1082    prototype: Option<ObjectId>,
1083    slots: u32,
1084) -> Result<ObjectId, HeapError> {
1085    let object = cx
1086        .heap
1087        .alloc_object(ObjectKind::Ordinary, prototype, slots)?;
1088    cx.heap.roots().push(Value::object(object));
1089    Ok(object)
1090}
1091
1092/// Defines `Symbol.toStringTag` on `object` as `tag` (non-writable,
1093/// non-enumerable, configurable).
1094fn to_string_tag(cx: &mut Cx<'_>, object: ObjectId, tag: &str) -> Result<(), HeapError> {
1095    let tag = cx.heap.intern(tag)?;
1096    let key = crate::PropertyKey::symbol(cx.realm.symbols.to_string_tag);
1097    cx.heap.add_property(
1098        object,
1099        key,
1100        PropertyFlags::data(false, false, true),
1101        Value::string(tag),
1102    )
1103}
1104
1105/// The realm's globals, constructors and prototypes. Returns the
1106/// preallocated out-of-memory error.
1107pub(crate) fn install(cx: &mut Cx<'_>) -> Result<ObjectId, HeapError> {
1108    let mark = cx.heap.roots().mark();
1109    let result = install_rooted(cx);
1110    cx.heap.roots().truncate(mark);
1111    result
1112}
1113
1114fn install_rooted(cx: &mut Cx<'_>) -> Result<ObjectId, HeapError> {
1115    let global = cx.realm.global();
1116    let constant = PropertyFlags::data(false, false, false);
1117    define(cx, global, "globalThis", Value::object(global), hidden())?;
1118    define(cx, global, "undefined", Value::UNDEFINED, constant)?;
1119    define(cx, global, "NaN", Value::number(f64::NAN), constant)?;
1120    define(
1121        cx,
1122        global,
1123        "Infinity",
1124        Value::number(f64::INFINITY),
1125        constant,
1126    )?;
1127    methods(
1128        cx,
1129        global,
1130        &[
1131            Native::ParseInt,
1132            Native::ParseFloat,
1133            Native::IsNaN,
1134            Native::IsFinite,
1135        ],
1136    )?;
1137    let eval = native_function(cx, Native::Eval)?;
1138    cx.set_intrinsic(Intrinsic::Eval, eval);
1139    define(cx, global, "eval", Value::object(eval), hidden())?;
1140    function::install(cx)?;
1141    object::install(cx)?;
1142    symbol::install(cx)?;
1143    reflect::install(cx)?;
1144    proxy::install(cx)?;
1145    array::install(cx)?;
1146    string::install(cx)?;
1147    iterator::install(cx)?;
1148    iterator_helpers::install(cx)?;
1149    generator::install(cx)?;
1150    generator::install_async_from_sync(cx)?;
1151    promise::install(cx)?;
1152    number::install(cx)?;
1153    boolean::install(cx)?;
1154    math::install(cx)?;
1155    bigint::install(cx)?;
1156    uri::install(cx)?;
1157    regexp::install(cx)?;
1158    date::install(cx)?;
1159    json::install(cx)?;
1160    collection::install(cx)?;
1161    buffer::install(cx)?;
1162    typed_array::install(cx)?;
1163    atomics::install(cx)?;
1164    error::install(cx)?;
1165    regexp::record_flag_cache(cx)?;
1166    to_string_tag(cx, global, "global")?;
1167    order_globals(cx, global)?;
1168    let message = cx.heap.intern("out of memory")?;
1169    let error = vm_error::new_error(cx, ErrorKind::Internal, Value::string(message))?;
1170    Ok(error.as_object().unwrap())
1171}
1172
1173/// The global object's properties in QuickJS's order: its
1174/// `JS_AddIntrinsicBasicObjects`, `JS_AddIntrinsicBaseObjects` and the
1175/// `JS_AddIntrinsic*` calls of `JS_NewContext`, which define them in an
1176/// order the install's dependencies do not allow.
1177const GLOBAL_ORDER: &[&str] = &[
1178    "Error",
1179    "EvalError",
1180    "RangeError",
1181    "ReferenceError",
1182    "SyntaxError",
1183    "TypeError",
1184    "URIError",
1185    "InternalError",
1186    "AggregateError",
1187    "Array",
1188    "Object",
1189    "Function",
1190    "Iterator",
1191    "parseInt",
1192    "parseFloat",
1193    "isNaN",
1194    "isFinite",
1195    "decodeURI",
1196    "decodeURIComponent",
1197    "encodeURI",
1198    "encodeURIComponent",
1199    "escape",
1200    "unescape",
1201    "Infinity",
1202    "NaN",
1203    "undefined",
1204    "eval",
1205    "Number",
1206    "Boolean",
1207    "String",
1208    "Math",
1209    "Reflect",
1210    "Symbol",
1211    "globalThis",
1212    "BigInt",
1213    "Date",
1214    "RegExp",
1215    "JSON",
1216    "Proxy",
1217    "Map",
1218    "Set",
1219    "WeakMap",
1220    "WeakSet",
1221    "ArrayBuffer",
1222    "SharedArrayBuffer",
1223    "Uint8ClampedArray",
1224    "Int8Array",
1225    "Uint8Array",
1226    "Int16Array",
1227    "Uint16Array",
1228    "Int32Array",
1229    "Uint32Array",
1230    "BigInt64Array",
1231    "BigUint64Array",
1232    "Float16Array",
1233    "Float32Array",
1234    "Float64Array",
1235    "DataView",
1236    "Atomics",
1237    "Promise",
1238    "WeakRef",
1239    "FinalizationRegistry",
1240];
1241
1242/// Puts the global object's properties in [`GLOBAL_ORDER`].
1243fn order_globals(cx: &mut Cx<'_>, global: ObjectId) -> Result<(), HeapError> {
1244    let mut keys = Vec::with_capacity(GLOBAL_ORDER.len());
1245    for name in GLOBAL_ORDER {
1246        keys.push(cx.heap.property_key(name)?);
1247    }
1248    debug_assert!(
1249        keys.iter()
1250            .all(|&key| cx.heap.lookup_own(global, key).is_some()),
1251        "every global in GLOBAL_ORDER is installed"
1252    );
1253    cx.heap.reorder_dictionary(global, &keys);
1254    Ok(())
1255}
1256
1257/// Defines `print` on the global object.
1258/// qjs's `print` and `console.log`.
1259pub(crate) fn install_print(cx: &mut Cx<'_>) -> Result<(), HeapError> {
1260    let mark = cx.heap.roots().mark();
1261    let result = (|| {
1262        let global = cx.realm.global();
1263        let print = native_function(cx, Native::Print)?;
1264        define(cx, global, "print", Value::object(print), hidden())?;
1265        let prototype = cx.realm.intrinsic(Intrinsic::ObjectPrototype);
1266        let console = plain_object(cx, Some(prototype), 1)?;
1267        let log = native_function(cx, Native::ConsoleLog)?;
1268        define(cx, console, "log", Value::object(log), hidden())?;
1269        define(cx, global, "console", Value::object(console), hidden())
1270    })();
1271    cx.heap.roots().truncate(mark);
1272    result
1273}
1274
1275/// qjs's `--std` helpers the suites' shells use: `load` and `read`.
1276pub(crate) fn install_std(cx: &mut Cx<'_>) -> Result<(), HeapError> {
1277    let mark = cx.heap.roots().mark();
1278    let result = (|| {
1279        let global = cx.realm.global();
1280        for native in [Native::Load, Native::Read] {
1281            let function = native_function(cx, native)?;
1282            define(
1283                cx,
1284                global,
1285                native.js_name(),
1286                Value::object(function),
1287                hidden(),
1288            )?;
1289        }
1290        Ok(())
1291    })();
1292    cx.heap.roots().truncate(mark);
1293    result
1294}
1295
1296/// qjs's `scriptArgs`: an array of the script's path and arguments.
1297pub(crate) fn install_script_args(cx: &mut Cx<'_>, args: &[String]) -> Result<(), HeapError> {
1298    let mark = cx.heap.roots().mark();
1299    let result = (|| {
1300        let array = script_args_array(cx, args)?;
1301        let global = cx.realm.global();
1302        define(cx, global, "scriptArgs", Value::object(array), hidden())
1303    })();
1304    cx.heap.roots().truncate(mark);
1305    result
1306}
1307
1308/// An array of `args` as strings, rooted.
1309fn script_args_array(cx: &mut Cx<'_>, args: &[String]) -> Result<ObjectId, HeapError> {
1310    let prototype = cx.realm.intrinsic(Intrinsic::ArrayPrototype);
1311    let array = cx.heap.alloc_array(Some(prototype), args.len() as u32)?;
1312    cx.heap.roots().push(Value::object(array));
1313    for (index, arg) in args.iter().enumerate() {
1314        let text = cx.heap.alloc_string(arg)?;
1315        cx.heap
1316            .set_element(array, index as u32, Value::string(text))?;
1317    }
1318    Ok(array)
1319}
1320
1321/// QuickJS's `js_std_add_helpers` as `qjs` runs it: `console` (with `log`),
1322/// `performance` (with `now`), `scriptArgs` when given, `print`, then
1323/// `__loadScript`, in that order, each writable, enumerable and
1324/// configurable (`JS_SetPropertyStr`).
1325pub(crate) fn install_qjs_helpers(
1326    cx: &mut Cx<'_>,
1327    script_args: Option<&[String]>,
1328) -> Result<(), HeapError> {
1329    let mark = cx.heap.roots().mark();
1330    let result = (|| {
1331        let global = cx.realm.global();
1332        let all = PropertyFlags::data(true, true, true);
1333        let prototype = cx.realm.intrinsic(Intrinsic::ObjectPrototype);
1334        let console = plain_object(cx, Some(prototype), 1)?;
1335        let log = native_function(cx, Native::ConsoleLog)?;
1336        define(cx, console, "log", Value::object(log), all)?;
1337        define(cx, global, "console", Value::object(console), all)?;
1338        let performance = plain_object(cx, Some(prototype), 1)?;
1339        let now = native_function(cx, Native::PerformanceNow)?;
1340        define(cx, performance, "now", Value::object(now), all)?;
1341        define(cx, global, "performance", Value::object(performance), all)?;
1342        if let Some(args) = script_args {
1343            let array = script_args_array(cx, args)?;
1344            define(cx, global, "scriptArgs", Value::object(array), all)?;
1345        }
1346        let print = native_function(cx, Native::Print)?;
1347        define(cx, global, "print", Value::object(print), all)?;
1348        let load_script = native_function(cx, Native::LoadScript)?;
1349        define(cx, global, "__loadScript", Value::object(load_script), all)
1350    })();
1351    cx.heap.roots().truncate(mark);
1352    result
1353}
1354
1355/// A typed array's length, or a `TypeError` when it is out of bounds.
1356pub(crate) fn typed_array_length_or_throw(cx: &mut Cx<'_>, object: ObjectId) -> Result<u64, Throw> {
1357    match crate::vm::typed::length(cx.heap, object) {
1358        Some(length) => Ok(length as u64),
1359        None => Err(vm_error::type_error(
1360            cx,
1361            "ArrayBuffer is detached or resized",
1362        )),
1363    }
1364}
1365
1366/// `$262.detachArrayBuffer(buffer)`.
1367pub(crate) fn detach_array_buffer(cx: &mut Cx<'_>, site: CallSite) -> Result<Value, Throw> {
1368    // QuickJS's `JS_DetachArrayBuffer`: anything but an ArrayBuffer is
1369    // ignored, and the result is `undefined`.
1370    let buffer = site.arg(cx, 0);
1371    let is_array_buffer = buffer.as_object().is_some_and(|object| {
1372        cx.heap.internal_tag(object) == crate::heap::object::InternalTag::ArrayBuffer
1373    });
1374    if is_array_buffer {
1375        buffer::detach(cx, buffer)?;
1376    }
1377    Ok(Value::UNDEFINED)
1378}
1379
1380pub(crate) use bigint::to_bigint;
1381pub(crate) use buffer::detach as detach_buffer;
1382pub(crate) use buffer::new_array_buffer;
1383pub(crate) use date::iso_string as date_iso_string;
1384pub(crate) use generator::async_from_sync_iterator;
1385pub(crate) use json::json_module_text;
1386pub(crate) use regexp::RegExpFlagCache;
1387
1388/// An ordinary object inheriting from `%Object.prototype%`, rooted.
1389pub(crate) fn new_plain(cx: &mut Cx<'_>, slots: u32) -> Result<ObjectId, Throw> {
1390    let prototype = cx.realm.intrinsic(Intrinsic::ObjectPrototype);
1391    cx.heap
1392        .alloc_object(ObjectKind::Ordinary, Some(prototype), slots)
1393        .map_err(|error| vm_error::heap_error(cx, error))
1394}