Skip to main content

js_component_bindgen/intrinsics/
mod.rs

1//! Intrinsics used from JS
2
3use std::collections::{BTreeSet, HashSet};
4use std::fmt::Write;
5
6use crate::source::Source;
7use crate::{TranspileOpts, uwrite, uwriteln};
8
9pub(crate) mod conversion;
10use conversion::ConversionIntrinsic;
11
12pub(crate) mod js_helper;
13use js_helper::JsHelperIntrinsic;
14
15pub(crate) mod webidl;
16use webidl::WebIdlIntrinsic;
17
18pub(crate) mod string;
19use string::StringIntrinsic;
20
21pub(crate) mod resource;
22use resource::ResourceIntrinsic;
23
24pub(crate) mod lift;
25use lift::LiftIntrinsic;
26
27pub(crate) mod lower;
28use lower::LowerIntrinsic;
29
30pub(crate) mod component;
31use component::ComponentIntrinsic;
32
33pub(crate) mod p3;
34use p3::async_future::AsyncFutureIntrinsic;
35use p3::async_stream::AsyncStreamIntrinsic;
36use p3::async_task::AsyncTaskIntrinsic;
37use p3::error_context::ErrCtxIntrinsic;
38use p3::host::HostIntrinsic;
39use p3::waitable::WaitableIntrinsic;
40
41/// List of all intrinsics that are used by these
42///
43/// These intrinsics refer to JS code that is included in order to make
44/// transpiled WebAssembly components and their imports/exports functional
45/// in the relevant JS context.
46#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
47pub enum Intrinsic {
48    JsHelper(JsHelperIntrinsic),
49    WebIdl(WebIdlIntrinsic),
50    Conversion(ConversionIntrinsic),
51    String(StringIntrinsic),
52    Resource(ResourceIntrinsic),
53    ErrCtx(ErrCtxIntrinsic),
54    AsyncTask(AsyncTaskIntrinsic),
55    Waitable(WaitableIntrinsic),
56    Lift(LiftIntrinsic),
57    Lower(LowerIntrinsic),
58    AsyncStream(AsyncStreamIntrinsic),
59    AsyncFuture(AsyncFutureIntrinsic),
60    Component(ComponentIntrinsic),
61    Host(HostIntrinsic),
62
63    // Polyfills
64    PromiseWithResolversPonyfill,
65
66    /// Enable debug logging
67    DebugLog,
68
69    /// Global setting for determinism (used in async)
70    GlobalAsyncDeterminism,
71
72    /// Randomly produce a boolean true/false
73    CoinFlip,
74
75    // Basic type helpers
76    ConstantI32Max,
77    ConstantI32Min,
78    TypeCheckValidI32,
79    TypeCheckAsyncFn,
80    AsyncFunctionCtor,
81
82    Base64Compile,
83    ClampGuest,
84    FetchCompile,
85
86    // Globals
87    SymbolCabiDispose,
88    SymbolCabiLower,
89    SymbolResourceHandle,
90    SymbolResourceRep,
91    SymbolDispose,
92    SymbolAsyncIterator,
93    SymbolIterator,
94    ScopeId,
95    HandleTables,
96
97    /// Class that conforms to a `ReadableStreams`-like interface and is usable externally
98    ///
99    /// This is normally the `ReadableStream` class provided by the platform itself.
100    PlatformReadableStreamClass,
101
102    // Global Initializers
103    FinalizationRegistryCreate,
104
105    // Global classes
106    ComponentError,
107
108    // WASI object helpers
109    GetErrorPayload,
110    GetErrorPayloadString,
111
112    /// Class that manages (and synchronizes) writes to managed buffers
113    ManagedBufferClass,
114
115    /// Buffer manager that is used to synchronize component writes
116    BufferManagerClass,
117
118    /// Global for an instantiated buffer manager singleton
119    GlobalBufferManager,
120
121    /// Reusable table structure for holding canonical ABI objects by their representation/identifier of (e.g. resources, waitables, etc)
122    ///
123    /// Representations of objects stored in one of these tables is a u32 (0 is expected to be an invalid index).
124    RepTableClass,
125
126    /// Event codes used for async, as a JS enum
127    AsyncEventCodeEnum,
128
129    // JS helper functions
130    IsLE,
131    ThrowInvalidBool,
132    ThrowUninitialized,
133    HasOwnProperty,
134    InstantiateCore,
135
136    /// Tracking of component memories
137    GlobalComponentMemoryMap,
138
139    /// Tracking of component memories
140    RegisterGlobalMemoryForComponent,
141
142    /// Tracking of component memories
143    LookupMemoriesForComponent,
144
145    /// Global that tracks the current task
146    GlobalCurrentTaskMeta,
147
148    /// Gets the current global task state
149    GetGlobalCurrentTaskMetaFn,
150
151    /// Gets the current global task state
152    SetGlobalCurrentTaskMetaFn,
153
154    /// Execute a closure with a certain set current task
155    WithGlobalCurrentTaskMetaFn,
156
157    /// Execute an async closure with a certain set current task
158    WithGlobalCurrentTaskMetaFnAsync,
159
160    /// Clear the global task meta
161    ClearGlobalCurrentTaskMetaFn,
162
163    /// Wrap the JS payload of a `WebAssembly.Suspending` import so the
164    /// importing component's current-task register survives suspension
165    SuspendingImportWrapperFn,
166}
167
168impl Intrinsic {
169    pub fn render(&self, output: &mut Source, args: &RenderIntrinsicsArgs) {
170        match self {
171            Intrinsic::JsHelper(i) => i.render(output, args),
172            Intrinsic::Conversion(i) => i.render(output, args),
173            Intrinsic::String(i) => i.render(output, args),
174            Intrinsic::ErrCtx(i) => i.render(output, args),
175            Intrinsic::Resource(i) => i.render(output, args),
176            Intrinsic::AsyncTask(i) => i.render(output, args),
177            Intrinsic::Waitable(i) => i.render(output, args),
178            Intrinsic::Lift(i) => i.render(output, args),
179            Intrinsic::Lower(i) => i.render(output, args),
180            Intrinsic::AsyncStream(i) => i.render(output, args),
181            Intrinsic::AsyncFuture(i) => i.render(output, args),
182            Intrinsic::Component(i) => i.render(output, args),
183            Intrinsic::Host(i) => i.render(output, args),
184
185            Intrinsic::GlobalAsyncDeterminism => {
186                uwriteln!(
187                    output,
188                    "const {var_name} = '{determinism}';",
189                    var_name = self.name(),
190                    determinism = args.determinism_profile,
191                );
192            }
193
194            Intrinsic::CoinFlip => {
195                uwriteln!(
196                    output,
197                    "const {var_name} = () => {{ return Math.random() > 0.5; }};",
198                    var_name = self.name(),
199                );
200            }
201
202            Intrinsic::ConstantI32Min => output.push_str(&format!(
203                "const {const_name} = -2_147_483_648;\n",
204                const_name = self.name()
205            )),
206
207            Intrinsic::ConstantI32Max => {
208                uwriteln!(
209                    output,
210                    r#"
211                      const {const_name} = 2_147_483_647;
212                    "#,
213                    const_name = self.name()
214                )
215            }
216
217            Intrinsic::TypeCheckValidI32 => {
218                let i32_const_min = Intrinsic::ConstantI32Min.name();
219                let i32_const_max = Intrinsic::ConstantI32Max.name();
220
221                uwriteln!(
222                    output,
223                    r#"
224                      const {fn_name} = (n) => typeof n === 'number' && n >= {i32_const_min} && n <= {i32_const_max};
225                    "#,
226                    fn_name = self.name()
227                );
228            }
229
230            Intrinsic::AsyncFunctionCtor => {
231                let async_fn_type = Intrinsic::AsyncFunctionCtor.name();
232                uwriteln!(
233                    output,
234                    "const {async_fn_type} = (async () => {{}}).constructor;"
235                );
236            }
237
238            Intrinsic::TypeCheckAsyncFn => {
239                let async_fn_check = Intrinsic::TypeCheckAsyncFn.name();
240                let async_fn_ctor = Intrinsic::AsyncFunctionCtor.name();
241                uwriteln!(
242                    output,
243                    r#"
244                    const {async_fn_check} = (f) => {{
245                        return f instanceof {async_fn_ctor};
246                    }};
247                    "#,
248                );
249            }
250
251            Intrinsic::Base64Compile => {
252                if !args.transpile_opts.nodejs_compat_disabled {
253                    uwriteln!(
254                        output,
255                        r#"
256                          const base64Compile = str => WebAssembly.compile(
257                              typeof Buffer !== 'undefined'
258                                  ? Buffer.from(str, 'base64')
259                                  : Uint8Array.from(atob(str), b => b.charCodeAt(0))
260                          );
261                        "#
262                    );
263                } else {
264                    uwriteln!(
265                        output,
266                        r#"
267                          const base64Compile = str => WebAssembly.compile(Uint8Array.from(atob(str), b => b.charCodeAt(0)));
268                        "#
269                    );
270                }
271            }
272
273            Intrinsic::ClampGuest => {
274                uwriteln!(
275                    output,
276                    r#"
277                      function clampGuest(i, min, max) {{
278                          if (i < min || i > max) {{
279                              throw new TypeError(`must be between ${{min}} and ${{max}}`);
280                          }}
281                          return i;
282                      }}
283                    "#
284                );
285            }
286
287            Intrinsic::ComponentError => output.push_str(
288                "
289                class ComponentError extends Error {
290                    constructor (value) {
291                        const enumerable = typeof value !== 'string';
292                        super(enumerable ? `${String(value)} (see error.payload)` : value);
293                        Object.defineProperty(this, 'payload', { value, enumerable });
294                    }
295                }
296            ",
297            ),
298
299            Intrinsic::FinalizationRegistryCreate => output.push_str(
300                "
301                function finalizationRegistryCreate (unregister) {
302                    if (typeof FinalizationRegistry === 'undefined') {
303                        return { unregister () {} };
304                    }
305                    return new FinalizationRegistry(unregister);
306                }
307            ",
308            ),
309
310            Intrinsic::FetchCompile => {
311                if !args.transpile_opts.nodejs_compat_disabled {
312                    output.push_str("
313                    const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
314                    let _fs;
315                    async function fetchCompile (url) {
316                        if (isNode) {
317                            _fs = _fs || await import('node:fs/promises');
318                            return WebAssembly.compile(await _fs.readFile(url));
319                        }
320                        return fetch(url).then(WebAssembly.compileStreaming);
321                    }
322                ")
323                } else {
324                    output.push_str(
325                        "
326                    const fetchCompile = url => fetch(url).then(WebAssembly.compileStreaming);
327                ",
328                    )
329                }
330            }
331
332            Intrinsic::GetErrorPayload => {
333                let hop = Intrinsic::HasOwnProperty.name();
334                uwrite!(
335                    output,
336                    "
337                    function getErrorPayload(e) {{
338                        if (e && {hop}.call(e, 'payload')) return e.payload;
339                        if (e instanceof Error) throw e;
340                        return e;
341                    }}
342                "
343                )
344            }
345
346            Intrinsic::GetErrorPayloadString => {
347                let hop = Intrinsic::HasOwnProperty.name();
348                uwrite!(
349                    output,
350                    "
351                    function getErrorPayloadString(e) {{
352                        if (e && {hop}.call(e, 'payload')) return e.payload;
353                        if (e instanceof Error) return e.message;
354                        return e;
355                    }}
356                "
357                )
358            }
359
360            Intrinsic::WebIdl(w) => w.render(output),
361
362            Intrinsic::HandleTables => {
363                let var_name = self.name();
364                uwriteln!(
365                    output,
366                    r#"
367                      const {var_name} = [];
368                    "#,
369                );
370            }
371
372            Intrinsic::HasOwnProperty => output.push_str(
373                "
374                const hasOwnProperty = Object.prototype.hasOwnProperty;
375            ",
376            ),
377
378            Intrinsic::InstantiateCore => {
379                if !args.instantiation_occurred {
380                    output.push_str(
381                        "
382                    const instantiateCore = WebAssembly.instantiate;
383                ",
384                    )
385                }
386            }
387
388            Intrinsic::IsLE => output.push_str(
389                "
390                const isLE = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
391            ",
392            ),
393
394            Intrinsic::SymbolCabiDispose => output.push_str(
395                "
396                const symbolCabiDispose = Symbol.for('cabiDispose');
397            ",
398            ),
399
400            Intrinsic::SymbolCabiLower => output.push_str(
401                "
402                const symbolCabiLower = Symbol.for('cabiLower');
403            ",
404            ),
405
406            Intrinsic::ScopeId => {
407                let name = self.name();
408                uwriteln!(output, "let {name} = 0;");
409            }
410
411            Intrinsic::SymbolResourceHandle => output.push_str(
412                "
413                const symbolRscHandle = Symbol('handle');
414            ",
415            ),
416
417            Intrinsic::SymbolResourceRep => output.push_str(
418                "
419                const symbolRscRep = Symbol.for('cabiRep');
420            ",
421            ),
422
423            Intrinsic::SymbolDispose => {
424                let var_name = self.name();
425                uwriteln!(
426                    output,
427                    "const {var_name} = Symbol.dispose || Symbol.for('dispose');"
428                );
429            }
430
431            Intrinsic::SymbolAsyncIterator => {
432                let var_name = self.name();
433                uwriteln!(output, "const {var_name} = Symbol.asyncIterator;");
434            }
435
436            Intrinsic::SymbolIterator => {
437                let var_name = self.name();
438                uwriteln!(output, "const {var_name} = Symbol.iterator;");
439            }
440
441            Intrinsic::ThrowInvalidBool => output.push_str(
442                "
443                function throwInvalidBool() {
444                    throw new TypeError('invalid variant discriminant for bool');
445                }
446            ",
447            ),
448
449            Intrinsic::ThrowUninitialized => output.push_str(
450                "
451                function throwUninitialized() {
452                    throw new TypeError('Wasm uninitialized use `await $init` first');
453                }
454            ",
455            ),
456
457            Intrinsic::DebugLog => {
458                let fn_name = Intrinsic::DebugLog.name();
459                output.push_str(&format!(
460                    "
461                    const {fn_name} = (...args) => {{
462                        if (!globalThis?.process?.env?.JCO_DEBUG) {{ return; }}
463                        console.debug(...args);
464                    }};
465                "
466                ));
467            }
468
469            Intrinsic::PromiseWithResolversPonyfill => {
470                let fn_name = self.name();
471                output.push_str(&format!(
472                    r#"
473                    function {fn_name}() {{
474                        if (Promise.withResolvers) {{
475                            return Promise.withResolvers();
476                        }} else {{
477                            let resolve;
478                            let reject;
479                            const promise = new Promise((res, rej) => {{
480                                resolve = res;
481                                reject = rej;
482                            }});
483                            return {{ promise, resolve, reject }};
484                        }}
485                    }}
486                "#
487                ));
488            }
489
490            Intrinsic::AsyncEventCodeEnum => {
491                let name = Intrinsic::AsyncEventCodeEnum.name();
492                output.push_str(&format!(
493                    "
494                    const {name} = {{
495                        NONE: 0,
496                        SUBTASK: 1,
497                        STREAM_READ: 2,
498                        STREAM_WRITE: 3,
499                        FUTURE_READ: 4,
500                        FUTURE_WRITE: 5,
501                        TASK_CANCELLED: 6,
502                    }};
503                "
504                ));
505            }
506
507            Intrinsic::ManagedBufferClass => {
508                let debug_log_fn = Intrinsic::DebugLog.name();
509                let managed_buffer_class = Intrinsic::ManagedBufferClass.name();
510                output.push_str(&format!(
511                    r#"
512                    class {managed_buffer_class} {{
513                        static MAX_LENGTH = 2**28 - 1;
514                        #componentIdx;
515                        #memory;
516
517                        #elemMeta = null;
518
519                        #start;
520                        #ptr;
521                        capacity;
522                        processed = 0;
523
524                        #hostOnlyData; // initial data (only filled out for host-owned)
525
526                        target;
527
528                        constructor(args) {{
529                            if (args.capacity > {managed_buffer_class}.MAX_LENGTH) {{
530                                 throw new Error(`buffer size [${{args.capacity}}] greater than max length`);
531                            }}
532                            if (args.componentIdx === undefined) {{ throw new TypeError('missing/invalid component idx'); }}
533                            if (args.capacity === undefined) {{ throw new TypeError('missing/invalid capacity'); }}
534                            if (!args.elemMeta || typeof args.elemMeta.align32 !== 'number') {{
535                                throw new TypeError('missing/invalid element metadata');
536                            }}
537
538                            if (!args.memory && args.start === undefined && args.data === undefined) {{
539                                throw new TypeError('either memory and start ptr or data must be provided for managed buffers');
540                            }}
541
542                            if (args.memory && args.start == undefined) {{
543                                throw new TypeError('missing/invalid start ptr, depsite memory being present');
544                            }}
545
546                            if (!args.elemMeta.isNone && args.capacity > 0) {{
547                                if (args.start && args.start % args.elemMeta.align32 !== 0) {{
548                                    throw new Error(`invalid alignment: type with 32bit alignment [${{args.elemMeta.align32}}] at starting pointer [${{args.start}}]`);
549                                }}
550                                // TODO: memory lenght bounds check
551                            }}
552
553                            this.#componentIdx = args.componentIdx;
554                            this.#memory = args.memory;
555                            this.#start = args.start;
556                            this.#ptr = this.#start;
557                            this.capacity = args.capacity;
558                            this.#elemMeta = args.elemMeta;
559
560                            if (args.data !== undefined && !Array.isArray(args.data)) {{
561                                throw new TypeError('host-only data must be an array');
562                            }}
563                            this.#hostOnlyData = args.data;
564
565                            this.target = args.target;
566                        }}
567
568                        setTarget(tgt) {{ this.target = tgt; }}
569
570                        remaining() {{
571                            return this.capacity - this.processed;
572                        }}
573
574                        componentIdx() {{ return this.#componentIdx; }}
575
576                        getElemMeta() {{ return this.#elemMeta; }}
577
578                        isHostOwned() {{ return !this.#memory; }}
579
580                        read(count) {{
581                            {debug_log_fn}('[{managed_buffer_class}#read()] args', {{ count }});
582                            if (count === undefined || count <= 0) {{
583                                throw new TypeError(`missing/invalid count [${{count}}]`);
584                            }}
585
586                            const cap = this.capacity;
587                            if (count > cap) {{
588                                throw new Error(`cannot read [${{count}}] elements from buffer with capacity [${{cap}}]`);
589                            }}
590
591                            let values = [];
592                            if (this.#elemMeta.isNone) {{
593                                values = [...new Array(count)].map(() => null);
594                            }} else {{
595                                if (this.isHostOwned()) {{
596                                    values = this.#hostOnlyData.slice(0, count);
597                                    this.#hostOnlyData = this.#hostOnlyData.slice(count);
598                                }} else if (this.#elemMeta.payloadTypeName === 'U8') {{
599                                    values = Array.from(new Uint8Array(this.#memory.buffer, this.#ptr, count));
600                                    this.#ptr += count;
601                                }} else {{
602                                    let currentCount = count;
603                                    let startPtr = this.#ptr;
604                                    if (this.#elemMeta.stringEncoding === undefined) {{
605                                        throw new Error('string encoding unknown during read');
606                                    }}
607                                    let liftCtx = {{
608                                        storagePtr: startPtr,
609                                        memory: this.#memory,
610                                        componentIdx: this.#componentIdx,
611                                        stringEncoding: this.#elemMeta.stringEncoding,
612                                    }};
613                                    if (currentCount < 0) {{ throw new Error('unexpectedly invalid count'); }}
614                                    while (currentCount > 0) {{
615                                        const [value, _ctx] = this.#elemMeta.liftFn(liftCtx);
616                                        values.push(value);
617                                        currentCount -= 1;
618                                    }}
619                                    this.#ptr = liftCtx.storagePtr;
620                                }}
621                            }}
622
623                            this.processed += count;
624                            return values;
625                        }}
626
627                        write(values) {{
628                            {debug_log_fn}('[{managed_buffer_class}#write()] args', {{ values }});
629
630                            if (!Array.isArray(values)) {{ throw new TypeError('values input to write() must be an array'); }}
631                            let rc = this.remaining();
632                            if (values.length > rc) {{
633                                throw new Error(`cannot write [${{values.length}}] elements to managed buffer with remaining capacity [${{rc}}]`);
634                            }}
635
636                            if (this.#elemMeta.isNone) {{
637                                if (!values.every(v => v === null)) {{
638                                    throw new Error('non-null values in write() to unit managed buffer');
639                                }}
640                            }} else {{
641                                if (this.isHostOwned()) {{
642                                    this.#hostOnlyData = this.#hostOnlyData.concat(values);
643                                }} else if (this.#elemMeta.payloadTypeName === 'U8') {{
644                                    new Uint8Array(this.#memory.buffer, this.#ptr, values.length).set(values);
645                                    this.#ptr += values.length;
646                                }} else {{
647                                    let startPtr = this.#ptr;
648                                    if (this.#elemMeta.stringEncoding === undefined) {{
649                                        throw new Error('string encoding unknown during write');
650                                    }}
651
652                                    const lowerCtx = {{
653                                        memory: this.#memory,
654                                        storagePtr: startPtr,
655                                        componentIdx: this.#componentIdx,
656                                        stringEncoding: this.#elemMeta.stringEncoding,
657                                        realloc: this.#elemMeta.getReallocFn?.(),
658                                        getReallocFn: this.#elemMeta.getReallocFn,
659                                    }}
660                                    for (const v of values) {{
661                                        lowerCtx.vals = [v];
662                                        this.#elemMeta.lowerFn(lowerCtx);
663                                    }}
664
665                                    this.#ptr = lowerCtx.storagePtr;
666                                }}
667                            }}
668
669                            this.processed += values.length;
670                        }}
671
672                    }}
673                "#
674                ));
675            }
676
677            Intrinsic::BufferManagerClass => {
678                let debug_log_fn = Intrinsic::DebugLog.name();
679                let buffer_manager_class = Intrinsic::BufferManagerClass.name();
680                let managed_buffer_class = Intrinsic::ManagedBufferClass.name();
681
682                output.push_str(&format!(r#"
683                    class {buffer_manager_class} {{
684                        #buffers = new Map();
685                        #bufferIDs = new Map();
686
687                        // NOTE: componentIdx === -1 indicates the host
688                        getNextBufferID(componentIdx) {{
689                            const current = this.#bufferIDs.get(componentIdx);
690                            if (current === undefined) {{
691                                this.#bufferIDs.set(componentIdx, 1n);
692                                return 1n;
693                            }}
694                            const next = current + 1n;
695                            this.#bufferIDs.set(componentIdx, next);
696                            return next;
697                        }}
698
699                        getBuffer(componentIdx, bufferID) {{
700                            {debug_log_fn}('[{buffer_manager_class}#getBuffer()] args', {{ componentIdx, bufferID }});
701                            return this.#buffers.get(componentIdx)?.get(bufferID);
702                        }}
703
704                        createBuffer(args) {{
705                            {debug_log_fn}('[{buffer_manager_class}#createBuffer()] args', args);
706                            if (!args || typeof args !== 'object') {{ throw new TypeError('missing/invalid argument object'); }}
707
708                            if (args.start === undefined && args.data === undefined) {{
709                                throw new  TypeError('either a starting pointer or initial values must be provided');
710                            }}
711
712                            if (args.start !== undefined && args.componentIdx === undefined) {{ throw new TypeError('missing/invalid component idx'); }}
713                            if (args.count === undefined) {{ throw new TypeError('missing/invalid obj count'); }}
714                            if (!args.elemMeta) {{ throw new TypeError('missing/invalid element metadata for use with managed buffer'); }}
715
716                            const {{ componentIdx, data, start, count }} = args;
717
718                            if (!this.#buffers.has(componentIdx)) {{ this.#buffers.set(componentIdx, new Map()); }}
719                            const instanceBuffers = this.#buffers.get(componentIdx);
720
721                            const nextBufID = this.getNextBufferID(componentIdx);
722
723                            const buffer = new {managed_buffer_class}({{
724                                componentIdx,
725                                memory: args.memory,
726                                start: args.start,
727                                capacity: args.count,
728                                elemMeta: args.elemMeta,
729                                data: args.data,
730                                target: args.target,
731                                stringEncoding: args.stringEncoding,
732                            }});
733
734                            if (instanceBuffers.has(nextBufID)) {{
735                                throw new Error(`managed buffer with ID [${{nextBufID}}] already exists`);
736                            }}
737                            instanceBuffers.set(nextBufID, buffer);
738
739                            return {{ id: nextBufID, buffer }};
740                        }}
741
742                        deleteBuffer(componentIdx, bufferID) {{
743                            {debug_log_fn}('[{buffer_manager_class}#deleteBuffer()] args', {{ componentIdx, bufferID }});
744                            return this.#buffers.get(componentIdx)?.delete(bufferID);
745                        }}
746
747                    }}
748                "#));
749            }
750
751            Intrinsic::GlobalBufferManager => {
752                let global_buffer_manager = Intrinsic::GlobalBufferManager.name();
753                let buffer_manager_class = Intrinsic::BufferManagerClass.name();
754                output.push_str(&format!(
755                    "const {global_buffer_manager} = new {buffer_manager_class}();"
756                ));
757            }
758
759            Intrinsic::RepTableClass => {
760                let debug_log_fn = Intrinsic::DebugLog.name();
761                let rep_table_class = Intrinsic::RepTableClass.name();
762                output.push_str(&format!(r#"
763                    class {rep_table_class} {{
764                        // Sentinel marking a freed slot; the freelist link for a freed slot
765                        // lives in the odd cell. This keeps get()/contains()/remove() on freed
766                        // reps well-defined (previously they returned/corrupted freelist links).
767                        static FREE = Symbol('{rep_table_class}.free');
768
769                        #data = [0, null];
770                        #size = 0;
771                        #target;
772
773                        constructor(args) {{
774                            this.target = args?.target;
775                        }}
776
777                        data() {{ return this.#data; }}
778
779                        insert(val) {{
780                            {debug_log_fn}('[{rep_table_class}#insert()] args', {{ val, target: this.target }});
781                            const freeIdx = this.#data[0];
782                            if (freeIdx === 0) {{
783                                this.#data.push(val);
784                                this.#data.push(null);
785                                const rep = (this.#data.length >> 1) - 1;
786                                {debug_log_fn}('[{rep_table_class}#insert()] inserted', {{ val, target: this.target, rep }});
787                                this.#size += 1;
788                                return rep;
789                            }}
790                            const placementIdx = freeIdx << 1;
791                            if (this.#data[placementIdx] !== {rep_table_class}.FREE) {{
792                                throw new Error('corrupt rep table freelist: head does not point at a freed slot');
793                            }}
794                            this.#data[0] = this.#data[placementIdx + 1];
795                            this.#data[placementIdx] = val;
796                            this.#data[placementIdx + 1] = null;
797                            {debug_log_fn}('[{rep_table_class}#insert()] inserted', {{ val, target: this.target, rep: freeIdx }});
798                            this.#size += 1;
799                            return freeIdx;
800                        }}
801
802                        get(rep) {{
803                            {debug_log_fn}('[{rep_table_class}#get()] args', {{ rep, target: this.target }});
804                            if (rep === 0) {{ throw new Error('invalid resource rep during get, (cannot be 0)'); }}
805
806                            const baseIdx = rep << 1;
807                            const val = this.#data[baseIdx];
808                            if (val === {rep_table_class}.FREE) {{ return undefined; }}
809                            return val;
810                        }}
811
812                        contains(rep) {{
813                            {debug_log_fn}('[{rep_table_class}#contains()] args', {{ rep, target: this.target }});
814                            if (rep === 0) {{ throw new Error('invalid resource rep during contains, (cannot be 0)'); }}
815
816                            const baseIdx = rep << 1;
817                            const val = this.#data[baseIdx];
818                            return val !== {rep_table_class}.FREE && !!val;
819                        }}
820
821                        remove(rep) {{
822                            {debug_log_fn}('[{rep_table_class}#remove()] args', {{ rep, target: this.target }});
823                            if (rep === 0) {{ throw new Error('invalid resource rep during remove, (cannot be 0)'); }}
824                            if (this.#data.length === 2) {{ throw new Error('invalid'); }}
825
826                            const baseIdx = rep << 1;
827                            if (baseIdx >= this.#data.length) {{
828                                throw new Error(`invalid rep [${{rep}}] during remove, out of range`);
829                            }}
830                            const val = this.#data[baseIdx];
831                            if (val === {rep_table_class}.FREE) {{
832                                throw new Error(`double removal of rep [${{rep}}] (already freed)`);
833                            }}
834
835                            this.#data[baseIdx] = {rep_table_class}.FREE;
836                            this.#data[baseIdx + 1] = this.#data[0];
837                            this.#data[0] = rep;
838                            this.#size -= 1;
839
840                            return val;
841                        }}
842
843                        size() {{ return this.#size; }}
844
845                        clear() {{
846                            {debug_log_fn}('[{rep_table_class}#clear()] args', {{ rep, target: this.target }});
847                            this.#data = [0, null];
848                        }}
849                    }}
850                "#));
851            }
852
853            Intrinsic::GlobalComponentMemoryMap => {
854                let global_component_memory_map = Intrinsic::GlobalComponentMemoryMap.name();
855                output.push_str(&format!(
856                    "const {global_component_memory_map} = new Map();\n"
857                ));
858            }
859
860            Intrinsic::RegisterGlobalMemoryForComponent => {
861                let global_component_memory_map = Intrinsic::GlobalComponentMemoryMap.name();
862                let register_global_component_memory =
863                    Intrinsic::RegisterGlobalMemoryForComponent.name();
864                output.push_str(&format!(
865                    r#"
866                      function {register_global_component_memory}(args) {{
867                          const {{ componentIdx, memory, memoryIdx }} = args ?? {{}};
868                          if (componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
869                          if (memory === undefined && memoryIdx === undefined) {{ throw new TypeError('missing both memory & memory idx'); }}
870                          let inner = {global_component_memory_map}.get(componentIdx);
871                          if (!inner) {{
872                              inner = {{}};
873                              {global_component_memory_map}.set(componentIdx, inner);
874                          }}
875
876                          inner[memoryIdx] = {{ memory, memoryIdx, componentIdx }};
877                      }}
878                    "#)
879                );
880            }
881
882            Intrinsic::LookupMemoriesForComponent => {
883                let global_component_memory_map = Intrinsic::GlobalComponentMemoryMap.name();
884                let lookup_global_memories_for_component =
885                    Intrinsic::LookupMemoriesForComponent.name();
886                output.push_str(&format!(
887                    r#"
888                      function {lookup_global_memories_for_component}(args) {{
889                          const {{ componentIdx }} = args ?? {{}};
890                          if (args.componentIdx === undefined) {{ throw new TypeError("missing component idx"); }}
891
892                          const metas = {global_component_memory_map}.get(componentIdx);
893                          if (!metas) {{ return []; }}
894
895                          if (args.memoryIdx === undefined) {{
896                              return Object.values(metas);
897                          }}
898
899                          const meta = metas[args.memoryIdx];
900                          return meta?.memory;
901                      }}
902                    "#)
903                );
904            }
905
906            Self::GlobalCurrentTaskMeta => {
907                let name = self.name();
908                output.push_str(&format!("const {name} = {{}};\n"));
909            }
910
911            Self::GetGlobalCurrentTaskMetaFn => {
912                let get_current_global_task_meta_fn = Self::GetGlobalCurrentTaskMetaFn.name();
913                let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
914
915                uwriteln!(
916                    output,
917                    r#"
918                      function {get_current_global_task_meta_fn}(componentIdx) {{
919                          if (componentIdx === null || componentIdx === undefined) {{
920                              throw new Error("missing/invalid component idx");
921                          }}
922                          const v = {global_current_task_meta_obj}[componentIdx];
923                          if (v === undefined || v === null) {{
924                              return undefined;
925                          }}
926                          return {{ ...v }};
927                      }}
928                    "#,
929                );
930            }
931
932            Self::SetGlobalCurrentTaskMetaFn => {
933                let set_global_current_task_meta_fn = self.name();
934                let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
935
936                uwriteln!(
937                    output,
938                    r#"
939                      function {set_global_current_task_meta_fn}(args) {{
940                          if (!args) {{ throw new TypeError('args missing'); }}
941                          if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
942                          if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
943                          const {{ taskID, componentIdx }} = args;
944                          return {global_current_task_meta_obj}[componentIdx] = {{ taskID, componentIdx }};
945                      }}
946                    "#,
947                );
948            }
949
950            Self::WithGlobalCurrentTaskMetaFn => {
951                let debug_log_fn = Intrinsic::DebugLog.name();
952                let with_global_current_task_meta_fn = Self::WithGlobalCurrentTaskMetaFn.name();
953                let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
954
955                output.push_str(&format!(
956                    r#"
957                      function {with_global_current_task_meta_fn}(args) {{
958                          {debug_log_fn}('[{with_global_current_task_meta_fn}()] args', args);
959                          if (!args) {{ throw new TypeError('args missing'); }}
960                          if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
961                          if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
962                          if (!args.fn) {{ throw new TypeError('missing fn'); }}
963                          const {{ taskID, componentIdx, fn }} = args;
964
965                          try {{
966                              {global_current_task_meta_obj}[componentIdx] = {{ taskID, componentIdx }};
967                              return fn();
968                          }} catch (err) {{
969                              {debug_log_fn}("error while executing sync callee/callback", {{
970                                  ...args,
971                                  err,
972                              }});
973                              throw err;
974                          }} finally {{
975                              {global_current_task_meta_obj}[componentIdx] = null;
976                          }}
977                      }}
978                    "#,
979                ));
980            }
981
982            // NOTE: this function wrapper/closure intrinsic essentially acts as a
983            // defactor task queue, ensuring that the right "current task" is set when
984            // callees and/or callbacks (WebAssembly functions) run.
985            //
986            // The idea here is to avoid creating *our own* centralized task queue/event loop,
987            // and allow the underlying JS runtime (NodeJS, Browser) to do it's normal scheduling.
988            //
989            // This costs us complexity -- an `await`/`.then()`/etc anywhere else could park a
990            // runtime task and bring us here, in which case we'd be executing *right* before a completely
991            // unrelated task (this matters most when it's multiple tasks in the same component idx)
992            //
993            // e.g.:
994            // 1. [componentIdx 1, task 2] entered -- it's async so this is an `await task.enter()`
995            // 2. JS runtime switches away from that task
996            // 3. [componentIdx 1, task 1] already running, and is about to run it's callee or a callback
997            //
998            // At (3), we must be careful because the "current" thread is *not* [componentIdx 1, task 1] which
999            // is about to try to run it's callback.
1000            //
1001            // This is complicated because when two tasks run at the same time, we have to ensure that the component
1002            // is not exclusively locked by one task. This generally happens @ task.enter(), but an interleaving
1003            // of events in which this check happens, then *another* task attempts to exclusively lock could happen.
1004            //
1005            // In the future, this mechanism may be replaced with a simple event loop that necessarily executes
1006            // all pending work serially, with this intrinsic becoming simply queueing work onto that event loop.
1007            //
1008            Self::WithGlobalCurrentTaskMetaFnAsync => {
1009                let debug_log_fn = Intrinsic::DebugLog.name();
1010                let with_global_current_task_meta_async_fn =
1011                    Self::WithGlobalCurrentTaskMetaFnAsync.name();
1012                let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
1013
1014                output.push_str(&format!(
1015                    r#"
1016                      async function {with_global_current_task_meta_async_fn}(args) {{
1017                          {debug_log_fn}('[{with_global_current_task_meta_async_fn}()] args', args);
1018                          if (!args) {{ throw new TypeError('args missing'); }}
1019                          if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
1020                          if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
1021                          if (!args.fn) {{ throw new TypeError('missing fn'); }}
1022
1023                          const {{ taskID, componentIdx, fn }} = args;
1024
1025                          try {{
1026                              {global_current_task_meta_obj}[componentIdx] = {{ taskID, componentIdx }};
1027                              return await fn();
1028                          }} catch (err) {{
1029                              {debug_log_fn}("error while executing async callee/callback", {{
1030                                  ...args,
1031                                  err,
1032                              }});
1033                              throw err;
1034                          }} finally {{
1035                              {global_current_task_meta_obj}[componentIdx] = null;
1036                          }}
1037                      }}
1038                    "#,
1039                ));
1040            }
1041
1042            Self::ClearGlobalCurrentTaskMetaFn => {
1043                let debug_log_fn = Intrinsic::DebugLog.name();
1044                let clear_global_current_task_meta_fn = Self::ClearGlobalCurrentTaskMetaFn.name();
1045                let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
1046
1047                output.push_str(&format!(
1048                    r#"
1049                      async function {clear_global_current_task_meta_fn}(args) {{
1050                          {debug_log_fn}('[{clear_global_current_task_meta_fn}()] args', args);
1051                          if (!args) {{ throw new TypeError('args missing'); }}
1052                          if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
1053                          if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
1054                          const {{ taskID, componentIdx }} = args;
1055
1056                          const meta = {global_current_task_meta_obj}[componentIdx];
1057                          if (!meta) {{ throw new Error(`missing current task meta for component idx [${{componentIdx}}]`); }}
1058
1059                          if (meta.taskID !== taskID) {{
1060                              throw new Error(`task ID [${{meta.taskID}}] != requested ID [${{taskID}}]`);
1061                          }}
1062                          if (meta.componentIdx !== componentIdx) {{
1063                              throw new Error(`component idx [${{meta.componentIdx}}] != requested idx [${{componentIdx}}]`);
1064                          }}
1065
1066                          {global_current_task_meta_obj}[componentIdx] = null;
1067                      }}
1068                    "#,
1069                ));
1070            }
1071
1072            // Under JSPI a wasm stack suspends inside a task's callback
1073            // slice; other tasks then set the per-component current-task
1074            // register. Restoring the captured entry when the awaited
1075            // import settles is the last JS to run before the suspended
1076            // stack resumes, so the resumed continuation's context.get /
1077            // context.set (and task-exit bookkeeping) address the task
1078            // that is actually executing.
1079            Self::SuspendingImportWrapperFn => {
1080                let suspending_import_wrapper_fn = Self::SuspendingImportWrapperFn.name();
1081                let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
1082
1083                output.push_str(&format!(
1084                    r#"
1085                      function {suspending_import_wrapper_fn}(componentIdx, fn) {{
1086                          return async function (...args) {{
1087                              const saved = {global_current_task_meta_obj}[componentIdx] ?? null;
1088                              try {{
1089                                  return await fn.apply(null, args);
1090                              }} finally {{
1091                                  {global_current_task_meta_obj}[componentIdx] = saved;
1092                              }}
1093                          }};
1094                      }}
1095                    "#,
1096                ));
1097            }
1098
1099            // TODO(feat): customizable stream classes
1100            Intrinsic::PlatformReadableStreamClass => {
1101                let name = self.name();
1102                uwriteln!(
1103                    output,
1104                    r#"
1105                        if (!ReadableStream) {{
1106                            throw new Error('builtin stream class [ReadableStream] is not available');
1107                        }}
1108                        const {name} = ReadableStream;
1109                    "#
1110                );
1111            }
1112        }
1113    }
1114}
1115
1116/// Profile for determinism to be used by async implementation
1117#[derive(Debug, Default, PartialEq, Eq)]
1118pub enum AsyncDeterminismProfile {
1119    /// Allow random ordering non-determinism
1120    #[default]
1121    Random,
1122
1123    /// Require determinism
1124    #[allow(unused)]
1125    Deterministic,
1126}
1127
1128impl std::fmt::Display for AsyncDeterminismProfile {
1129    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1130        write!(
1131            f,
1132            "{}",
1133            match self {
1134                Self::Deterministic => "deterministic",
1135                Self::Random => "random",
1136            }
1137        )
1138    }
1139}
1140
1141/// Arguments to `render_intrinsics`
1142#[derive(bon::Builder)]
1143#[non_exhaustive]
1144pub struct RenderIntrinsicsArgs<'a> {
1145    /// List of intrinsics being built for use
1146    pub(crate) intrinsics: &'a mut BTreeSet<Intrinsic>,
1147    /// Whether instantiation has occurred
1148    #[builder(default)]
1149    pub(crate) instantiation_occurred: bool,
1150    /// The kind of determinism to use
1151    #[builder(default)]
1152    pub(crate) determinism_profile: AsyncDeterminismProfile,
1153    /// Options provided when performing transpilation
1154    pub(crate) transpile_opts: &'a TranspileOpts,
1155}
1156
1157/// Intrinsics that should be rendered as early as possible
1158const EARLY_INTRINSICS: [Intrinsic; 44] = [
1159    Intrinsic::PromiseWithResolversPonyfill,
1160    Intrinsic::SymbolDispose,
1161    Intrinsic::SymbolAsyncIterator,
1162    Intrinsic::SymbolIterator,
1163    Intrinsic::DebugLog,
1164    Intrinsic::GlobalAsyncDeterminism,
1165    Intrinsic::GlobalComponentMemoryMap,
1166    Intrinsic::GlobalCurrentTaskMeta,
1167    Intrinsic::GetGlobalCurrentTaskMetaFn,
1168    Intrinsic::SetGlobalCurrentTaskMetaFn,
1169    Intrinsic::WithGlobalCurrentTaskMetaFn,
1170    Intrinsic::WithGlobalCurrentTaskMetaFnAsync,
1171    Intrinsic::ClearGlobalCurrentTaskMetaFn,
1172    Intrinsic::SuspendingImportWrapperFn,
1173    Intrinsic::LookupMemoriesForComponent,
1174    Intrinsic::RegisterGlobalMemoryForComponent,
1175    Intrinsic::RepTableClass,
1176    Intrinsic::CoinFlip,
1177    Intrinsic::ScopeId,
1178    // Type checking helpers
1179    Intrinsic::ConstantI32Min,
1180    Intrinsic::ConstantI32Max,
1181    Intrinsic::Conversion(ConversionIntrinsic::IsValidNumericPrimitive),
1182    Intrinsic::Conversion(ConversionIntrinsic::RequireValidNumericPrimitive),
1183    Intrinsic::TypeCheckValidI32,
1184    Intrinsic::TypeCheckAsyncFn,
1185    // Resources
1186    Intrinsic::Resource(ResourceIntrinsic::ResourceCallBorrows),
1187    // Async helpers
1188    Intrinsic::AsyncFunctionCtor,
1189    Intrinsic::AsyncTask(AsyncTaskIntrinsic::ClearCurrentTask),
1190    Intrinsic::AsyncTask(AsyncTaskIntrinsic::CurrentTaskMayBlock),
1191    Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskIds),
1192    Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentComponentIdxs),
1193    Intrinsic::AsyncTask(AsyncTaskIntrinsic::UnpackCallbackResult),
1194    Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncSubtaskClass),
1195    // Host helpers
1196    Intrinsic::Host(HostIntrinsic::PrepareCall),
1197    Intrinsic::Host(HostIntrinsic::AsyncStartCall),
1198    Intrinsic::Host(HostIntrinsic::SyncStartCall),
1199    // Waitable helpers
1200    Intrinsic::Waitable(WaitableIntrinsic::WaitableClass),
1201    // Error context helpers
1202    Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalErrCtxTableMap),
1203    // Context get/set are not used via trampolines but are
1204    // `UnsafeIntrinsic`s, so they are mapped for any module that uses them
1205    Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextGet),
1206    Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextSet),
1207    // Required for context.{get,set}
1208    Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskMap),
1209    Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass),
1210    Intrinsic::AsyncEventCodeEnum,
1211    Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask),
1212];
1213
1214/// Emits the intrinsic `i` to this file and then returns the name of the
1215/// intrinsic.
1216pub fn render_intrinsics(args: RenderIntrinsicsArgs) -> Source {
1217    let mut output = Source::default();
1218    let mut rendered_intrinsics = HashSet::new();
1219
1220    // Render some early intrinsics
1221    for intrinsic in EARLY_INTRINSICS {
1222        intrinsic.render(&mut output, &args);
1223        rendered_intrinsics.insert(intrinsic.name());
1224    }
1225
1226    // Add intrinsics to the list we must render
1227    if args.intrinsics.contains(&Intrinsic::GetErrorPayload)
1228        || args.intrinsics.contains(&Intrinsic::GetErrorPayloadString)
1229    {
1230        args.intrinsics.insert(Intrinsic::HasOwnProperty);
1231    }
1232    if args
1233        .intrinsics
1234        .contains(&Intrinsic::String(StringIntrinsic::Utf16Encode))
1235    {
1236        args.intrinsics.insert(Intrinsic::IsLE);
1237    }
1238
1239    if args
1240        .intrinsics
1241        .contains(&Intrinsic::Conversion(ConversionIntrinsic::F32ToI32))
1242        || args
1243            .intrinsics
1244            .contains(&Intrinsic::Conversion(ConversionIntrinsic::I32ToF32))
1245    {
1246        output.push_str(
1247            "
1248            const i32ToF32I = new Int32Array(1);
1249            const i32ToF32F = new Float32Array(i32ToF32I.buffer);
1250        ",
1251        );
1252    }
1253
1254    if args
1255        .intrinsics
1256        .contains(&Intrinsic::Conversion(ConversionIntrinsic::F64ToI64))
1257        || args
1258            .intrinsics
1259            .contains(&Intrinsic::Conversion(ConversionIntrinsic::I64ToF64))
1260    {
1261        output.push_str(
1262            "
1263            const i64ToF64I = new BigInt64Array(1);
1264            const i64ToF64F = new Float64Array(i64ToF64I.buffer);
1265        ",
1266        );
1267    }
1268
1269    if args.intrinsics.contains(&Intrinsic::Resource(
1270        ResourceIntrinsic::ResourceTransferBorrow,
1271    )) || args.intrinsics.contains(&Intrinsic::Resource(
1272        ResourceIntrinsic::ResourceTransferBorrowValidLifting,
1273    )) {
1274        args.intrinsics.insert(Intrinsic::Resource(
1275            ResourceIntrinsic::ResourceTableCreateBorrow,
1276        ));
1277    }
1278
1279    if args
1280        .intrinsics
1281        .contains(&Intrinsic::String(StringIntrinsic::Utf8Encode))
1282        || args
1283            .intrinsics
1284            .contains(&Intrinsic::String(StringIntrinsic::Utf8EncodeAsync))
1285    {
1286        args.intrinsics.extend([
1287            &Intrinsic::IsLE,
1288            &Intrinsic::String(StringIntrinsic::GlobalTextEncoderUtf8),
1289        ]);
1290    }
1291
1292    if args
1293        .intrinsics
1294        .contains(&Intrinsic::String(StringIntrinsic::Utf16Encode))
1295        || args
1296            .intrinsics
1297            .contains(&Intrinsic::String(StringIntrinsic::Utf16EncodeAsync))
1298    {
1299        args.intrinsics.extend([&Intrinsic::IsLE]);
1300    }
1301
1302    // Attempting to perform a debug message hoist will require string encoding to memory
1303    if args.intrinsics.contains(&Intrinsic::ErrCtx(
1304        ErrCtxIntrinsic::ErrorContextDebugMessage,
1305    )) {
1306        args.intrinsics.extend([
1307            &Intrinsic::String(StringIntrinsic::Utf8Encode),
1308            &Intrinsic::String(StringIntrinsic::Utf16Encode),
1309            &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
1310        ]);
1311    }
1312
1313    if args
1314        .intrinsics
1315        .contains(&Intrinsic::ErrCtx(ErrCtxIntrinsic::ErrorContextNew))
1316    {
1317        args.intrinsics.extend([
1318            &Intrinsic::ErrCtx(ErrCtxIntrinsic::ComponentGlobalTable),
1319            &Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalRefCountAdd),
1320            &Intrinsic::ErrCtx(ErrCtxIntrinsic::ReserveGlobalRep),
1321            &Intrinsic::ErrCtx(ErrCtxIntrinsic::CreateLocalHandle),
1322            &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
1323        ]);
1324    }
1325
1326    if args.intrinsics.contains(&Intrinsic::ErrCtx(
1327        ErrCtxIntrinsic::ErrorContextDebugMessage,
1328    )) {
1329        args.intrinsics.extend([
1330            &Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalRefCountAdd),
1331            &Intrinsic::ErrCtx(ErrCtxIntrinsic::ErrorContextDrop),
1332            &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
1333        ]);
1334    }
1335
1336    if args
1337        .intrinsics
1338        .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::DriverLoop))
1339    {
1340        args.intrinsics.extend([
1341            &Intrinsic::TypeCheckValidI32,
1342            &Intrinsic::Conversion(ConversionIntrinsic::ToInt32),
1343            &Intrinsic::Component(ComponentIntrinsic::ComponentStateSetAllError),
1344        ]);
1345    }
1346
1347    if args.intrinsics.contains(&Intrinsic::Component(
1348        ComponentIntrinsic::GetOrCreateAsyncState,
1349    )) {
1350        args.intrinsics.extend([&Intrinsic::RepTableClass]);
1351    }
1352
1353    if args
1354        .intrinsics
1355        .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass))
1356    {
1357        args.intrinsics.extend([
1358            &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1359            &Intrinsic::Component(ComponentIntrinsic::GlobalAsyncStateMap),
1360            &Intrinsic::RepTableClass,
1361            &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncSubtaskClass),
1362            &Intrinsic::Waitable(WaitableIntrinsic::WaitableClass),
1363            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureValueClass),
1364        ]);
1365    }
1366
1367    if args
1368        .intrinsics
1369        .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetNew))
1370    {
1371        args.intrinsics
1372            .extend([&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetClass)]);
1373    }
1374
1375    if args
1376        .intrinsics
1377        .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetPoll))
1378        || args
1379            .intrinsics
1380            .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetWait))
1381    {
1382        args.intrinsics
1383            .extend([&Intrinsic::Host(HostIntrinsic::StoreEventInComponentMemory)]);
1384    }
1385
1386    if args
1387        .intrinsics
1388        .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetDrop))
1389    {
1390        args.intrinsics
1391            .extend([&Intrinsic::Waitable(WaitableIntrinsic::RemoveWaitableSet)]);
1392    }
1393
1394    if args.intrinsics.contains(&Intrinsic::Component(
1395        ComponentIntrinsic::GetOrCreateAsyncState,
1396    )) {
1397        args.intrinsics.extend([
1398            &Intrinsic::Component(ComponentIntrinsic::ComponentAsyncStateClass),
1399            &Intrinsic::Component(ComponentIntrinsic::GlobalAsyncStateMap),
1400        ]);
1401    }
1402
1403    if args.intrinsics.contains(&Intrinsic::Component(
1404        ComponentIntrinsic::ComponentAsyncStateClass,
1405    )) {
1406        args.intrinsics.extend([&Intrinsic::AsyncStream(
1407            AsyncStreamIntrinsic::GlobalStreamMap,
1408        )]);
1409    }
1410
1411    if args
1412        .intrinsics
1413        .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatResult))
1414        | args
1415            .intrinsics
1416            .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatOption))
1417        | args
1418            .intrinsics
1419            .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatEnum))
1420    {
1421        args.intrinsics
1422            .extend([&Intrinsic::Lift(LiftIntrinsic::LiftFlatVariant)]);
1423    }
1424
1425    if args
1426        .intrinsics
1427        .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatVariant))
1428    {
1429        args.intrinsics.extend([
1430            &Intrinsic::Lift(LiftIntrinsic::LiftFlatU8),
1431            &Intrinsic::Lift(LiftIntrinsic::LiftFlatU16),
1432            &Intrinsic::Lift(LiftIntrinsic::LiftFlatU32),
1433            &Intrinsic::Lift(LiftIntrinsic::LiftFlatFloat64),
1434        ]);
1435    }
1436
1437    if args
1438        .intrinsics
1439        .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatResult))
1440    {
1441        args.intrinsics
1442            .insert(Intrinsic::Lower(LowerIntrinsic::LowerFlatVariant));
1443    }
1444
1445    if args
1446        .intrinsics
1447        .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatOption))
1448    {
1449        args.intrinsics
1450            .insert(Intrinsic::Lower(LowerIntrinsic::LowerFlatVariant));
1451    }
1452
1453    if args
1454        .intrinsics
1455        .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatVariant))
1456    {
1457        args.intrinsics.extend([
1458            &Intrinsic::Lower(LowerIntrinsic::LowerFlatU8),
1459            &Intrinsic::Lower(LowerIntrinsic::LowerFlatU16),
1460            &Intrinsic::Lower(LowerIntrinsic::LowerFlatU32),
1461        ]);
1462    }
1463
1464    if args
1465        .intrinsics
1466        .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStream))
1467    {
1468        args.intrinsics.extend([
1469            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamMap),
1470            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::ExternalStreamClass),
1471            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::InternalStreamClass),
1472            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::IsStreamLowerableObject),
1473            &Intrinsic::SymbolResourceRep,
1474            &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1475            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GenReadFnFromLowerableStream),
1476            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GenStreamHostInjectFn),
1477            &Intrinsic::Lower(LowerIntrinsic::LowerFlatU32),
1478        ])
1479    }
1480
1481    if args.intrinsics.contains(&Intrinsic::AsyncStream(
1482        AsyncStreamIntrinsic::GenStreamHostInjectFn,
1483    )) {
1484        args.intrinsics.insert(Intrinsic::AsyncStream(
1485            AsyncStreamIntrinsic::PendingValueQueueClass,
1486        ));
1487    }
1488
1489    if args.intrinsics.contains(&Intrinsic::AsyncStream(
1490        AsyncStreamIntrinsic::GenReadFnFromLowerableStream,
1491    )) {
1492        args.intrinsics.extend([
1493            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::IsStreamLowerableObject),
1494            &Intrinsic::SymbolAsyncIterator,
1495            &Intrinsic::SymbolIterator,
1496            &Intrinsic::SymbolDispose,
1497            &Intrinsic::PlatformReadableStreamClass,
1498        ]);
1499    }
1500
1501    if args.intrinsics.contains(&Intrinsic::AsyncStream(
1502        AsyncStreamIntrinsic::IsStreamLowerableObject,
1503    )) {
1504        args.intrinsics.extend([
1505            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::ExternalStreamClass),
1506            &Intrinsic::SymbolAsyncIterator,
1507            &Intrinsic::SymbolIterator,
1508            &Intrinsic::PlatformReadableStreamClass,
1509        ]);
1510    }
1511
1512    if args
1513        .intrinsics
1514        .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatFuture))
1515    {
1516        args.intrinsics.extend([
1517            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureMap),
1518            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1519            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::InternalFutureClass),
1520            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::IsFutureLowerableObject),
1521            &Intrinsic::SymbolResourceRep,
1522            &Intrinsic::GetErrorPayload,
1523            &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1524            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GenFutureHostInjectFn),
1525            &Intrinsic::Lower(LowerIntrinsic::LowerFlatU32),
1526        ])
1527    }
1528
1529    if args
1530        .intrinsics
1531        .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStringAny))
1532    {
1533        args.intrinsics.extend([
1534            &Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf8),
1535            &Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf16),
1536        ]);
1537    }
1538
1539    if args
1540        .intrinsics
1541        .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf8))
1542    {
1543        args.intrinsics
1544            .insert(Intrinsic::String(StringIntrinsic::GlobalTextDecoderUtf8));
1545    }
1546
1547    if args
1548        .intrinsics
1549        .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStringAny))
1550    {
1551        args.intrinsics.extend([
1552            &Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf8),
1553            &Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf16),
1554        ]);
1555    }
1556
1557    if args
1558        .intrinsics
1559        .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf8))
1560    {
1561        args.intrinsics.extend([
1562            Intrinsic::String(StringIntrinsic::GlobalTextEncoderUtf8),
1563            Intrinsic::String(StringIntrinsic::Utf8Encode),
1564        ]);
1565    }
1566
1567    if args
1568        .intrinsics
1569        .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf16))
1570    {
1571        args.intrinsics.extend([
1572            Intrinsic::String(StringIntrinsic::Utf16Encode),
1573            Intrinsic::IsLE,
1574        ]);
1575    }
1576
1577    if args
1578        .intrinsics
1579        .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf16))
1580    {
1581        args.intrinsics
1582            .insert(Intrinsic::String(StringIntrinsic::Utf16Decoder));
1583    }
1584
1585    if args
1586        .intrinsics
1587        .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStream))
1588    {
1589        args.intrinsics.insert(Intrinsic::AsyncStream(
1590            AsyncStreamIntrinsic::ExternalStreamClass,
1591        ));
1592    }
1593
1594    if args.intrinsics.contains(&Intrinsic::AsyncTask(
1595        AsyncTaskIntrinsic::CreateNewCurrentTask,
1596    )) || args
1597        .intrinsics
1598        .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask))
1599        || args
1600            .intrinsics
1601            .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::ClearCurrentTask))
1602    {
1603        args.intrinsics.extend([
1604            &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass),
1605            &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskMap),
1606        ]);
1607    }
1608
1609    if args
1610        .intrinsics
1611        .contains(&Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamNew))
1612    {
1613        args.intrinsics.extend([
1614            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamMap),
1615            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamTableMap),
1616            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamWritableEndClass),
1617            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamReadableEndClass),
1618        ]);
1619    }
1620
1621    if args.intrinsics.contains(&Intrinsic::AsyncStream(
1622        AsyncStreamIntrinsic::StreamWritableEndClass,
1623    )) || args.intrinsics.contains(&Intrinsic::AsyncStream(
1624        AsyncStreamIntrinsic::StreamReadableEndClass,
1625    )) {
1626        args.intrinsics.extend([
1627            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::InternalStreamClass),
1628            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamEndClass),
1629            &Intrinsic::AsyncEventCodeEnum,
1630        ]);
1631    }
1632
1633    if args.intrinsics.contains(&Intrinsic::AsyncStream(
1634        AsyncStreamIntrinsic::StreamNewFromLift,
1635    )) {
1636        args.intrinsics.extend([
1637            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamMap),
1638            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamTableMap),
1639            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::HostStreamClass),
1640            &Intrinsic::AsyncStream(AsyncStreamIntrinsic::ExternalStreamClass),
1641            &Intrinsic::GlobalBufferManager,
1642        ]);
1643    }
1644
1645    if args.intrinsics.contains(&Intrinsic::AsyncStream(
1646        AsyncStreamIntrinsic::ExternalStreamClass,
1647    )) {
1648        args.intrinsics.insert(Intrinsic::SymbolResourceRep);
1649    }
1650
1651    if args
1652        .intrinsics
1653        .contains(&Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamWrite))
1654        || args
1655            .intrinsics
1656            .contains(&Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamRead))
1657        || args
1658            .intrinsics
1659            .contains(&Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureWrite))
1660        || args
1661            .intrinsics
1662            .contains(&Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureRead))
1663    {
1664        args.intrinsics.extend([
1665            &Intrinsic::GlobalBufferManager,
1666            &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncBlockedConstant),
1667            &Intrinsic::AsyncEventCodeEnum,
1668        ]);
1669    }
1670
1671    if args
1672        .intrinsics
1673        .contains(&Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureNew))
1674    {
1675        args.intrinsics.extend([
1676            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureMap),
1677            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1678            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureTableMap),
1679            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureWritableEndClass),
1680            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureReadableEndClass),
1681        ]);
1682    }
1683
1684    if args.intrinsics.contains(&Intrinsic::AsyncFuture(
1685        AsyncFutureIntrinsic::FutureNewFromLift,
1686    )) {
1687        args.intrinsics.extend([
1688            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1689            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureMap),
1690            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::HostFutureClass),
1691            &Intrinsic::GlobalBufferManager,
1692        ]);
1693    }
1694
1695    if args.intrinsics.contains(&Intrinsic::AsyncFuture(
1696        AsyncFutureIntrinsic::FutureWritableEndClass,
1697    )) || args.intrinsics.contains(&Intrinsic::AsyncFuture(
1698        AsyncFutureIntrinsic::FutureReadableEndClass,
1699    )) {
1700        args.intrinsics.extend([
1701            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1702            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureValueClass),
1703            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::InternalFutureClass),
1704            &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureEndClass),
1705            &Intrinsic::AsyncEventCodeEnum,
1706        ]);
1707    }
1708
1709    if args.intrinsics.contains(&Intrinsic::GlobalBufferManager) {
1710        args.intrinsics.extend([&Intrinsic::BufferManagerClass]);
1711    }
1712
1713    if args.intrinsics.contains(&Intrinsic::BufferManagerClass) {
1714        args.intrinsics.extend([&Intrinsic::ManagedBufferClass]);
1715    }
1716
1717    if args.intrinsics.contains(&Intrinsic::AsyncTask(
1718        AsyncTaskIntrinsic::EnterSymmetricSyncGuestCall,
1719    )) || args.intrinsics.contains(&Intrinsic::AsyncTask(
1720        AsyncTaskIntrinsic::ExitSymmetricSyncGuestCall,
1721    )) {
1722        args.intrinsics.extend([
1723            &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentComponentIdxs),
1724            &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1725            &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask),
1726            &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskIds),
1727            &Intrinsic::ClearGlobalCurrentTaskMetaFn,
1728            &Intrinsic::AsyncTask(AsyncTaskIntrinsic::SymmetricSyncGuestCallStack),
1729        ]);
1730    }
1731
1732    for current_intrinsic in args.intrinsics.iter() {
1733        // Skip already rendered intrinsics (i.e. the early intrinsics)
1734        if rendered_intrinsics.contains(current_intrinsic.name()) {
1735            continue;
1736        }
1737
1738        current_intrinsic.render(&mut output, &args);
1739    }
1740
1741    output
1742}
1743
1744impl Intrinsic {
1745    pub fn get_global_names() -> impl IntoIterator<Item = &'static str> {
1746        JsHelperIntrinsic::get_global_names()
1747            .into_iter()
1748            .chain(vec![
1749                // Intrinsic list exactly as below
1750                "base64Compile",
1751                "clampGuest",
1752                "ComponentError",
1753                "fetchCompile",
1754                "finalizationRegistryCreate",
1755                "getErrorPayload",
1756                "HANDLE_TABLES",
1757                "hasOwnProperty",
1758                "imports",
1759                "instantiateCore",
1760                "isLE",
1761                "scopeId",
1762                "symbolCabiDispose",
1763                "symbolCabiLower",
1764                "symbolDispose",
1765                "symbolAsyncIterator",
1766                "symbolIterator",
1767                "symbolRscHandle",
1768                "symbolRscRep",
1769                "T_FLAG",
1770                "throwInvalidBool",
1771                "throwUninitialized",
1772                // JS Globals / non intrinsic names
1773                "ArrayBuffer",
1774                "BigInt",
1775                "BigInt64Array",
1776                "DataView",
1777                "dv",
1778                "emptyFunc",
1779                "Error",
1780                "fetch",
1781                "Float32Array",
1782                "Float64Array",
1783                "Int32Array",
1784                "Object",
1785                "process",
1786                "String",
1787                "TextDecoder",
1788                "TextEncoder",
1789                "TypeError",
1790                "Uint16Array",
1791                "Uint8Array",
1792                "URL",
1793                "WebAssembly",
1794                "GlobalComponentMemories",
1795            ])
1796    }
1797
1798    pub fn name(&self) -> &'static str {
1799        match self {
1800            Intrinsic::JsHelper(i) => i.name(),
1801            Intrinsic::Conversion(i) => i.name(),
1802            Intrinsic::WebIdl(i) => i.name(),
1803            Intrinsic::String(i) => i.name(),
1804            Intrinsic::ErrCtx(i) => i.name(),
1805            Intrinsic::AsyncTask(i) => i.name(),
1806            Intrinsic::Waitable(i) => i.name(),
1807            Intrinsic::Resource(i) => i.name(),
1808            Intrinsic::Lift(i) => i.name(),
1809            Intrinsic::Lower(i) => i.name(),
1810            Intrinsic::AsyncStream(i) => i.name(),
1811            Intrinsic::AsyncFuture(i) => i.name(),
1812            Intrinsic::Component(i) => i.name(),
1813            Intrinsic::Host(i) => i.name(),
1814
1815            Intrinsic::Base64Compile => "base64Compile",
1816            Intrinsic::ClampGuest => "clampGuest",
1817            Intrinsic::ComponentError => "ComponentError",
1818            Intrinsic::FetchCompile => "fetchCompile",
1819            Intrinsic::FinalizationRegistryCreate => "finalizationRegistryCreate",
1820            Intrinsic::GetErrorPayload => "getErrorPayload",
1821            Intrinsic::GetErrorPayloadString => "getErrorPayloadString",
1822            Intrinsic::HandleTables => "HANDLE_TABLES",
1823            Intrinsic::HasOwnProperty => "hasOwnProperty",
1824            Intrinsic::InstantiateCore => "instantiateCore",
1825            Intrinsic::IsLE => "isLE",
1826            Intrinsic::ScopeId => "SCOPE_ID",
1827
1828            Intrinsic::SymbolCabiDispose => "symbolCabiDispose",
1829            Intrinsic::SymbolCabiLower => "symbolCabiLower",
1830            Intrinsic::SymbolDispose => "symbolDispose",
1831            Intrinsic::SymbolAsyncIterator => "symbolAsyncIterator",
1832            Intrinsic::SymbolIterator => "symbolIterator",
1833            Intrinsic::SymbolResourceHandle => "symbolRscHandle",
1834            Intrinsic::SymbolResourceRep => "symbolRscRep",
1835
1836            Intrinsic::ThrowInvalidBool => "throwInvalidBool",
1837            Intrinsic::ThrowUninitialized => "throwUninitialized",
1838
1839            // Debugging
1840            Intrinsic::DebugLog => "_debugLog",
1841            Intrinsic::PromiseWithResolversPonyfill => "promiseWithResolvers",
1842
1843            // Types
1844            Intrinsic::ConstantI32Min => "I32_MIN",
1845            Intrinsic::ConstantI32Max => "I32_MAX",
1846            Intrinsic::TypeCheckValidI32 => "_typeCheckValidI32",
1847            Intrinsic::TypeCheckAsyncFn => "_typeCheckAsyncFn",
1848            Intrinsic::AsyncFunctionCtor => "ASYNC_FN_CTOR",
1849
1850            // Streams
1851            Intrinsic::PlatformReadableStreamClass => "_PlatformReadableStream",
1852
1853            // Async
1854            Intrinsic::GlobalAsyncDeterminism => "ASYNC_DETERMINISM",
1855            Intrinsic::CoinFlip => "_coinFlip",
1856
1857            // Global current task tracking machinery
1858            Self::GlobalCurrentTaskMeta => "CURRENT_TASK_META",
1859            Self::GetGlobalCurrentTaskMetaFn => "_getGlobalCurrentTaskMeta",
1860            Self::SetGlobalCurrentTaskMetaFn => "_setGlobalCurrentTaskMeta",
1861            Self::WithGlobalCurrentTaskMetaFn => "_withGlobalCurrentTaskMeta",
1862            Self::WithGlobalCurrentTaskMetaFnAsync => "_withGlobalCurrentTaskMetaAsync",
1863            Self::ClearGlobalCurrentTaskMetaFn => "_clearCurrentTask",
1864            Self::SuspendingImportWrapperFn => "_suspendingImport",
1865
1866            // Iteratively saved metadata
1867            Intrinsic::GlobalComponentMemoryMap => "GLOBAL_COMPONENT_MEMORY_MAP",
1868            Intrinsic::RegisterGlobalMemoryForComponent => "registerGlobalMemoryForComponent",
1869            Intrinsic::LookupMemoriesForComponent => "lookupMemoriesForComponent",
1870
1871            // Data structures
1872            Intrinsic::RepTableClass => "RepTable",
1873
1874            // Buffers for managed/synchronized writing to/from component memory
1875            Intrinsic::ManagedBufferClass => "ManagedBuffer",
1876            Intrinsic::BufferManagerClass => "BufferManager",
1877            Intrinsic::GlobalBufferManager => "BUFFER_MGR",
1878
1879            // Helpers for working with async state
1880            Intrinsic::AsyncEventCodeEnum => "ASYNC_EVENT_CODE",
1881        }
1882    }
1883}