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 const v = {global_current_task_meta_obj}[componentIdx];
893 if (v === undefined || v === null) {{ return undefined; }}
894 return {{ ...v }};
895 }}
896 "#,
897 );
898 }
899
900 Self::SetGlobalCurrentTaskMetaFn => {
901 let set_global_current_task_meta_fn = self.name();
902 let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
903
904 uwriteln!(
905 output,
906 r#"
907 function {set_global_current_task_meta_fn}(args) {{
908 if (!args) {{ throw new TypeError('args missing'); }}
909 if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
910 if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
911 const {{ taskID, componentIdx }} = args;
912 return {global_current_task_meta_obj}[componentIdx] = {{ taskID, componentIdx }};
913 }}
914 "#,
915 );
916 }
917
918 Self::WithGlobalCurrentTaskMetaFn => {
919 let debug_log_fn = Intrinsic::DebugLog.name();
920 let with_global_current_task_meta_fn = Self::WithGlobalCurrentTaskMetaFn.name();
921 let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
922
923 output.push_str(&format!(
924 r#"
925 function {with_global_current_task_meta_fn}(args) {{
926 {debug_log_fn}('[{with_global_current_task_meta_fn}()] args', args);
927 if (!args) {{ throw new TypeError('args missing'); }}
928 if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
929 if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
930 if (!args.fn) {{ throw new TypeError('missing fn'); }}
931 const {{ taskID, componentIdx, fn }} = args;
932
933 try {{
934 {global_current_task_meta_obj}[componentIdx] = {{ taskID, componentIdx }};
935 return fn();
936 }} catch (err) {{
937 {debug_log_fn}("error while executing sync callee/callback", {{
938 ...args,
939 err,
940 }});
941 throw err;
942 }} finally {{
943 {global_current_task_meta_obj}[componentIdx] = null;
944 }}
945 }}
946 "#,
947 ));
948 }
949
950 Self::WithGlobalCurrentTaskMetaFnAsync => {
951 let debug_log_fn = Intrinsic::DebugLog.name();
952 let with_global_current_task_meta_async_fn =
953 Self::WithGlobalCurrentTaskMetaFnAsync.name();
954 let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
955 let get_or_create_async_state_fn = ComponentIntrinsic::GetOrCreateAsyncState.name();
956
957 output.push_str(&format!(
958 r#"
959 async function {with_global_current_task_meta_async_fn}(args) {{
960 {debug_log_fn}('[{with_global_current_task_meta_async_fn}()] args', args);
961 if (!args) {{ throw new TypeError('args missing'); }}
962 if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
963 if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
964 if (!args.fn) {{ throw new TypeError('missing fn'); }}
965 const {{ taskID, componentIdx, fn }} = args;
966
967 // If there is already an async task executing, we must wait for it
968 // to complete before we can can run the closure we were given
969 //
970 let current = {global_current_task_meta_obj}[componentIdx];
971 let cstate;
972 if (current && current.taskID !== taskID) {{
973 cstate = {get_or_create_async_state_fn}(componentIdx);
974 while (current && current.taskID !== taskID) {{
975 const {{ promise, resolve }} = Promise.withResolvers();
976 cstate.onNextExclusiveRelease(resolve);
977 await promise;
978 current = {global_current_task_meta_obj}[componentIdx];
979 }}
980
981 // Since we've just waited for the component to not be locked, re-lock
982 // exclusivity so we can run the fn below (likely a callee/callback)
983 cstate.exclusiveLock();
984 }}
985
986 try {{
987 {global_current_task_meta_obj}[componentIdx] = {{ taskID, componentIdx }};
988 return await fn();
989 }} catch (err) {{
990 {debug_log_fn}("error while executing async callee/callback", {{
991 ...args,
992 err,
993 }});
994 throw err;
995 }} finally {{
996 {global_current_task_meta_obj}[componentIdx] = null;
997 }}
998 }}
999 "#,
1000 ));
1001 }
1002
1003 Self::ClearGlobalCurrentTaskMetaFn => {
1004 let debug_log_fn = Intrinsic::DebugLog.name();
1005 let clear_global_current_task_meta_fn = Self::ClearGlobalCurrentTaskMetaFn.name();
1006 let global_current_task_meta_obj = Self::GlobalCurrentTaskMeta.name();
1007
1008 output.push_str(&format!(
1009 r#"
1010 async function {clear_global_current_task_meta_fn}(args) {{
1011 {debug_log_fn}('[{clear_global_current_task_meta_fn}()] args', args);
1012 if (!args) {{ throw new TypeError('args missing'); }}
1013 if (args.taskID === undefined) {{ throw new TypeError('missing task ID'); }}
1014 if (args.componentIdx === undefined) {{ throw new TypeError('missing component idx'); }}
1015 const {{ taskID, componentIdx }} = args;
1016
1017 const meta = {global_current_task_meta_obj}[componentIdx];
1018 if (!meta) {{ throw new Error(`missing current task meta for component idx [${{componentIdx}}]n`); }}
1019
1020 if (meta.taskID !== taskID) {{
1021 throw new Error(`task ID [${{meta.taskID}}] != requested ID [${{taskID}}]`);
1022 }}
1023 if (meta.componentIdx !== componentIdx) {{
1024 throw new Error(`component idx [${{meta.componentIdx}}] != requested idx [${{componentIdx}}]`);
1025 }}
1026
1027 {global_current_task_meta_obj}[componentIdx] = null;
1028 }}
1029 "#,
1030 ));
1031 }
1032
1033 Intrinsic::PlatformReadableStreamClass => {
1035 let name = self.name();
1036 uwriteln!(
1037 output,
1038 r#"
1039 if (!ReadableStream) {{
1040 throw new Error('builtin stream class [ReadableStream] is not available');
1041 }}
1042 const {name} = ReadableStream;
1043 "#
1044 );
1045 }
1046 }
1047 }
1048}
1049
1050#[derive(Debug, Default, PartialEq, Eq)]
1052pub enum AsyncDeterminismProfile {
1053 #[default]
1055 Random,
1056
1057 #[allow(unused)]
1059 Deterministic,
1060}
1061
1062impl std::fmt::Display for AsyncDeterminismProfile {
1063 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1064 write!(
1065 f,
1066 "{}",
1067 match self {
1068 Self::Deterministic => "deterministic",
1069 Self::Random => "random",
1070 }
1071 )
1072 }
1073}
1074
1075#[derive(bon::Builder)]
1077#[non_exhaustive]
1078pub struct RenderIntrinsicsArgs<'a> {
1079 pub(crate) intrinsics: &'a mut BTreeSet<Intrinsic>,
1081 #[builder(default)]
1083 pub(crate) instantiation_occurred: bool,
1084 #[builder(default)]
1086 pub(crate) determinism_profile: AsyncDeterminismProfile,
1087 pub(crate) transpile_opts: &'a TranspileOpts,
1089}
1090
1091const EARLY_INTRINSICS: [Intrinsic; 37] = [
1093 Intrinsic::PromiseWithResolversPonyfill,
1094 Intrinsic::SymbolDispose,
1095 Intrinsic::SymbolAsyncIterator,
1096 Intrinsic::SymbolIterator,
1097 Intrinsic::DebugLog,
1098 Intrinsic::GlobalAsyncDeterminism,
1099 Intrinsic::GlobalComponentMemoryMap,
1100 Intrinsic::GlobalCurrentTaskMeta,
1101 Intrinsic::GetGlobalCurrentTaskMetaFn,
1102 Intrinsic::SetGlobalCurrentTaskMetaFn,
1103 Intrinsic::WithGlobalCurrentTaskMetaFn,
1104 Intrinsic::WithGlobalCurrentTaskMetaFnAsync,
1105 Intrinsic::ClearGlobalCurrentTaskMetaFn,
1106 Intrinsic::LookupMemoriesForComponent,
1107 Intrinsic::RegisterGlobalMemoryForComponent,
1108 Intrinsic::RepTableClass,
1109 Intrinsic::CoinFlip,
1110 Intrinsic::ScopeId,
1111 Intrinsic::ConstantI32Min,
1113 Intrinsic::ConstantI32Max,
1114 Intrinsic::Conversion(ConversionIntrinsic::IsValidNumericPrimitive),
1115 Intrinsic::Conversion(ConversionIntrinsic::RequireValidNumericPrimitive),
1116 Intrinsic::TypeCheckValidI32,
1117 Intrinsic::TypeCheckAsyncFn,
1118 Intrinsic::Resource(ResourceIntrinsic::ResourceCallBorrows),
1120 Intrinsic::AsyncFunctionCtor,
1122 Intrinsic::AsyncTask(AsyncTaskIntrinsic::ClearCurrentTask),
1123 Intrinsic::AsyncTask(AsyncTaskIntrinsic::CurrentTaskMayBlock),
1124 Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskIds),
1125 Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentComponentIdxs),
1126 Intrinsic::AsyncTask(AsyncTaskIntrinsic::UnpackCallbackResult),
1127 Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncSubtaskClass),
1128 Intrinsic::Host(HostIntrinsic::PrepareCall),
1130 Intrinsic::Host(HostIntrinsic::AsyncStartCall),
1131 Intrinsic::Host(HostIntrinsic::SyncStartCall),
1132 Intrinsic::Waitable(WaitableIntrinsic::WaitableClass),
1134 Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalErrCtxTableMap),
1136];
1137
1138pub fn render_intrinsics(args: RenderIntrinsicsArgs) -> Source {
1141 let mut output = Source::default();
1142 let mut rendered_intrinsics = HashSet::new();
1143
1144 for intrinsic in EARLY_INTRINSICS {
1146 intrinsic.render(&mut output, &args);
1147 rendered_intrinsics.insert(intrinsic.name());
1148 }
1149
1150 if args.intrinsics.contains(&Intrinsic::GetErrorPayload)
1152 || args.intrinsics.contains(&Intrinsic::GetErrorPayloadString)
1153 {
1154 args.intrinsics.insert(Intrinsic::HasOwnProperty);
1155 }
1156 if args
1157 .intrinsics
1158 .contains(&Intrinsic::String(StringIntrinsic::Utf16Encode))
1159 {
1160 args.intrinsics.insert(Intrinsic::IsLE);
1161 }
1162
1163 if args
1164 .intrinsics
1165 .contains(&Intrinsic::Conversion(ConversionIntrinsic::F32ToI32))
1166 || args
1167 .intrinsics
1168 .contains(&Intrinsic::Conversion(ConversionIntrinsic::I32ToF32))
1169 {
1170 output.push_str(
1171 "
1172 const i32ToF32I = new Int32Array(1);
1173 const i32ToF32F = new Float32Array(i32ToF32I.buffer);
1174 ",
1175 );
1176 }
1177
1178 if args
1179 .intrinsics
1180 .contains(&Intrinsic::Conversion(ConversionIntrinsic::F64ToI64))
1181 || args
1182 .intrinsics
1183 .contains(&Intrinsic::Conversion(ConversionIntrinsic::I64ToF64))
1184 {
1185 output.push_str(
1186 "
1187 const i64ToF64I = new BigInt64Array(1);
1188 const i64ToF64F = new Float64Array(i64ToF64I.buffer);
1189 ",
1190 );
1191 }
1192
1193 if args.intrinsics.contains(&Intrinsic::Resource(
1194 ResourceIntrinsic::ResourceTransferBorrow,
1195 )) || args.intrinsics.contains(&Intrinsic::Resource(
1196 ResourceIntrinsic::ResourceTransferBorrowValidLifting,
1197 )) {
1198 args.intrinsics.insert(Intrinsic::Resource(
1199 ResourceIntrinsic::ResourceTableCreateBorrow,
1200 ));
1201 }
1202
1203 if args
1204 .intrinsics
1205 .contains(&Intrinsic::String(StringIntrinsic::Utf8Encode))
1206 || args
1207 .intrinsics
1208 .contains(&Intrinsic::String(StringIntrinsic::Utf8EncodeAsync))
1209 {
1210 args.intrinsics.extend([
1211 &Intrinsic::IsLE,
1212 &Intrinsic::String(StringIntrinsic::GlobalTextEncoderUtf8),
1213 ]);
1214 }
1215
1216 if args
1217 .intrinsics
1218 .contains(&Intrinsic::String(StringIntrinsic::Utf16Encode))
1219 || args
1220 .intrinsics
1221 .contains(&Intrinsic::String(StringIntrinsic::Utf16EncodeAsync))
1222 {
1223 args.intrinsics.extend([&Intrinsic::IsLE]);
1224 }
1225
1226 if args.intrinsics.contains(&Intrinsic::ErrCtx(
1228 ErrCtxIntrinsic::ErrorContextDebugMessage,
1229 )) {
1230 args.intrinsics.extend([
1231 &Intrinsic::String(StringIntrinsic::Utf8Encode),
1232 &Intrinsic::String(StringIntrinsic::Utf16Encode),
1233 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
1234 ]);
1235 }
1236
1237 if args
1238 .intrinsics
1239 .contains(&Intrinsic::ErrCtx(ErrCtxIntrinsic::ErrorContextNew))
1240 {
1241 args.intrinsics.extend([
1242 &Intrinsic::ErrCtx(ErrCtxIntrinsic::ComponentGlobalTable),
1243 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalRefCountAdd),
1244 &Intrinsic::ErrCtx(ErrCtxIntrinsic::ReserveGlobalRep),
1245 &Intrinsic::ErrCtx(ErrCtxIntrinsic::CreateLocalHandle),
1246 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
1247 ]);
1248 }
1249
1250 if args.intrinsics.contains(&Intrinsic::ErrCtx(
1251 ErrCtxIntrinsic::ErrorContextDebugMessage,
1252 )) {
1253 args.intrinsics.extend([
1254 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalRefCountAdd),
1255 &Intrinsic::ErrCtx(ErrCtxIntrinsic::ErrorContextDrop),
1256 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
1257 ]);
1258 }
1259
1260 if args
1261 .intrinsics
1262 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextGet))
1263 || args
1264 .intrinsics
1265 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextSet))
1266 {
1267 args.intrinsics.extend([
1268 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskMap),
1269 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass),
1270 &Intrinsic::AsyncEventCodeEnum,
1271 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask),
1272 ]);
1273 }
1274
1275 if args
1276 .intrinsics
1277 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::DriverLoop))
1278 {
1279 args.intrinsics.extend([
1280 &Intrinsic::TypeCheckValidI32,
1281 &Intrinsic::Conversion(ConversionIntrinsic::ToInt32),
1282 &Intrinsic::Component(ComponentIntrinsic::ComponentStateSetAllError),
1283 ]);
1284 }
1285
1286 if args.intrinsics.contains(&Intrinsic::Component(
1287 ComponentIntrinsic::GetOrCreateAsyncState,
1288 )) {
1289 args.intrinsics.extend([&Intrinsic::RepTableClass]);
1290 }
1291
1292 if args
1293 .intrinsics
1294 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass))
1295 {
1296 args.intrinsics.extend([
1297 &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1298 &Intrinsic::Component(ComponentIntrinsic::GlobalAsyncStateMap),
1299 &Intrinsic::RepTableClass,
1300 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncSubtaskClass),
1301 &Intrinsic::Waitable(WaitableIntrinsic::WaitableClass),
1302 ]);
1303 }
1304
1305 if args
1306 .intrinsics
1307 .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetNew))
1308 {
1309 args.intrinsics
1310 .extend([&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetClass)]);
1311 }
1312
1313 if args
1314 .intrinsics
1315 .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetPoll))
1316 || args
1317 .intrinsics
1318 .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetWait))
1319 {
1320 args.intrinsics
1321 .extend([&Intrinsic::Host(HostIntrinsic::StoreEventInComponentMemory)]);
1322 }
1323
1324 if args
1325 .intrinsics
1326 .contains(&Intrinsic::Waitable(WaitableIntrinsic::WaitableSetDrop))
1327 {
1328 args.intrinsics
1329 .extend([&Intrinsic::Waitable(WaitableIntrinsic::RemoveWaitableSet)]);
1330 }
1331
1332 if args.intrinsics.contains(&Intrinsic::Component(
1333 ComponentIntrinsic::GetOrCreateAsyncState,
1334 )) {
1335 args.intrinsics.extend([
1336 &Intrinsic::Component(ComponentIntrinsic::ComponentAsyncStateClass),
1337 &Intrinsic::Component(ComponentIntrinsic::GlobalAsyncStateMap),
1338 ]);
1339 }
1340
1341 if args.intrinsics.contains(&Intrinsic::Component(
1342 ComponentIntrinsic::ComponentAsyncStateClass,
1343 )) {
1344 args.intrinsics.extend([&Intrinsic::AsyncStream(
1345 AsyncStreamIntrinsic::GlobalStreamMap,
1346 )]);
1347 }
1348
1349 if args
1350 .intrinsics
1351 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatResult))
1352 | args
1353 .intrinsics
1354 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatOption))
1355 | args
1356 .intrinsics
1357 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatOption))
1358 {
1359 args.intrinsics
1360 .extend([&Intrinsic::Lift(LiftIntrinsic::LiftFlatVariant)]);
1361 }
1362
1363 if args
1364 .intrinsics
1365 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatVariant))
1366 {
1367 args.intrinsics.extend([
1368 &Intrinsic::Lift(LiftIntrinsic::LiftFlatU8),
1369 &Intrinsic::Lift(LiftIntrinsic::LiftFlatU16),
1370 &Intrinsic::Lift(LiftIntrinsic::LiftFlatU32),
1371 ]);
1372 }
1373
1374 if args
1375 .intrinsics
1376 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatResult))
1377 {
1378 args.intrinsics
1379 .insert(Intrinsic::Lower(LowerIntrinsic::LowerFlatVariant));
1380 }
1381
1382 if args
1383 .intrinsics
1384 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatOption))
1385 {
1386 args.intrinsics
1387 .insert(Intrinsic::Lower(LowerIntrinsic::LowerFlatVariant));
1388 }
1389
1390 if args
1391 .intrinsics
1392 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatVariant))
1393 {
1394 args.intrinsics.extend([
1395 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU8),
1396 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU16),
1397 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU32),
1398 ]);
1399 }
1400
1401 if args
1402 .intrinsics
1403 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStream))
1404 {
1405 args.intrinsics.extend([
1406 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamMap),
1407 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::ExternalStreamClass),
1408 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::InternalStreamClass),
1409 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::IsStreamLowerableObject),
1410 &Intrinsic::SymbolResourceRep,
1411 &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1412 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GenReadFnFromLowerableStream),
1413 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GenStreamHostInjectFn),
1414 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU32),
1415 ])
1416 }
1417
1418 if args.intrinsics.contains(&Intrinsic::AsyncStream(
1419 AsyncStreamIntrinsic::GenStreamHostInjectFn,
1420 )) {
1421 args.intrinsics.insert(Intrinsic::AsyncStream(
1422 AsyncStreamIntrinsic::PendingValueQueueClass,
1423 ));
1424 }
1425
1426 if args
1427 .intrinsics
1428 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatFuture))
1429 {
1430 args.intrinsics.extend([
1431 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureMap),
1432 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1433 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::InternalFutureClass),
1434 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::IsFutureLowerableObject),
1435 &Intrinsic::SymbolResourceRep,
1436 &Intrinsic::GetErrorPayload,
1437 &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1438 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GenFutureHostInjectFn),
1439 &Intrinsic::Lower(LowerIntrinsic::LowerFlatU32),
1440 ])
1441 }
1442
1443 if args
1444 .intrinsics
1445 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStringAny))
1446 {
1447 args.intrinsics.extend([
1448 &Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf8),
1449 &Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf16),
1450 ]);
1451 }
1452
1453 if args
1454 .intrinsics
1455 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf8))
1456 {
1457 args.intrinsics
1458 .insert(Intrinsic::String(StringIntrinsic::GlobalTextDecoderUtf8));
1459 }
1460
1461 if args
1462 .intrinsics
1463 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStringAny))
1464 {
1465 args.intrinsics.extend([
1466 &Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf8),
1467 &Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf16),
1468 ]);
1469 }
1470
1471 if args
1472 .intrinsics
1473 .contains(&Intrinsic::Lower(LowerIntrinsic::LowerFlatStringUtf8))
1474 {
1475 args.intrinsics
1476 .insert(Intrinsic::String(StringIntrinsic::GlobalTextEncoderUtf8));
1477 }
1478
1479 if args
1480 .intrinsics
1481 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStringUtf16))
1482 {
1483 args.intrinsics
1484 .insert(Intrinsic::String(StringIntrinsic::Utf16Decoder));
1485 }
1486
1487 if args
1488 .intrinsics
1489 .contains(&Intrinsic::Lift(LiftIntrinsic::LiftFlatStream))
1490 {
1491 args.intrinsics.insert(Intrinsic::AsyncStream(
1492 AsyncStreamIntrinsic::ExternalStreamClass,
1493 ));
1494 }
1495
1496 if args.intrinsics.contains(&Intrinsic::AsyncTask(
1497 AsyncTaskIntrinsic::CreateNewCurrentTask,
1498 )) || args
1499 .intrinsics
1500 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask))
1501 || args
1502 .intrinsics
1503 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::ClearCurrentTask))
1504 {
1505 args.intrinsics.extend([
1506 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass),
1507 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskMap),
1508 ]);
1509 }
1510
1511 if args
1512 .intrinsics
1513 .contains(&Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamNew))
1514 {
1515 args.intrinsics.extend([
1516 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamMap),
1517 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamTableMap),
1518 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamWritableEndClass),
1519 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamReadableEndClass),
1520 ]);
1521 }
1522
1523 if args.intrinsics.contains(&Intrinsic::AsyncStream(
1524 AsyncStreamIntrinsic::StreamWritableEndClass,
1525 )) || args.intrinsics.contains(&Intrinsic::AsyncStream(
1526 AsyncStreamIntrinsic::StreamReadableEndClass,
1527 )) {
1528 args.intrinsics.extend([
1529 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::InternalStreamClass),
1530 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamEndClass),
1531 &Intrinsic::AsyncEventCodeEnum,
1532 ]);
1533 }
1534
1535 if args.intrinsics.contains(&Intrinsic::AsyncStream(
1536 AsyncStreamIntrinsic::StreamNewFromLift,
1537 )) {
1538 args.intrinsics.extend([
1539 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamMap),
1540 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::GlobalStreamTableMap),
1541 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::HostStreamClass),
1542 &Intrinsic::AsyncStream(AsyncStreamIntrinsic::ExternalStreamClass),
1543 ]);
1544 }
1545
1546 if args
1547 .intrinsics
1548 .contains(&Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamWrite))
1549 || args
1550 .intrinsics
1551 .contains(&Intrinsic::AsyncStream(AsyncStreamIntrinsic::StreamRead))
1552 || args
1553 .intrinsics
1554 .contains(&Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureWrite))
1555 || args
1556 .intrinsics
1557 .contains(&Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureRead))
1558 {
1559 args.intrinsics.extend([
1560 &Intrinsic::GlobalBufferManager,
1561 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncBlockedConstant),
1562 &Intrinsic::AsyncEventCodeEnum,
1563 ]);
1564 }
1565
1566 if args
1567 .intrinsics
1568 .contains(&Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureNew))
1569 {
1570 args.intrinsics.extend([
1571 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureMap),
1572 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1573 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureTableMap),
1574 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureWritableEndClass),
1575 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureReadableEndClass),
1576 ]);
1577 }
1578
1579 if args.intrinsics.contains(&Intrinsic::AsyncFuture(
1580 AsyncFutureIntrinsic::FutureNewFromLift,
1581 )) {
1582 args.intrinsics.extend([
1583 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1584 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::GlobalFutureMap),
1585 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::HostFutureClass),
1586 ]);
1587 }
1588
1589 if args.intrinsics.contains(&Intrinsic::AsyncFuture(
1590 AsyncFutureIntrinsic::FutureWritableEndClass,
1591 )) || args.intrinsics.contains(&Intrinsic::AsyncFuture(
1592 AsyncFutureIntrinsic::FutureReadableEndClass,
1593 )) {
1594 args.intrinsics.extend([
1595 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::NestedFutureSymbol),
1596 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::InternalFutureClass),
1597 &Intrinsic::AsyncFuture(AsyncFutureIntrinsic::FutureEndClass),
1598 &Intrinsic::AsyncEventCodeEnum,
1599 ]);
1600 }
1601
1602 if args.intrinsics.contains(&Intrinsic::GlobalBufferManager) {
1603 args.intrinsics.extend([&Intrinsic::BufferManagerClass]);
1604 }
1605
1606 if args.intrinsics.contains(&Intrinsic::BufferManagerClass) {
1607 args.intrinsics.extend([&Intrinsic::ManagedBufferClass]);
1608 }
1609
1610 if args.intrinsics.contains(&Intrinsic::AsyncTask(
1611 AsyncTaskIntrinsic::EnterSymmetricSyncGuestCall,
1612 )) || args.intrinsics.contains(&Intrinsic::AsyncTask(
1613 AsyncTaskIntrinsic::ExitSymmetricSyncGuestCall,
1614 )) {
1615 args.intrinsics.extend([
1616 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentComponentIdxs),
1617 &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
1618 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask),
1619 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskIds),
1620 &Intrinsic::ClearGlobalCurrentTaskMetaFn,
1621 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::SymmetricSyncGuestCallStack),
1622 ]);
1623 }
1624
1625 for current_intrinsic in args.intrinsics.iter() {
1626 if rendered_intrinsics.contains(current_intrinsic.name()) {
1628 continue;
1629 }
1630
1631 current_intrinsic.render(&mut output, &args);
1632 }
1633
1634 output
1635}
1636
1637impl Intrinsic {
1638 pub fn get_global_names() -> impl IntoIterator<Item = &'static str> {
1639 JsHelperIntrinsic::get_global_names()
1640 .into_iter()
1641 .chain(vec![
1642 "base64Compile",
1644 "clampGuest",
1645 "ComponentError",
1646 "fetchCompile",
1647 "finalizationRegistryCreate",
1648 "getErrorPayload",
1649 "HANDLE_TABLES",
1650 "hasOwnProperty",
1651 "imports",
1652 "instantiateCore",
1653 "isLE",
1654 "scopeId",
1655 "symbolCabiDispose",
1656 "symbolCabiLower",
1657 "symbolDispose",
1658 "symbolAsyncIterator",
1659 "symbolIterator",
1660 "symbolRscHandle",
1661 "symbolRscRep",
1662 "T_FLAG",
1663 "throwInvalidBool",
1664 "throwUninitialized",
1665 "ArrayBuffer",
1667 "BigInt",
1668 "BigInt64Array",
1669 "DataView",
1670 "dv",
1671 "emptyFunc",
1672 "Error",
1673 "fetch",
1674 "Float32Array",
1675 "Float64Array",
1676 "Int32Array",
1677 "Object",
1678 "process",
1679 "String",
1680 "TextDecoder",
1681 "TextEncoder",
1682 "TypeError",
1683 "Uint16Array",
1684 "Uint8Array",
1685 "URL",
1686 "WebAssembly",
1687 "GlobalComponentMemories",
1688 ])
1689 }
1690
1691 pub fn name(&self) -> &'static str {
1692 match self {
1693 Intrinsic::JsHelper(i) => i.name(),
1694 Intrinsic::Conversion(i) => i.name(),
1695 Intrinsic::WebIdl(i) => i.name(),
1696 Intrinsic::String(i) => i.name(),
1697 Intrinsic::ErrCtx(i) => i.name(),
1698 Intrinsic::AsyncTask(i) => i.name(),
1699 Intrinsic::Waitable(i) => i.name(),
1700 Intrinsic::Resource(i) => i.name(),
1701 Intrinsic::Lift(i) => i.name(),
1702 Intrinsic::Lower(i) => i.name(),
1703 Intrinsic::AsyncStream(i) => i.name(),
1704 Intrinsic::AsyncFuture(i) => i.name(),
1705 Intrinsic::Component(i) => i.name(),
1706 Intrinsic::Host(i) => i.name(),
1707
1708 Intrinsic::Base64Compile => "base64Compile",
1709 Intrinsic::ClampGuest => "clampGuest",
1710 Intrinsic::ComponentError => "ComponentError",
1711 Intrinsic::FetchCompile => "fetchCompile",
1712 Intrinsic::FinalizationRegistryCreate => "finalizationRegistryCreate",
1713 Intrinsic::GetErrorPayload => "getErrorPayload",
1714 Intrinsic::GetErrorPayloadString => "getErrorPayloadString",
1715 Intrinsic::HandleTables => "HANDLE_TABLES",
1716 Intrinsic::HasOwnProperty => "hasOwnProperty",
1717 Intrinsic::InstantiateCore => "instantiateCore",
1718 Intrinsic::IsLE => "isLE",
1719 Intrinsic::ScopeId => "SCOPE_ID",
1720
1721 Intrinsic::SymbolCabiDispose => "symbolCabiDispose",
1722 Intrinsic::SymbolCabiLower => "symbolCabiLower",
1723 Intrinsic::SymbolDispose => "symbolDispose",
1724 Intrinsic::SymbolAsyncIterator => "symbolAsyncIterator",
1725 Intrinsic::SymbolIterator => "symbolIterator",
1726 Intrinsic::SymbolResourceHandle => "symbolRscHandle",
1727 Intrinsic::SymbolResourceRep => "symbolRscRep",
1728
1729 Intrinsic::ThrowInvalidBool => "throwInvalidBool",
1730 Intrinsic::ThrowUninitialized => "throwUninitialized",
1731
1732 Intrinsic::DebugLog => "_debugLog",
1734 Intrinsic::PromiseWithResolversPonyfill => "promiseWithResolvers",
1735
1736 Intrinsic::ConstantI32Min => "I32_MIN",
1738 Intrinsic::ConstantI32Max => "I32_MAX",
1739 Intrinsic::TypeCheckValidI32 => "_typeCheckValidI32",
1740 Intrinsic::TypeCheckAsyncFn => "_typeCheckAsyncFn",
1741 Intrinsic::AsyncFunctionCtor => "ASYNC_FN_CTOR",
1742
1743 Intrinsic::PlatformReadableStreamClass => "_PlatformReadableStream",
1745
1746 Intrinsic::GlobalAsyncDeterminism => "ASYNC_DETERMINISM",
1748 Intrinsic::CoinFlip => "_coinFlip",
1749
1750 Self::GlobalCurrentTaskMeta => "CURRENT_TASK_META",
1752 Self::GetGlobalCurrentTaskMetaFn => "_getGlobalCurrentTaskMeta",
1753 Self::SetGlobalCurrentTaskMetaFn => "_setGlobalCurrentTaskMeta",
1754 Self::WithGlobalCurrentTaskMetaFn => "_withGlobalCurrentTaskMeta",
1755 Self::WithGlobalCurrentTaskMetaFnAsync => "_withGlobalCurrentTaskMetaAsync",
1756 Self::ClearGlobalCurrentTaskMetaFn => "_clearCurrentTask",
1757
1758 Intrinsic::GlobalComponentMemoryMap => "GLOBAL_COMPONENT_MEMORY_MAP",
1760 Intrinsic::RegisterGlobalMemoryForComponent => "registerGlobalMemoryForComponent",
1761 Intrinsic::LookupMemoriesForComponent => "lookupMemoriesForComponent",
1762
1763 Intrinsic::RepTableClass => "RepTable",
1765
1766 Intrinsic::ManagedBufferClass => "ManagedBuffer",
1768 Intrinsic::BufferManagerClass => "BufferManager",
1769 Intrinsic::GlobalBufferManager => "BUFFER_MGR",
1770
1771 Intrinsic::AsyncEventCodeEnum => "ASYNC_EVENT_CODE",
1773 }
1774 }
1775}