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
164impl Intrinsic {
165 pub fn render(&self, output: &mut Source, args: &RenderIntrinsicsArgs) {
166 match self {
167 Intrinsic::JsHelper(i) => i.render(output, args),
168 Intrinsic::Conversion(i) => i.render(output, args),
169 Intrinsic::String(i) => i.render(output, args),
170 Intrinsic::ErrCtx(i) => i.render(output, args),
171 Intrinsic::Resource(i) => i.render(output, args),
172 Intrinsic::AsyncTask(i) => i.render(output, args),
173 Intrinsic::Waitable(i) => i.render(output, args),
174 Intrinsic::Lift(i) => i.render(output, args),
175 Intrinsic::Lower(i) => i.render(output, args),
176 Intrinsic::AsyncStream(i) => i.render(output, args),
177 Intrinsic::AsyncFuture(i) => i.render(output, args),
178 Intrinsic::Component(i) => i.render(output, args),
179 Intrinsic::Host(i) => i.render(output, args),
180
181 Intrinsic::GlobalAsyncDeterminism => {
182 uwriteln!(
183 output,
184 "const {var_name} = '{determinism}';",
185 var_name = self.name(),
186 determinism = args.determinism_profile,
187 );
188 }
189
190 Intrinsic::CoinFlip => {
191 uwriteln!(
192 output,
193 "const {var_name} = () => {{ return Math.random() > 0.5; }};",
194 var_name = self.name(),
195 );
196 }
197
198 Intrinsic::ConstantI32Min => output.push_str(&format!(
199 "const {const_name} = -2_147_483_648;\n",
200 const_name = self.name()
201 )),
202
203 Intrinsic::ConstantI32Max => {
204 uwriteln!(
205 output,
206 r#"
207 const {const_name} = 2_147_483_647;
208 "#,
209 const_name = self.name()
210 )
211 }
212
213 Intrinsic::TypeCheckValidI32 => {
214 let i32_const_min = Intrinsic::ConstantI32Min.name();
215 let i32_const_max = Intrinsic::ConstantI32Max.name();
216
217 uwriteln!(
218 output,
219 r#"
220 const {fn_name} = (n) => typeof n === 'number' && n >= {i32_const_min} && n <= {i32_const_max};
221 "#,
222 fn_name = self.name()
223 );
224 }
225
226 Intrinsic::AsyncFunctionCtor => {
227 let async_fn_type = Intrinsic::AsyncFunctionCtor.name();
228 uwriteln!(
229 output,
230 "const {async_fn_type} = (async () => {{}}).constructor;"
231 );
232 }
233
234 Intrinsic::TypeCheckAsyncFn => {
235 let async_fn_check = Intrinsic::TypeCheckAsyncFn.name();
236 let async_fn_ctor = Intrinsic::AsyncFunctionCtor.name();
237 uwriteln!(
238 output,
239 r#"
240 const {async_fn_check} = (f) => {{
241 return f instanceof {async_fn_ctor};
242 }};
243 "#,
244 );
245 }
246
247 Intrinsic::Base64Compile => {
248 if !args.transpile_opts.nodejs_compat_disabled {
249 uwriteln!(
250 output,
251 r#"
252 const base64Compile = str => WebAssembly.compile(
253 typeof Buffer !== 'undefined'
254 ? Buffer.from(str, 'base64')
255 : Uint8Array.from(atob(str), b => b.charCodeAt(0))
256 );
257 "#
258 );
259 } else {
260 uwriteln!(
261 output,
262 r#"
263 const base64Compile = str => WebAssembly.compile(Uint8Array.from(atob(str), b => b.charCodeAt(0)));
264 "#
265 );
266 }
267 }
268
269 Intrinsic::ClampGuest => {
270 uwriteln!(
271 output,
272 r#"
273 function clampGuest(i, min, max) {{
274 if (i < min || i > max) {{
275 throw new TypeError(`must be between ${{min}} and ${{max}}`);
276 }}
277 return i;
278 }}
279 "#
280 );
281 }
282
283 Intrinsic::ComponentError => output.push_str(
284 "
285 class ComponentError extends Error {
286 constructor (value) {
287 const enumerable = typeof value !== 'string';
288 super(enumerable ? `${String(value)} (see error.payload)` : value);
289 Object.defineProperty(this, 'payload', { value, enumerable });
290 }
291 }
292 ",
293 ),
294
295 Intrinsic::FinalizationRegistryCreate => output.push_str(
296 "
297 function finalizationRegistryCreate (unregister) {
298 if (typeof FinalizationRegistry === 'undefined') {
299 return { unregister () {} };
300 }
301 return new FinalizationRegistry(unregister);
302 }
303 ",
304 ),
305
306 Intrinsic::FetchCompile => {
307 if !args.transpile_opts.nodejs_compat_disabled {
308 output.push_str("
309 const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
310 let _fs;
311 async function fetchCompile (url) {
312 if (isNode) {
313 _fs = _fs || await import('node:fs/promises');
314 return WebAssembly.compile(await _fs.readFile(url));
315 }
316 return fetch(url).then(WebAssembly.compileStreaming);
317 }
318 ")
319 } else {
320 output.push_str(
321 "
322 const fetchCompile = url => fetch(url).then(WebAssembly.compileStreaming);
323 ",
324 )
325 }
326 }
327
328 Intrinsic::GetErrorPayload => {
329 let hop = Intrinsic::HasOwnProperty.name();
330 uwrite!(
331 output,
332 "
333 function getErrorPayload(e) {{
334 if (e && {hop}.call(e, 'payload')) return e.payload;
335 if (e instanceof Error) throw e;
336 return e;
337 }}
338 "
339 )
340 }
341
342 Intrinsic::GetErrorPayloadString => {
343 let hop = Intrinsic::HasOwnProperty.name();
344 uwrite!(
345 output,
346 "
347 function getErrorPayloadString(e) {{
348 if (e && {hop}.call(e, 'payload')) return e.payload;
349 if (e instanceof Error) return e.message;
350 return e;
351 }}
352 "
353 )
354 }
355
356 Intrinsic::WebIdl(w) => w.render(output),
357
358 Intrinsic::HandleTables => {
359 let var_name = self.name();
360 uwriteln!(
361 output,
362 r#"
363 const {var_name} = [];
364 "#,
365 );
366 }
367
368 Intrinsic::HasOwnProperty => output.push_str(
369 "
370 const hasOwnProperty = Object.prototype.hasOwnProperty;
371 ",
372 ),
373
374 Intrinsic::InstantiateCore => {
375 if !args.instantiation_occurred {
376 output.push_str(
377 "
378 const instantiateCore = WebAssembly.instantiate;
379 ",
380 )
381 }
382 }
383
384 Intrinsic::IsLE => output.push_str(
385 "
386 const isLE = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
387 ",
388 ),
389
390 Intrinsic::SymbolCabiDispose => output.push_str(
391 "
392 const symbolCabiDispose = Symbol.for('cabiDispose');
393 ",
394 ),
395
396 Intrinsic::SymbolCabiLower => output.push_str(
397 "
398 const symbolCabiLower = Symbol.for('cabiLower');
399 ",
400 ),
401
402 Intrinsic::ScopeId => {
403 let name = self.name();
404 uwriteln!(output, "let {name} = 0;");
405 }
406
407 Intrinsic::SymbolResourceHandle => output.push_str(
408 "
409 const symbolRscHandle = Symbol('handle');
410 ",
411 ),
412
413 Intrinsic::SymbolResourceRep => output.push_str(
414 "
415 const symbolRscRep = Symbol.for('cabiRep');
416 ",
417 ),
418
419 Intrinsic::SymbolDispose => {
420 let var_name = self.name();
421 uwriteln!(
422 output,
423 "const {var_name} = Symbol.dispose || Symbol.for('dispose');"
424 );
425 }
426
427 Intrinsic::SymbolAsyncIterator => {
428 let var_name = self.name();
429 uwriteln!(output, "const {var_name} = Symbol.asyncIterator;");
430 }
431
432 Intrinsic::SymbolIterator => {
433 let var_name = self.name();
434 uwriteln!(output, "const {var_name} = Symbol.iterator;");
435 }
436
437 Intrinsic::ThrowInvalidBool => output.push_str(
438 "
439 function throwInvalidBool() {
440 throw new TypeError('invalid variant discriminant for bool');
441 }
442 ",
443 ),
444
445 Intrinsic::ThrowUninitialized => output.push_str(
446 "
447 function throwUninitialized() {
448 throw new TypeError('Wasm uninitialized use `await $init` first');
449 }
450 ",
451 ),
452
453 Intrinsic::DebugLog => {
454 let fn_name = Intrinsic::DebugLog.name();
455 output.push_str(&format!(
456 "
457 const {fn_name} = (...args) => {{
458 if (!globalThis?.process?.env?.JCO_DEBUG) {{ return; }}
459 console.debug(...args);
460 }};
461 "
462 ));
463 }
464
465 Intrinsic::PromiseWithResolversPonyfill => {
466 let fn_name = self.name();
467 output.push_str(&format!(
468 r#"
469 function {fn_name}() {{
470 if (Promise.withResolvers) {{
471 return Promise.withResolvers();
472 }} else {{
473 let resolve;
474 let reject;
475 const promise = new Promise((res, rej) => {{
476 resolve = res;
477 reject = rej;
478 }});
479 return {{ promise, resolve, reject }};
480 }}
481 }}
482 "#
483 ));
484 }
485
486 Intrinsic::AsyncEventCodeEnum => {
487 let name = Intrinsic::AsyncEventCodeEnum.name();
488 output.push_str(&format!(
489 "
490 const {name} = {{
491 NONE: 0,
492 SUBTASK: 1,
493 STREAM_READ: 2,
494 STREAM_WRITE: 3,
495 FUTURE_READ: 4,
496 FUTURE_WRITE: 5,
497 TASK_CANCELLED: 6,
498 }};
499 "
500 ));
501 }
502
503 Intrinsic::ManagedBufferClass => {
504 let debug_log_fn = Intrinsic::DebugLog.name();
505 let managed_buffer_class = Intrinsic::ManagedBufferClass.name();
506 output.push_str(&format!(
507 r#"
508 class {managed_buffer_class} {{
509 static MAX_LENGTH = 2**28 - 1;
510 #componentIdx;
511 #memory;
512
513 #elemMeta = null;
514
515 #start;
516 #ptr;
517 capacity;
518 processed = 0;
519
520 #hostOnlyData; // initial data (only filled out for host-owned)
521
522 target;
523
524 constructor(args) {{
525 if (args.capacity > {managed_buffer_class}.MAX_LENGTH) {{
526 throw new Error(`buffer size [${{args.capacity}}] greater than max length`);
527 }}
528 if (args.componentIdx === undefined) {{ throw new TypeError('missing/invalid component idx'); }}
529 if (args.capacity === undefined) {{ throw new TypeError('missing/invalid capacity'); }}
530 if (!args.elemMeta || typeof args.elemMeta.align32 !== 'number') {{
531 throw new TypeError('missing/invalid element metadata');
532 }}
533
534 if (!args.memory && args.start === undefined && args.data === undefined) {{
535 throw new TypeError('either memory and start ptr or data must be provided for managed buffers');
536 }}
537
538 if (args.memory && args.start == undefined) {{
539 throw new TypeError('missing/invalid start ptr, depsite memory being present');
540 }}
541
542 if (!args.elemMeta.isNone && args.capacity > 0) {{
543 if (args.start && args.start % args.elemMeta.align32 !== 0) {{
544 throw new Error(`invalid alignment: type with 32bit alignment [${{args.elemMeta.align32}}] at starting pointer [${{args.start}}]`);
545 }}
546 // TODO: memory lenght bounds check
547 }}
548
549 this.#componentIdx = args.componentIdx;
550 this.#memory = args.memory;
551 this.#start = args.start;
552 this.#ptr = this.#start;
553 this.capacity = args.capacity;
554 this.#elemMeta = args.elemMeta;
555
556 if (args.data !== undefined && !Array.isArray(args.data)) {{
557 throw new TypeError('host-only data must be an array');
558 }}
559 this.#hostOnlyData = args.data;
560
561 this.target = args.target;
562 }}
563
564 setTarget(tgt) {{ this.target = tgt; }}
565
566 remaining() {{
567 return this.capacity - this.processed;
568 }}
569
570 componentIdx() {{ return this.#componentIdx; }}
571
572 getElemMeta() {{ return this.#elemMeta; }}
573
574 isHostOwned() {{ return !this.#memory; }}
575
576 read(count) {{
577 {debug_log_fn}('[{managed_buffer_class}#read()] args', {{ count }});
578 if (count === undefined || count <= 0) {{
579 throw new TypeError(`missing/invalid count [${{count}}]`);
580 }}
581
582 const cap = this.capacity;
583 if (count > cap) {{
584 throw new Error(`cannot read [${{count}}] elements from buffer with capacity [${{cap}}]`);
585 }}
586
587 let values = [];
588 if (this.#elemMeta.isNone) {{
589 values = [...new Array(count)].map(() => null);
590 }} else {{
591 if (this.isHostOwned()) {{
592 values = this.#hostOnlyData.slice(0, count);
593 this.#hostOnlyData = this.#hostOnlyData.slice(count);
594 }} else if (this.#elemMeta.payloadTypeName === 'U8') {{
595 values = Array.from(new Uint8Array(this.#memory.buffer, this.#ptr, count));
596 this.#ptr += count;
597 }} else {{
598 let currentCount = count;
599 let startPtr = this.#ptr;
600 if (this.#elemMeta.stringEncoding === undefined) {{
601 throw new Error('string encoding unknown during read');
602 }}
603 let liftCtx = {{
604 storagePtr: startPtr,
605 memory: this.#memory,
606 componentIdx: this.#componentIdx,
607 stringEncoding: this.#elemMeta.stringEncoding,
608 }};
609 if (currentCount < 0) {{ throw new Error('unexpectedly invalid count'); }}
610 while (currentCount > 0) {{
611 const [value, _ctx] = this.#elemMeta.liftFn(liftCtx);
612 values.push(value);
613 currentCount -= 1;
614 }}
615 this.#ptr = liftCtx.storagePtr;
616 }}
617 }}
618
619 this.processed += count;
620 return values;
621 }}
622
623 write(values) {{
624 {debug_log_fn}('[{managed_buffer_class}#write()] args', {{ values }});
625
626 if (!Array.isArray(values)) {{ throw new TypeError('values input to write() must be an array'); }}
627 let rc = this.remaining();
628 if (values.length > rc) {{
629 throw new Error(`cannot write [${{values.length}}] elements to managed buffer with remaining capacity [${{rc}}]`);
630 }}
631
632 if (this.#elemMeta.isNone) {{
633 if (!values.every(v => v === null)) {{
634 throw new Error('non-null values in write() to unit managed buffer');
635 }}
636 }} else {{
637 if (this.isHostOwned()) {{
638 this.#hostOnlyData = this.#hostOnlyData.concat(values);
639 }} else if (this.#elemMeta.payloadTypeName === 'U8') {{
640 new Uint8Array(this.#memory.buffer, this.#ptr, values.length).set(values);
641 this.#ptr += values.length;
642 }} else {{
643 let startPtr = this.#ptr;
644 if (this.#elemMeta.stringEncoding === undefined) {{
645 throw new Error('string encoding unknown during write');
646 }}
647
648 const lowerCtx = {{
649 memory: this.#memory,
650 storagePtr: startPtr,
651 componentIdx: this.#componentIdx,
652 stringEncoding: this.#elemMeta.stringEncoding,
653 realloc: this.#elemMeta.getReallocFn?.(),
654 getReallocFn: this.#elemMeta.getReallocFn,
655 }}
656 for (const v of values) {{
657 lowerCtx.vals = [v];
658 this.#elemMeta.lowerFn(lowerCtx);
659 }}
660
661 this.#ptr = lowerCtx.storagePtr;
662 }}
663 }}
664
665 this.processed += values.length;
666 }}
667
668 }}
669 "#
670 ));
671 }
672
673 Intrinsic::BufferManagerClass => {
674 let debug_log_fn = Intrinsic::DebugLog.name();
675 let buffer_manager_class = Intrinsic::BufferManagerClass.name();
676 let managed_buffer_class = Intrinsic::ManagedBufferClass.name();
677
678 output.push_str(&format!(r#"
679 class {buffer_manager_class} {{
680 #buffers = new Map();
681 #bufferIDs = new Map();
682
683 // NOTE: componentIdx === -1 indicates the host
684 getNextBufferID(componentIdx) {{
685 const current = this.#bufferIDs.get(componentIdx);
686 if (current === undefined) {{
687 this.#bufferIDs.set(componentIdx, 1n);
688 return 1n;
689 }}
690 const next = current + 1n;
691 this.#bufferIDs.set(componentIdx, next);
692 return next;
693 }}
694
695 getBuffer(componentIdx, bufferID) {{
696 {debug_log_fn}('[{buffer_manager_class}#getBuffer()] args', {{ componentIdx, bufferID }});
697 return this.#buffers.get(componentIdx)?.get(bufferID);
698 }}
699
700 createBuffer(args) {{
701 {debug_log_fn}('[{buffer_manager_class}#createBuffer()] args', args);
702 if (!args || typeof args !== 'object') {{ throw new TypeError('missing/invalid argument object'); }}
703
704 if (args.start === undefined && args.data === undefined) {{
705 throw new TypeError('either a starting pointer or initial values must be provided');
706 }}
707
708 if (args.start !== undefined && args.componentIdx === undefined) {{ throw new TypeError('missing/invalid component idx'); }}
709 if (args.count === undefined) {{ throw new TypeError('missing/invalid obj count'); }}
710 if (!args.elemMeta) {{ throw new TypeError('missing/invalid element metadata for use with managed buffer'); }}
711
712 const {{ componentIdx, data, start, count }} = args;
713
714 if (!this.#buffers.has(componentIdx)) {{ this.#buffers.set(componentIdx, new Map()); }}
715 const instanceBuffers = this.#buffers.get(componentIdx);
716
717 const nextBufID = this.getNextBufferID(componentIdx);
718
719 const buffer = new {managed_buffer_class}({{
720 componentIdx,
721 memory: args.memory,
722 start: args.start,
723 capacity: args.count,
724 elemMeta: args.elemMeta,
725 data: args.data,
726 target: args.target,
727 stringEncoding: args.stringEncoding,
728 }});
729
730 if (instanceBuffers.has(nextBufID)) {{
731 throw new Error(`managed buffer with ID [${{nextBufID}}] already exists`);
732 }}
733 instanceBuffers.set(nextBufID, buffer);
734
735 return {{ id: nextBufID, buffer }};
736 }}
737
738 deleteBuffer(componentIdx, bufferID) {{
739 {debug_log_fn}('[{buffer_manager_class}#deleteBuffer()] args', {{ componentIdx, bufferID }});
740 return this.#buffers.get(componentIdx)?.delete(bufferID);
741 }}
742
743 }}
744 "#));
745 }
746
747 Intrinsic::GlobalBufferManager => {
748 let global_buffer_manager = Intrinsic::GlobalBufferManager.name();
749 let buffer_manager_class = Intrinsic::BufferManagerClass.name();
750 output.push_str(&format!(
751 "const {global_buffer_manager} = new {buffer_manager_class}();"
752 ));
753 }
754
755 Intrinsic::RepTableClass => {
756 let debug_log_fn = Intrinsic::DebugLog.name();
757 let rep_table_class = Intrinsic::RepTableClass.name();
758 output.push_str(&format!(r#"
759 class {rep_table_class} {{
760 #data = [0, null];
761 #target;
762
763 constructor(args) {{
764 this.target = args?.target;
765 }}
766
767 data() {{ return this.#data; }}
768
769 insert(val) {{
770 {debug_log_fn}('[{rep_table_class}#insert()] args', {{ val, target: this.target }});
771 const freeIdx = this.#data[0];
772 if (freeIdx === 0) {{
773 this.#data.push(val);
774 this.#data.push(null);
775 const rep = (this.#data.length >> 1) - 1;
776 {debug_log_fn}('[{rep_table_class}#insert()] inserted', {{ val, target: this.target, rep }});
777 return rep;
778 }}
779 this.#data[0] = this.#data[freeIdx << 1];
780 const placementIdx = freeIdx << 1;
781 this.#data[placementIdx] = val;
782 this.#data[placementIdx + 1] = null;
783 {debug_log_fn}('[{rep_table_class}#insert()] inserted', {{ val, target: this.target, rep: freeIdx }});
784 return freeIdx;
785 }}
786
787 get(rep) {{
788 {debug_log_fn}('[{rep_table_class}#get()] args', {{ rep, target: this.target }});
789 if (rep === 0) {{ throw new Error('invalid resource rep during get, (cannot be 0)'); }}
790
791 const baseIdx = rep << 1;
792 const val = this.#data[baseIdx];
793 return val;
794 }}
795
796 contains(rep) {{
797 {debug_log_fn}('[{rep_table_class}#contains()] args', {{ rep, target: this.target }});
798 if (rep === 0) {{ throw new Error('invalid resource rep during contains, (cannot be 0)'); }}
799
800 const baseIdx = rep << 1;
801 return !!this.#data[baseIdx];
802 }}
803
804 remove(rep) {{
805 {debug_log_fn}('[{rep_table_class}#remove()] args', {{ rep, target: this.target }});
806 if (rep === 0) {{ throw new Error('invalid resource rep during remove, (cannot be 0)'); }}
807 if (this.#data.length === 2) {{ throw new Error('invalid'); }}
808
809 const baseIdx = rep << 1;
810 const val = this.#data[baseIdx];
811
812 this.#data[baseIdx] = this.#data[0];
813 this.#data[0] = rep;
814
815 return val;
816 }}
817
818 clear() {{
819 {debug_log_fn}('[{rep_table_class}#clear()] args', {{ rep, target: this.target }});
820 this.#data = [0, null];
821 }}
822 }}
823 "#));
824 }
825
826 Intrinsic::GlobalComponentMemoryMap => {
827 let global_component_memory_map = Intrinsic::GlobalComponentMemoryMap.name();
828 output.push_str(&format!(
829 "const {global_component_memory_map} = new Map();\n"
830 ));
831 }
832
833 Intrinsic::RegisterGlobalMemoryForComponent => {
834 let global_component_memory_map = Intrinsic::GlobalComponentMemoryMap.name();
835 let register_global_component_memory =
836 Intrinsic::RegisterGlobalMemoryForComponent.name();
837 output.push_str(&format!(
838 r#"
839 function {register_global_component_memory}(args) {{
840 const {{ componentIdx, memory, memoryIdx }} = args ?? {{}};
841 if (componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
842 if (memory === undefined && memoryIdx === undefined) {{ throw new TypeError('missing both memory & memory idx'); }}
843 let inner = {global_component_memory_map}.get(componentIdx);
844 if (!inner) {{
845 inner = {{}};
846 {global_component_memory_map}.set(componentIdx, inner);
847 }}
848
849 inner[memoryIdx] = {{ memory, memoryIdx, componentIdx }};
850 }}
851 "#)
852 );
853 }
854
855 Intrinsic::LookupMemoriesForComponent => {
856 let global_component_memory_map = Intrinsic::GlobalComponentMemoryMap.name();
857 let lookup_global_memories_for_component =
858 Intrinsic::LookupMemoriesForComponent.name();
859 output.push_str(&format!(
860 r#"
861 function {lookup_global_memories_for_component}(args) {{
862 const {{ componentIdx }} = args ?? {{}};
863 if (args.componentIdx === undefined) {{ throw new TypeError("missing component idx"); }}
864
865 const metas = {global_component_memory_map}.get(componentIdx);
866 if (!metas) {{ return []; }}
867
868 if (args.memoryIdx === undefined) {{
869 return Object.values(metas);
870 }}
871
872 const meta = metas[args.memoryIdx];
873 return meta?.memory;
874 }}
875 "#)
876 );
877 }
878
879 Self::GlobalCurrentTaskMeta => {
880 let name = self.name();
881 output.push_str(&format!("const {name} = {{}};\n"));
882 }
883
884 Self::GetGlobalCurrentTaskMetaFn => {
885 let get_current_global_task_meta_fn = Self::GetGlobalCurrentTaskMetaFn.name();
886 let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
887
888 uwriteln!(
889 output,
890 r#"
891 function {get_current_global_task_meta_fn}(componentIdx) {{
892 if (componentIdx === null || componentIdx === undefined) {{
893 throw new Error("missing/invalid component idx");
894 }}
895 const v = {global_current_task_meta_obj}[componentIdx];
896 if (v === undefined || v === null) {{
897 return undefined;
898 }}
899 return {{ ...v }};
900 }}
901 "#,
902 );
903 }
904
905 Self::SetGlobalCurrentTaskMetaFn => {
906 let set_global_current_task_meta_fn = self.name();
907 let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
908
909 uwriteln!(
910 output,
911 r#"
912 function {set_global_current_task_meta_fn}(args) {{
913 if (!args) {{ throw new TypeError('args missing'); }}
914 if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
915 if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
916 const {{ taskID, componentIdx }} = args;
917 return {global_current_task_meta_obj}[componentIdx] = {{ taskID, componentIdx }};
918 }}
919 "#,
920 );
921 }
922
923 Self::WithGlobalCurrentTaskMetaFn => {
924 let debug_log_fn = Intrinsic::DebugLog.name();
925 let with_global_current_task_meta_fn = Self::WithGlobalCurrentTaskMetaFn.name();
926 let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
927
928 output.push_str(&format!(
929 r#"
930 function {with_global_current_task_meta_fn}(args) {{
931 {debug_log_fn}('[{with_global_current_task_meta_fn}()] args', args);
932 if (!args) {{ throw new TypeError('args missing'); }}
933 if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
934 if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
935 if (!args.fn) {{ throw new TypeError('missing fn'); }}
936 const {{ taskID, componentIdx, fn }} = args;
937
938 try {{
939 {global_current_task_meta_obj}[componentIdx] = {{ taskID, componentIdx }};
940 return fn();
941 }} catch (err) {{
942 {debug_log_fn}("error while executing sync callee/callback", {{
943 ...args,
944 err,
945 }});
946 throw err;
947 }} finally {{
948 {global_current_task_meta_obj}[componentIdx] = null;
949 }}
950 }}
951 "#,
952 ));
953 }
954
955 Self::WithGlobalCurrentTaskMetaFnAsync => {
982 let debug_log_fn = Intrinsic::DebugLog.name();
983 let with_global_current_task_meta_async_fn =
984 Self::WithGlobalCurrentTaskMetaFnAsync.name();
985 let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
986
987 output.push_str(&format!(
988 r#"
989 async function {with_global_current_task_meta_async_fn}(args) {{
990 {debug_log_fn}('[{with_global_current_task_meta_async_fn}()] args', args);
991 if (!args) {{ throw new TypeError('args missing'); }}
992 if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
993 if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
994 if (!args.fn) {{ throw new TypeError('missing fn'); }}
995
996 const {{ taskID, componentIdx, fn }} = args;
997
998 try {{
999 {global_current_task_meta_obj}[componentIdx] = {{ taskID, componentIdx }};
1000 return await fn();
1001 }} catch (err) {{
1002 {debug_log_fn}("error while executing async callee/callback", {{
1003 ...args,
1004 err,
1005 }});
1006 throw err;
1007 }} finally {{
1008 {global_current_task_meta_obj}[componentIdx] = null;
1009 }}
1010 }}
1011 "#,
1012 ));
1013 }
1014
1015 Self::ClearGlobalCurrentTaskMetaFn => {
1016 let debug_log_fn = Intrinsic::DebugLog.name();
1017 let clear_global_current_task_meta_fn = Self::ClearGlobalCurrentTaskMetaFn.name();
1018 let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
1019
1020 output.push_str(&format!(
1021 r#"
1022 async function {clear_global_current_task_meta_fn}(args) {{
1023 {debug_log_fn}('[{clear_global_current_task_meta_fn}()] args', args);
1024 if (!args) {{ throw new TypeError('args missing'); }}
1025 if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
1026 if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
1027 const {{ taskID, componentIdx }} = args;
1028
1029 const meta = {global_current_task_meta_obj}[componentIdx];
1030 if (!meta) {{ throw new Error(`missing current task meta for component idx [${{componentIdx}}]`); }}
1031
1032 if (meta.taskID !== taskID) {{
1033 throw new Error(`task ID [${{meta.taskID}}] != requested ID [${{taskID}}]`);
1034 }}
1035 if (meta.componentIdx !== componentIdx) {{
1036 throw new Error(`component idx [${{meta.componentIdx}}] != requested idx [${{componentIdx}}]`);
1037 }}
1038
1039 {global_current_task_meta_obj}[componentIdx] = null;
1040 }}
1041 "#,
1042 ));
1043 }
1044
1045 Intrinsic::PlatformReadableStreamClass => {
1047 let name = self.name();
1048 uwriteln!(
1049 output,
1050 r#"
1051 if (!ReadableStream) {{
1052 throw new Error('builtin stream class [ReadableStream] is not available');
1053 }}
1054 const {name} = ReadableStream;
1055 "#
1056 );
1057 }
1058 }
1059 }
1060}
1061
1062#[derive(Debug, Default, PartialEq, Eq)]
1064pub enum AsyncDeterminismProfile {
1065 #[default]
1067 Random,
1068
1069 #[allow(unused)]
1071 Deterministic,
1072}
1073
1074impl std::fmt::Display for AsyncDeterminismProfile {
1075 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1076 write!(
1077 f,
1078 "{}",
1079 match self {
1080 Self::Deterministic => "deterministic",
1081 Self::Random => "random",
1082 }
1083 )
1084 }
1085}
1086
1087#[derive(bon::Builder)]
1089#[non_exhaustive]
1090pub struct RenderIntrinsicsArgs<'a> {
1091 pub(crate) intrinsics: &'a mut BTreeSet<Intrinsic>,
1093 #[builder(default)]
1095 pub(crate) instantiation_occurred: bool,
1096 #[builder(default)]
1098 pub(crate) determinism_profile: AsyncDeterminismProfile,
1099 pub(crate) transpile_opts: &'a TranspileOpts,
1101}
1102
1103const EARLY_INTRINSICS: [Intrinsic; 43] = [
1105 Intrinsic::PromiseWithResolversPonyfill,
1106 Intrinsic::SymbolDispose,
1107 Intrinsic::SymbolAsyncIterator,
1108 Intrinsic::SymbolIterator,
1109 Intrinsic::DebugLog,
1110 Intrinsic::GlobalAsyncDeterminism,
1111 Intrinsic::GlobalComponentMemoryMap,
1112 Intrinsic::GlobalCurrentTaskMeta,
1113 Intrinsic::GetGlobalCurrentTaskMetaFn,
1114 Intrinsic::SetGlobalCurrentTaskMetaFn,
1115 Intrinsic::WithGlobalCurrentTaskMetaFn,
1116 Intrinsic::WithGlobalCurrentTaskMetaFnAsync,
1117 Intrinsic::ClearGlobalCurrentTaskMetaFn,
1118 Intrinsic::LookupMemoriesForComponent,
1119 Intrinsic::RegisterGlobalMemoryForComponent,
1120 Intrinsic::RepTableClass,
1121 Intrinsic::CoinFlip,
1122 Intrinsic::ScopeId,
1123 Intrinsic::ConstantI32Min,
1125 Intrinsic::ConstantI32Max,
1126 Intrinsic::Conversion(ConversionIntrinsic::IsValidNumericPrimitive),
1127 Intrinsic::Conversion(ConversionIntrinsic::RequireValidNumericPrimitive),
1128 Intrinsic::TypeCheckValidI32,
1129 Intrinsic::TypeCheckAsyncFn,
1130 Intrinsic::Resource(ResourceIntrinsic::ResourceCallBorrows),
1132 Intrinsic::AsyncFunctionCtor,
1134 Intrinsic::AsyncTask(AsyncTaskIntrinsic::ClearCurrentTask),
1135 Intrinsic::AsyncTask(AsyncTaskIntrinsic::CurrentTaskMayBlock),
1136 Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskIds),
1137 Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentComponentIdxs),
1138 Intrinsic::AsyncTask(AsyncTaskIntrinsic::UnpackCallbackResult),
1139 Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncSubtaskClass),
1140 Intrinsic::Host(HostIntrinsic::PrepareCall),
1142 Intrinsic::Host(HostIntrinsic::AsyncStartCall),
1143 Intrinsic::Host(HostIntrinsic::SyncStartCall),
1144 Intrinsic::Waitable(WaitableIntrinsic::WaitableClass),
1146 Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalErrCtxTableMap),
1148 Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextGet),
1151 Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextSet),
1152 Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskMap),
1154 Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass),
1155 Intrinsic::AsyncEventCodeEnum,
1156 Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask),
1157];
1158
1159pub fn render_intrinsics(args: RenderIntrinsicsArgs) -> Source {
1162 let mut output = Source::default();
1163 let mut rendered_intrinsics = HashSet::new();
1164
1165 for intrinsic in EARLY_INTRINSICS {
1167 intrinsic.render(&mut output, &args);
1168 rendered_intrinsics.insert(intrinsic.name());
1169 }
1170
1171 if args.intrinsics.contains(&Intrinsic::GetErrorPayload)
1173 || args.intrinsics.contains(&Intrinsic::GetErrorPayloadString)
1174 {
1175 args.intrinsics.insert(Intrinsic::HasOwnProperty);
1176 }
1177 if args
1178 .intrinsics
1179 .contains(&Intrinsic::String(StringIntrinsic::Utf16Encode))
1180 {
1181 args.intrinsics.insert(Intrinsic::IsLE);
1182 }
1183
1184 if args
1185 .intrinsics
1186 .contains(&Intrinsic::Conversion(ConversionIntrinsic::F32ToI32))
1187 || args
1188 .intrinsics
1189 .contains(&Intrinsic::Conversion(ConversionIntrinsic::I32ToF32))
1190 {
1191 output.push_str(
1192 "
1193 const i32ToF32I = new Int32Array(1);
1194 const i32ToF32F = new Float32Array(i32ToF32I.buffer);
1195 ",
1196 );
1197 }
1198
1199 if args
1200 .intrinsics
1201 .contains(&Intrinsic::Conversion(ConversionIntrinsic::F64ToI64))
1202 || args
1203 .intrinsics
1204 .contains(&Intrinsic::Conversion(ConversionIntrinsic::I64ToF64))
1205 {
1206 output.push_str(
1207 "
1208 const i64ToF64I = new BigInt64Array(1);
1209 const i64ToF64F = new Float64Array(i64ToF64I.buffer);
1210 ",
1211 );
1212 }
1213
1214 if args.intrinsics.contains(&Intrinsic::Resource(
1215 ResourceIntrinsic::ResourceTransferBorrow,
1216 )) || args.intrinsics.contains(&Intrinsic::Resource(
1217 ResourceIntrinsic::ResourceTransferBorrowValidLifting,
1218 )) {
1219 args.intrinsics.insert(Intrinsic::Resource(
1220 ResourceIntrinsic::ResourceTableCreateBorrow,
1221 ));
1222 }
1223
1224 if args
1225 .intrinsics
1226 .contains(&Intrinsic::String(StringIntrinsic::Utf8Encode))
1227 || args
1228 .intrinsics
1229 .contains(&Intrinsic::String(StringIntrinsic::Utf8EncodeAsync))
1230 {
1231 args.intrinsics.extend([
1232 &Intrinsic::IsLE,
1233 &Intrinsic::String(StringIntrinsic::GlobalTextEncoderUtf8),
1234 ]);
1235 }
1236
1237 if args
1238 .intrinsics
1239 .contains(&Intrinsic::String(StringIntrinsic::Utf16Encode))
1240 || args
1241 .intrinsics
1242 .contains(&Intrinsic::String(StringIntrinsic::Utf16EncodeAsync))
1243 {
1244 args.intrinsics.extend([&Intrinsic::IsLE]);
1245 }
1246
1247 if args.intrinsics.contains(&Intrinsic::ErrCtx(
1249 ErrCtxIntrinsic::ErrorContextDebugMessage,
1250 )) {
1251 args.intrinsics.extend([
1252 &Intrinsic::String(StringIntrinsic::Utf8Encode),
1253 &Intrinsic::String(StringIntrinsic::Utf16Encode),
1254 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
1255 ]);
1256 }
1257
1258 if args
1259 .intrinsics
1260 .contains(&Intrinsic::ErrCtx(ErrCtxIntrinsic::ErrorContextNew))
1261 {
1262 args.intrinsics.extend([
1263 &Intrinsic::ErrCtx(ErrCtxIntrinsic::ComponentGlobalTable),
1264 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalRefCountAdd),
1265 &Intrinsic::ErrCtx(ErrCtxIntrinsic::ReserveGlobalRep),
1266 &Intrinsic::ErrCtx(ErrCtxIntrinsic::CreateLocalHandle),
1267 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
1268 ]);
1269 }
1270
1271 if args.intrinsics.contains(&Intrinsic::ErrCtx(
1272 ErrCtxIntrinsic::ErrorContextDebugMessage,
1273 )) {
1274 args.intrinsics.extend([
1275 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalRefCountAdd),
1276 &Intrinsic::ErrCtx(ErrCtxIntrinsic::ErrorContextDrop),
1277 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
1278 ]);
1279 }
1280
1281 if args
1282 .intrinsics
1283 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::DriverLoop))
1284 {
1285 args.intrinsics.extend([
1286 &Intrinsic::TypeCheckValidI32,
1287 &Intrinsic::Conversion(ConversionIntrinsic::ToInt32),
1288 &Intrinsic::Component(ComponentIntrinsic::ComponentStateSetAllError),
1289 ]);
1290 }
1291
1292 if args.intrinsics.contains(&Intrinsic::Component(
1293 ComponentIntrinsic::GetOrCreateAsyncState,
1294 )) {
1295 args.intrinsics.extend([&Intrinsic::RepTableClass]);
1296 }
1297
1298 if args
1299 .intrinsics
1300 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass))
1301 {
1302 args.intrinsics.extend([
1303 &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1304 &Intrinsic::Component(ComponentIntrinsic::GlobalAsyncStateMap),
1305 &Intrinsic::RepTableClass,
1306 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncSubtaskClass),
1307 &Intrinsic::Waitable(WaitableIntrinsic::WaitableClass),
1308 ]);
1309 }
1310
1311 if args
1312 .intrinsics
1313 .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetNew))
1314 {
1315 args.intrinsics
1316 .extend([&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetClass)]);
1317 }
1318
1319 if args
1320 .intrinsics
1321 .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetPoll))
1322 || args
1323 .intrinsics
1324 .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetWait))
1325 {
1326 args.intrinsics
1327 .extend([&Intrinsic::Host(HostIntrinsic::StoreEventInComponentMemory)]);
1328 }
1329
1330 if args
1331 .intrinsics
1332 .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetDrop))
1333 {
1334 args.intrinsics
1335 .extend([&Intrinsic::Waitable(WaitableIntrinsic::RemoveWaitableSet)]);
1336 }
1337
1338 if args.intrinsics.contains(&Intrinsic::Component(
1339 ComponentIntrinsic::GetOrCreateAsyncState,
1340 )) {
1341 args.intrinsics.extend([
1342 &Intrinsic::Component(ComponentIntrinsic::ComponentAsyncStateClass),
1343 &Intrinsic::Component(ComponentIntrinsic::GlobalAsyncStateMap),
1344 ]);
1345 }
1346
1347 if args.intrinsics.contains(&Intrinsic::Component(
1348 ComponentIntrinsic::ComponentAsyncStateClass,
1349 )) {
1350 args.intrinsics.extend([&Intrinsic::AsyncStream(
1351 AsyncStreamIntrinsic::GlobalStreamMap,
1352 )]);
1353 }
1354
1355 if args
1356 .intrinsics
1357 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatResult))
1358 | args
1359 .intrinsics
1360 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatOption))
1361 | args
1362 .intrinsics
1363 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatOption))
1364 {
1365 args.intrinsics
1366 .extend([&Intrinsic::Lift(LiftIntrinsic::LiftFlatVariant)]);
1367 }
1368
1369 if args
1370 .intrinsics
1371 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatVariant))
1372 {
1373 args.intrinsics.extend([
1374 &Intrinsic::Lift(LiftIntrinsic::LiftFlatU8),
1375 &Intrinsic::Lift(LiftIntrinsic::LiftFlatU16),
1376 &Intrinsic::Lift(LiftIntrinsic::LiftFlatU32),
1377 &Intrinsic::Lift(LiftIntrinsic::LiftFlatFloat64),
1378 ]);
1379 }
1380
1381 if args
1382 .intrinsics
1383 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatResult))
1384 {
1385 args.intrinsics
1386 .insert(Intrinsic::Lower(LowerIntrinsic::LowerFlatVariant));
1387 }
1388
1389 if args
1390 .intrinsics
1391 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatOption))
1392 {
1393 args.intrinsics
1394 .insert(Intrinsic::Lower(LowerIntrinsic::LowerFlatVariant));
1395 }
1396
1397 if args
1398 .intrinsics
1399 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatVariant))
1400 {
1401 args.intrinsics.extend([
1402 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU8),
1403 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU16),
1404 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU32),
1405 ]);
1406 }
1407
1408 if args
1409 .intrinsics
1410 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStream))
1411 {
1412 args.intrinsics.extend([
1413 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamMap),
1414 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::ExternalStreamClass),
1415 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::InternalStreamClass),
1416 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::IsStreamLowerableObject),
1417 &Intrinsic::SymbolResourceRep,
1418 &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1419 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GenReadFnFromLowerableStream),
1420 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GenStreamHostInjectFn),
1421 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU32),
1422 ])
1423 }
1424
1425 if args.intrinsics.contains(&Intrinsic::AsyncStream(
1426 AsyncStreamIntrinsic::GenStreamHostInjectFn,
1427 )) {
1428 args.intrinsics.insert(Intrinsic::AsyncStream(
1429 AsyncStreamIntrinsic::PendingValueQueueClass,
1430 ));
1431 }
1432
1433 if args
1434 .intrinsics
1435 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatFuture))
1436 {
1437 args.intrinsics.extend([
1438 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureMap),
1439 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1440 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::InternalFutureClass),
1441 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::IsFutureLowerableObject),
1442 &Intrinsic::SymbolResourceRep,
1443 &Intrinsic::GetErrorPayload,
1444 &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1445 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GenFutureHostInjectFn),
1446 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU32),
1447 ])
1448 }
1449
1450 if args
1451 .intrinsics
1452 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStringAny))
1453 {
1454 args.intrinsics.extend([
1455 &Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf8),
1456 &Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf16),
1457 ]);
1458 }
1459
1460 if args
1461 .intrinsics
1462 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf8))
1463 {
1464 args.intrinsics
1465 .insert(Intrinsic::String(StringIntrinsic::GlobalTextDecoderUtf8));
1466 }
1467
1468 if args
1469 .intrinsics
1470 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStringAny))
1471 {
1472 args.intrinsics.extend([
1473 &Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf8),
1474 &Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf16),
1475 ]);
1476 }
1477
1478 if args
1479 .intrinsics
1480 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf8))
1481 {
1482 args.intrinsics
1483 .insert(Intrinsic::String(StringIntrinsic::GlobalTextEncoderUtf8));
1484 }
1485
1486 if args
1487 .intrinsics
1488 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf16))
1489 {
1490 args.intrinsics
1491 .insert(Intrinsic::String(StringIntrinsic::Utf16Decoder));
1492 }
1493
1494 if args
1495 .intrinsics
1496 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStream))
1497 {
1498 args.intrinsics.insert(Intrinsic::AsyncStream(
1499 AsyncStreamIntrinsic::ExternalStreamClass,
1500 ));
1501 }
1502
1503 if args.intrinsics.contains(&Intrinsic::AsyncTask(
1504 AsyncTaskIntrinsic::CreateNewCurrentTask,
1505 )) || args
1506 .intrinsics
1507 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask))
1508 || args
1509 .intrinsics
1510 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::ClearCurrentTask))
1511 {
1512 args.intrinsics.extend([
1513 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass),
1514 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskMap),
1515 ]);
1516 }
1517
1518 if args
1519 .intrinsics
1520 .contains(&Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamNew))
1521 {
1522 args.intrinsics.extend([
1523 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamMap),
1524 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamTableMap),
1525 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamWritableEndClass),
1526 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamReadableEndClass),
1527 ]);
1528 }
1529
1530 if args.intrinsics.contains(&Intrinsic::AsyncStream(
1531 AsyncStreamIntrinsic::StreamWritableEndClass,
1532 )) || args.intrinsics.contains(&Intrinsic::AsyncStream(
1533 AsyncStreamIntrinsic::StreamReadableEndClass,
1534 )) {
1535 args.intrinsics.extend([
1536 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::InternalStreamClass),
1537 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamEndClass),
1538 &Intrinsic::AsyncEventCodeEnum,
1539 ]);
1540 }
1541
1542 if args.intrinsics.contains(&Intrinsic::AsyncStream(
1543 AsyncStreamIntrinsic::StreamNewFromLift,
1544 )) {
1545 args.intrinsics.extend([
1546 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamMap),
1547 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamTableMap),
1548 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::HostStreamClass),
1549 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::ExternalStreamClass),
1550 &Intrinsic::GlobalBufferManager,
1551 ]);
1552 }
1553
1554 if args
1555 .intrinsics
1556 .contains(&Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamWrite))
1557 || args
1558 .intrinsics
1559 .contains(&Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamRead))
1560 || args
1561 .intrinsics
1562 .contains(&Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureWrite))
1563 || args
1564 .intrinsics
1565 .contains(&Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureRead))
1566 {
1567 args.intrinsics.extend([
1568 &Intrinsic::GlobalBufferManager,
1569 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncBlockedConstant),
1570 &Intrinsic::AsyncEventCodeEnum,
1571 ]);
1572 }
1573
1574 if args
1575 .intrinsics
1576 .contains(&Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureNew))
1577 {
1578 args.intrinsics.extend([
1579 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureMap),
1580 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1581 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureTableMap),
1582 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureWritableEndClass),
1583 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureReadableEndClass),
1584 ]);
1585 }
1586
1587 if args.intrinsics.contains(&Intrinsic::AsyncFuture(
1588 AsyncFutureIntrinsic::FutureNewFromLift,
1589 )) {
1590 args.intrinsics.extend([
1591 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1592 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureMap),
1593 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::HostFutureClass),
1594 &Intrinsic::GlobalBufferManager,
1595 ]);
1596 }
1597
1598 if args.intrinsics.contains(&Intrinsic::AsyncFuture(
1599 AsyncFutureIntrinsic::FutureWritableEndClass,
1600 )) || args.intrinsics.contains(&Intrinsic::AsyncFuture(
1601 AsyncFutureIntrinsic::FutureReadableEndClass,
1602 )) {
1603 args.intrinsics.extend([
1604 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1605 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::InternalFutureClass),
1606 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureEndClass),
1607 &Intrinsic::AsyncEventCodeEnum,
1608 ]);
1609 }
1610
1611 if args.intrinsics.contains(&Intrinsic::GlobalBufferManager) {
1612 args.intrinsics.extend([&Intrinsic::BufferManagerClass]);
1613 }
1614
1615 if args.intrinsics.contains(&Intrinsic::BufferManagerClass) {
1616 args.intrinsics.extend([&Intrinsic::ManagedBufferClass]);
1617 }
1618
1619 if args.intrinsics.contains(&Intrinsic::AsyncTask(
1620 AsyncTaskIntrinsic::EnterSymmetricSyncGuestCall,
1621 )) || args.intrinsics.contains(&Intrinsic::AsyncTask(
1622 AsyncTaskIntrinsic::ExitSymmetricSyncGuestCall,
1623 )) {
1624 args.intrinsics.extend([
1625 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentComponentIdxs),
1626 &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1627 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask),
1628 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskIds),
1629 &Intrinsic::ClearGlobalCurrentTaskMetaFn,
1630 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::SymmetricSyncGuestCallStack),
1631 ]);
1632 }
1633
1634 for current_intrinsic in args.intrinsics.iter() {
1635 if rendered_intrinsics.contains(current_intrinsic.name()) {
1637 continue;
1638 }
1639
1640 current_intrinsic.render(&mut output, &args);
1641 }
1642
1643 output
1644}
1645
1646impl Intrinsic {
1647 pub fn get_global_names() -> impl IntoIterator<Item = &'static str> {
1648 JsHelperIntrinsic::get_global_names()
1649 .into_iter()
1650 .chain(vec![
1651 "base64Compile",
1653 "clampGuest",
1654 "ComponentError",
1655 "fetchCompile",
1656 "finalizationRegistryCreate",
1657 "getErrorPayload",
1658 "HANDLE_TABLES",
1659 "hasOwnProperty",
1660 "imports",
1661 "instantiateCore",
1662 "isLE",
1663 "scopeId",
1664 "symbolCabiDispose",
1665 "symbolCabiLower",
1666 "symbolDispose",
1667 "symbolAsyncIterator",
1668 "symbolIterator",
1669 "symbolRscHandle",
1670 "symbolRscRep",
1671 "T_FLAG",
1672 "throwInvalidBool",
1673 "throwUninitialized",
1674 "ArrayBuffer",
1676 "BigInt",
1677 "BigInt64Array",
1678 "DataView",
1679 "dv",
1680 "emptyFunc",
1681 "Error",
1682 "fetch",
1683 "Float32Array",
1684 "Float64Array",
1685 "Int32Array",
1686 "Object",
1687 "process",
1688 "String",
1689 "TextDecoder",
1690 "TextEncoder",
1691 "TypeError",
1692 "Uint16Array",
1693 "Uint8Array",
1694 "URL",
1695 "WebAssembly",
1696 "GlobalComponentMemories",
1697 ])
1698 }
1699
1700 pub fn name(&self) -> &'static str {
1701 match self {
1702 Intrinsic::JsHelper(i) => i.name(),
1703 Intrinsic::Conversion(i) => i.name(),
1704 Intrinsic::WebIdl(i) => i.name(),
1705 Intrinsic::String(i) => i.name(),
1706 Intrinsic::ErrCtx(i) => i.name(),
1707 Intrinsic::AsyncTask(i) => i.name(),
1708 Intrinsic::Waitable(i) => i.name(),
1709 Intrinsic::Resource(i) => i.name(),
1710 Intrinsic::Lift(i) => i.name(),
1711 Intrinsic::Lower(i) => i.name(),
1712 Intrinsic::AsyncStream(i) => i.name(),
1713 Intrinsic::AsyncFuture(i) => i.name(),
1714 Intrinsic::Component(i) => i.name(),
1715 Intrinsic::Host(i) => i.name(),
1716
1717 Intrinsic::Base64Compile => "base64Compile",
1718 Intrinsic::ClampGuest => "clampGuest",
1719 Intrinsic::ComponentError => "ComponentError",
1720 Intrinsic::FetchCompile => "fetchCompile",
1721 Intrinsic::FinalizationRegistryCreate => "finalizationRegistryCreate",
1722 Intrinsic::GetErrorPayload => "getErrorPayload",
1723 Intrinsic::GetErrorPayloadString => "getErrorPayloadString",
1724 Intrinsic::HandleTables => "HANDLE_TABLES",
1725 Intrinsic::HasOwnProperty => "hasOwnProperty",
1726 Intrinsic::InstantiateCore => "instantiateCore",
1727 Intrinsic::IsLE => "isLE",
1728 Intrinsic::ScopeId => "SCOPE_ID",
1729
1730 Intrinsic::SymbolCabiDispose => "symbolCabiDispose",
1731 Intrinsic::SymbolCabiLower => "symbolCabiLower",
1732 Intrinsic::SymbolDispose => "symbolDispose",
1733 Intrinsic::SymbolAsyncIterator => "symbolAsyncIterator",
1734 Intrinsic::SymbolIterator => "symbolIterator",
1735 Intrinsic::SymbolResourceHandle => "symbolRscHandle",
1736 Intrinsic::SymbolResourceRep => "symbolRscRep",
1737
1738 Intrinsic::ThrowInvalidBool => "throwInvalidBool",
1739 Intrinsic::ThrowUninitialized => "throwUninitialized",
1740
1741 Intrinsic::DebugLog => "_debugLog",
1743 Intrinsic::PromiseWithResolversPonyfill => "promiseWithResolvers",
1744
1745 Intrinsic::ConstantI32Min => "I32_MIN",
1747 Intrinsic::ConstantI32Max => "I32_MAX",
1748 Intrinsic::TypeCheckValidI32 => "_typeCheckValidI32",
1749 Intrinsic::TypeCheckAsyncFn => "_typeCheckAsyncFn",
1750 Intrinsic::AsyncFunctionCtor => "ASYNC_FN_CTOR",
1751
1752 Intrinsic::PlatformReadableStreamClass => "_PlatformReadableStream",
1754
1755 Intrinsic::GlobalAsyncDeterminism => "ASYNC_DETERMINISM",
1757 Intrinsic::CoinFlip => "_coinFlip",
1758
1759 Self::GlobalCurrentTaskMeta => "CURRENT_TASK_META",
1761 Self::GetGlobalCurrentTaskMetaFn => "_getGlobalCurrentTaskMeta",
1762 Self::SetGlobalCurrentTaskMetaFn => "_setGlobalCurrentTaskMeta",
1763 Self::WithGlobalCurrentTaskMetaFn => "_withGlobalCurrentTaskMeta",
1764 Self::WithGlobalCurrentTaskMetaFnAsync => "_withGlobalCurrentTaskMetaAsync",
1765 Self::ClearGlobalCurrentTaskMetaFn => "_clearCurrentTask",
1766
1767 Intrinsic::GlobalComponentMemoryMap => "GLOBAL_COMPONENT_MEMORY_MAP",
1769 Intrinsic::RegisterGlobalMemoryForComponent => "registerGlobalMemoryForComponent",
1770 Intrinsic::LookupMemoriesForComponent => "lookupMemoriesForComponent",
1771
1772 Intrinsic::RepTableClass => "RepTable",
1774
1775 Intrinsic::ManagedBufferClass => "ManagedBuffer",
1777 Intrinsic::BufferManagerClass => "BufferManager",
1778 Intrinsic::GlobalBufferManager => "BUFFER_MGR",
1779
1780 Intrinsic::AsyncEventCodeEnum => "ASYNC_EVENT_CODE",
1782 }
1783 }
1784}