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