1use 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#[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 PromiseWithResolversPonyfill,
65
66 DebugLog,
68
69 GlobalAsyncDeterminism,
71
72 CoinFlip,
74
75 ConstantI32Max,
77 ConstantI32Min,
78 TypeCheckValidI32,
79 TypeCheckAsyncFn,
80 AsyncFunctionCtor,
81
82 Base64Compile,
83 ClampGuest,
84 FetchCompile,
85
86 SymbolCabiDispose,
88 SymbolCabiLower,
89 SymbolResourceHandle,
90 SymbolResourceRep,
91 SymbolDispose,
92 SymbolAsyncIterator,
93 SymbolIterator,
94 ScopeId,
95 HandleTables,
96
97 PlatformReadableStreamClass,
101
102 FinalizationRegistryCreate,
104
105 ComponentError,
107
108 GetErrorPayload,
110 GetErrorPayloadString,
111
112 ManagedBufferClass,
114
115 BufferManagerClass,
117
118 GlobalBufferManager,
120
121 RepTableClass,
125
126 AsyncEventCodeEnum,
128
129 IsLE,
131 ThrowInvalidBool,
132 ThrowUninitialized,
133 HasOwnProperty,
134 InstantiateCore,
135
136 GlobalComponentMemoryMap,
138
139 RegisterGlobalMemoryForComponent,
141
142 LookupMemoriesForComponent,
144
145 GlobalCurrentTaskMeta,
147
148 GetGlobalCurrentTaskMetaFn,
150
151 SetGlobalCurrentTaskMetaFn,
153
154 WithGlobalCurrentTaskMetaFn,
156
157 WithGlobalCurrentTaskMetaFnAsync,
159
160 ClearGlobalCurrentTaskMetaFn,
162
163 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 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 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 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#[derive(Debug, Default, PartialEq, Eq)]
1118pub enum AsyncDeterminismProfile {
1119 #[default]
1121 Random,
1122
1123 #[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#[derive(bon::Builder)]
1143#[non_exhaustive]
1144pub struct RenderIntrinsicsArgs<'a> {
1145 pub(crate) intrinsics: &'a mut BTreeSet<Intrinsic>,
1147 #[builder(default)]
1149 pub(crate) instantiation_occurred: bool,
1150 #[builder(default)]
1152 pub(crate) determinism_profile: AsyncDeterminismProfile,
1153 pub(crate) transpile_opts: &'a TranspileOpts,
1155}
1156
1157const 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 Intrinsic::ConstantI32Min,
1180 Intrinsic::ConstantI32Max,
1181 Intrinsic::Conversion(ConversionIntrinsic::IsValidNumericPrimitive),
1182 Intrinsic::Conversion(ConversionIntrinsic::RequireValidNumericPrimitive),
1183 Intrinsic::TypeCheckValidI32,
1184 Intrinsic::TypeCheckAsyncFn,
1185 Intrinsic::Resource(ResourceIntrinsic::ResourceCallBorrows),
1187 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 Intrinsic::Host(HostIntrinsic::PrepareCall),
1197 Intrinsic::Host(HostIntrinsic::AsyncStartCall),
1198 Intrinsic::Host(HostIntrinsic::SyncStartCall),
1199 Intrinsic::Waitable(WaitableIntrinsic::WaitableClass),
1201 Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalErrCtxTableMap),
1203 Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextGet),
1206 Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextSet),
1207 Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskMap),
1209 Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass),
1210 Intrinsic::AsyncEventCodeEnum,
1211 Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask),
1212];
1213
1214pub fn render_intrinsics(args: RenderIntrinsicsArgs) -> Source {
1217 let mut output = Source::default();
1218 let mut rendered_intrinsics = HashSet::new();
1219
1220 for intrinsic in EARLY_INTRINSICS {
1222 intrinsic.render(&mut output, &args);
1223 rendered_intrinsics.insert(intrinsic.name());
1224 }
1225
1226 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 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 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 "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 "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 Intrinsic::DebugLog => "_debugLog",
1841 Intrinsic::PromiseWithResolversPonyfill => "promiseWithResolvers",
1842
1843 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 Intrinsic::PlatformReadableStreamClass => "_PlatformReadableStream",
1852
1853 Intrinsic::GlobalAsyncDeterminism => "ASYNC_DETERMINISM",
1855 Intrinsic::CoinFlip => "_coinFlip",
1856
1857 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 Intrinsic::GlobalComponentMemoryMap => "GLOBAL_COMPONENT_MEMORY_MAP",
1868 Intrinsic::RegisterGlobalMemoryForComponent => "registerGlobalMemoryForComponent",
1869 Intrinsic::LookupMemoriesForComponent => "lookupMemoriesForComponent",
1870
1871 Intrinsic::RepTableClass => "RepTable",
1873
1874 Intrinsic::ManagedBufferClass => "ManagedBuffer",
1876 Intrinsic::BufferManagerClass => "BufferManager",
1877 Intrinsic::GlobalBufferManager => "BUFFER_MGR",
1878
1879 Intrinsic::AsyncEventCodeEnum => "ASYNC_EVENT_CODE",
1881 }
1882 }
1883}