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