1use std::collections::BTreeSet;
4use std::fmt::Write;
5
6use crate::source::Source;
7use crate::uwrite;
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 component;
28use component::ComponentIntrinsic;
29
30pub(crate) mod p3;
31use p3::async_future::AsyncFutureIntrinsic;
32use p3::async_stream::AsyncStreamIntrinsic;
33use p3::async_task::AsyncTaskIntrinsic;
34use p3::error_context::ErrCtxIntrinsic;
35use p3::waitable::WaitableIntrinsic;
36
37#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
43pub enum Intrinsic {
44 JsHelper(JsHelperIntrinsic),
45 WebIdl(WebIdlIntrinsic),
46 Conversion(ConversionIntrinsic),
47 String(StringIntrinsic),
48 Resource(ResourceIntrinsic),
49 ErrCtx(ErrCtxIntrinsic),
50 AsyncTask(AsyncTaskIntrinsic),
51 Waitable(WaitableIntrinsic),
52 Lift(LiftIntrinsic),
53 AsyncStream(AsyncStreamIntrinsic),
54 AsyncFuture(AsyncFutureIntrinsic),
55 Component(ComponentIntrinsic),
56
57 PromiseWithResolversPolyfill,
59
60 DebugLog,
62
63 GlobalAsyncDeterminism,
65
66 CoinFlip,
68
69 ConstantI32Max,
71 ConstantI32Min,
72 TypeCheckValidI32,
73
74 Base64Compile,
75 ClampGuest,
76 FetchCompile,
77
78 SymbolCabiDispose,
80 SymbolCabiLower,
81 SymbolResourceHandle,
82 SymbolResourceRep,
83 SymbolDispose,
84 ScopeId,
85 DefinedResourceTables,
86 HandleTables,
87
88 FinalizationRegistryCreate,
90
91 ComponentError,
93
94 GetErrorPayload,
96 GetErrorPayloadString,
97
98 ManagedBufferClass,
100
101 BufferManagerClass,
103
104 GlobalBufferManager,
106
107 RepTableClass,
111
112 AwaitableClass,
115
116 AsyncEventCodeEnum,
118
119 WriteAsyncEventToMemory,
121
122 IsLE,
124 ThrowInvalidBool,
125 ThrowUninitialized,
126 HasOwnProperty,
127 InstantiateCore,
128
129 IsBorrowedType,
134}
135
136#[derive(Debug, Default, PartialEq, Eq)]
138pub(crate) enum AsyncDeterminismProfile {
139 #[default]
141 Random,
142
143 #[allow(unused)]
145 Deterministic,
146}
147
148impl std::fmt::Display for AsyncDeterminismProfile {
149 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
150 write!(
151 f,
152 "{}",
153 match self {
154 Self::Deterministic => "deterministic",
155 Self::Random => "random",
156 }
157 )
158 }
159}
160
161pub struct RenderIntrinsicsArgs<'a> {
163 pub(crate) intrinsics: &'a mut BTreeSet<Intrinsic>,
165 pub(crate) no_nodejs_compat: bool,
167 pub(crate) instantiation: bool,
169 pub(crate) determinism: AsyncDeterminismProfile,
171}
172
173pub fn render_intrinsics(args: RenderIntrinsicsArgs) -> Source {
176 let mut output = Source::default();
177
178 args.intrinsics.insert(Intrinsic::DebugLog);
180 args.intrinsics.insert(Intrinsic::GlobalAsyncDeterminism);
181 args.intrinsics.insert(Intrinsic::CoinFlip);
182 args.intrinsics.insert(Intrinsic::ConstantI32Min);
183 args.intrinsics.insert(Intrinsic::ConstantI32Max);
184 args.intrinsics.insert(Intrinsic::TypeCheckValidI32);
185 args.intrinsics.insert(Intrinsic::AsyncTask(
186 AsyncTaskIntrinsic::GlobalAsyncCurrentTaskIds,
187 ));
188 args.intrinsics.insert(Intrinsic::AsyncTask(
189 AsyncTaskIntrinsic::GlobalAsyncCurrentComponentIdxs,
190 ));
191 args.intrinsics.insert(Intrinsic::AsyncTask(
192 AsyncTaskIntrinsic::UnpackCallbackResult,
193 ));
194 args.intrinsics
195 .insert(Intrinsic::PromiseWithResolversPolyfill);
196
197 if args.intrinsics.contains(&Intrinsic::GetErrorPayload)
199 || args.intrinsics.contains(&Intrinsic::GetErrorPayloadString)
200 {
201 args.intrinsics.insert(Intrinsic::HasOwnProperty);
202 }
203 if args
204 .intrinsics
205 .contains(&Intrinsic::String(StringIntrinsic::Utf16Encode))
206 {
207 args.intrinsics.insert(Intrinsic::IsLE);
208 }
209
210 if args
211 .intrinsics
212 .contains(&Intrinsic::Conversion(ConversionIntrinsic::F32ToI32))
213 || args
214 .intrinsics
215 .contains(&Intrinsic::Conversion(ConversionIntrinsic::I32ToF32))
216 {
217 output.push_str(
218 "
219 const i32ToF32I = new Int32Array(1);
220 const i32ToF32F = new Float32Array(i32ToF32I.buffer);
221 ",
222 );
223 }
224
225 if args
226 .intrinsics
227 .contains(&Intrinsic::Conversion(ConversionIntrinsic::F64ToI64))
228 || args
229 .intrinsics
230 .contains(&Intrinsic::Conversion(ConversionIntrinsic::I64ToF64))
231 {
232 output.push_str(
233 "
234 const i64ToF64I = new BigInt64Array(1);
235 const i64ToF64F = new Float64Array(i64ToF64I.buffer);
236 ",
237 );
238 }
239
240 if args.intrinsics.contains(&Intrinsic::Resource(
241 ResourceIntrinsic::ResourceTransferBorrow,
242 )) || args.intrinsics.contains(&Intrinsic::Resource(
243 ResourceIntrinsic::ResourceTransferBorrowValidLifting,
244 )) {
245 args.intrinsics.insert(Intrinsic::Resource(
246 ResourceIntrinsic::ResourceTableCreateBorrow,
247 ));
248 }
249
250 if args
252 .intrinsics
253 .contains(&Intrinsic::ErrCtx(ErrCtxIntrinsic::DebugMessage))
254 {
255 args.intrinsics.extend([
256 &Intrinsic::String(StringIntrinsic::Utf8Encode),
257 &Intrinsic::String(StringIntrinsic::Utf16Encode),
258 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
259 ]);
260 }
261 if args
262 .intrinsics
263 .contains(&Intrinsic::ErrCtx(ErrCtxIntrinsic::New))
264 {
265 args.intrinsics.extend([
266 &Intrinsic::ErrCtx(ErrCtxIntrinsic::ComponentGlobalTable),
267 &Intrinsic::ErrCtx(ErrCtxIntrinsic::ReserveGlobalRep),
268 &Intrinsic::ErrCtx(ErrCtxIntrinsic::CreateLocalHandle),
269 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
270 ]);
271 }
272
273 if args
274 .intrinsics
275 .contains(&Intrinsic::ErrCtx(ErrCtxIntrinsic::DebugMessage))
276 {
277 args.intrinsics.extend([
278 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GlobalRefCountAdd),
279 &Intrinsic::ErrCtx(ErrCtxIntrinsic::Drop),
280 &Intrinsic::ErrCtx(ErrCtxIntrinsic::GetLocalTable),
281 ]);
282 }
283
284 if args
285 .intrinsics
286 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextGet))
287 || args
288 .intrinsics
289 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::ContextSet))
290 {
291 args.intrinsics.extend([
292 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskMap),
293 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass),
294 &Intrinsic::AsyncEventCodeEnum,
295 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask),
296 ]);
297 }
298
299 if args
300 .intrinsics
301 .contains(&Intrinsic::Component(ComponentIntrinsic::BackpressureSet))
302 {
303 args.intrinsics.extend([&Intrinsic::Component(
304 ComponentIntrinsic::GetOrCreateAsyncState,
305 )]);
306 }
307
308 if args.intrinsics.contains(&Intrinsic::Component(
309 ComponentIntrinsic::GetOrCreateAsyncState,
310 )) {
311 args.intrinsics.extend([&Intrinsic::RepTableClass]);
312 }
313
314 if args
315 .intrinsics
316 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass))
317 {
318 args.intrinsics.extend([
319 &Intrinsic::Component(ComponentIntrinsic::GetOrCreateAsyncState),
320 &Intrinsic::Component(ComponentIntrinsic::GlobalAsyncStateMap),
321 &Intrinsic::RepTableClass,
322 &Intrinsic::AwaitableClass,
323 ]);
324 }
325
326 if args.intrinsics.contains(&Intrinsic::Component(
327 ComponentIntrinsic::GetOrCreateAsyncState,
328 )) {
329 args.intrinsics.extend([
330 &Intrinsic::Component(ComponentIntrinsic::ComponentAsyncStateClass),
331 &Intrinsic::Component(ComponentIntrinsic::GlobalAsyncStateMap),
332 ]);
333 }
334
335 if args
336 .intrinsics
337 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::StartCurrentTask))
338 || args
339 .intrinsics
340 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::GetCurrentTask))
341 || args
342 .intrinsics
343 .contains(&Intrinsic::AsyncTask(AsyncTaskIntrinsic::EndCurrentTask))
344 {
345 args.intrinsics.extend([
346 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::AsyncTaskClass),
347 &Intrinsic::AsyncTask(AsyncTaskIntrinsic::GlobalAsyncCurrentTaskMap),
348 ]);
349 }
350
351 for current_intrinsic in args.intrinsics.iter() {
353 match current_intrinsic {
354 Intrinsic::JsHelper(i) => i.render(&mut output),
355 Intrinsic::Conversion(i) => i.render(&mut output),
356 Intrinsic::String(i) => i.render(&mut output),
357 Intrinsic::ErrCtx(i) => i.render(&mut output),
358 Intrinsic::Resource(i) => i.render(&mut output),
359 Intrinsic::AsyncTask(i) => i.render(&mut output),
360 Intrinsic::Waitable(i) => i.render(&mut output, &args),
361 Intrinsic::Lift(i) => i.render(&mut output),
362 Intrinsic::AsyncStream(i) => i.render(&mut output),
363 Intrinsic::AsyncFuture(i) => i.render(&mut output),
364 Intrinsic::Component(i) => i.render(&mut output),
365
366 Intrinsic::GlobalAsyncDeterminism => {
367 output.push_str(&format!(
368 "const {var_name} = '{determinism}';\n",
369 var_name = current_intrinsic.name(),
370 determinism = args.determinism,
371 ));
372 }
373
374 Intrinsic::CoinFlip => {
375 output.push_str(&format!(
376 "const {var_name} = () => {{ return Math.random() > 0.5; }};\n",
377 var_name = current_intrinsic.name(),
378 ));
379 }
380
381 Intrinsic::AwaitableClass => {
382 output.push_str(&format!("
383 class {class_name} {{
384 static _ID = 0n;
385
386 #id;
387 #promise;
388 #resolved = false;
389
390 constructor(promise) {{
391 if (!promise) {{ throw new TypeError('Awaitable must have an interior promise'); }}
392 if (!('then' in promise) || typeof promise.then !== 'function') {{
393 throw new Error('missing/invalid promise');
394 }}
395 promise.then(() => this.#resolved = true);
396 this.#promise = promise;
397 this.#id = ++{class_name}._ID;
398 }}
399
400 id() {{ return this.#id; }}
401
402 resolved() {{ return this.#resolved; }}
403
404 then() {{ return this.#promise.then(...arguments); }}
405 }}
406 ",
407 class_name = current_intrinsic.name(),
408 ));
409 }
410
411 Intrinsic::ConstantI32Min => output.push_str(&format!(
412 "const {const_name} = -2_147_483_648;\n",
413 const_name = current_intrinsic.name()
414 )),
415 Intrinsic::ConstantI32Max => output.push_str(&format!(
416 "const {const_name} = 2_147_483_647;\n",
417 const_name = current_intrinsic.name()
418 )),
419 Intrinsic::TypeCheckValidI32 => {
420 let i32_const_min = Intrinsic::ConstantI32Min.name();
421 let i32_const_max = Intrinsic::ConstantI32Max.name();
422 output.push_str(&format!("const {fn_name} = (n) => typeof n === 'number' && n >= {i32_const_min} && n <= {i32_const_max};\n", fn_name = current_intrinsic.name()))
423 }
424
425 Intrinsic::Base64Compile => {
426 if !args.no_nodejs_compat {
427 output.push_str("
428 const base64Compile = str => WebAssembly.compile(typeof Buffer !== 'undefined' ? Buffer.from(str, 'base64') : Uint8Array.from(atob(str), b => b.charCodeAt(0)));
429 ")
430 } else {
431 output.push_str("
432 const base64Compile = str => WebAssembly.compile(Uint8Array.from(atob(str), b => b.charCodeAt(0)));
433 ")
434 }
435 }
436
437 Intrinsic::ClampGuest => output.push_str(
438 "
439 function clampGuest(i, min, max) {
440 if (i < min || i > max) \
441 throw new TypeError(`must be between ${min} and ${max}`);
442 return i;
443 }
444 ",
445 ),
446
447 Intrinsic::ComponentError => output.push_str(
448 "
449 class ComponentError extends Error {
450 constructor (value) {
451 const enumerable = typeof value !== 'string';
452 super(enumerable ? `${String(value)} (see error.payload)` : value);
453 Object.defineProperty(this, 'payload', { value, enumerable });
454 }
455 }
456 ",
457 ),
458
459 Intrinsic::DefinedResourceTables => {}
460
461 Intrinsic::FinalizationRegistryCreate => output.push_str(
462 "
463 function finalizationRegistryCreate (unregister) {
464 if (typeof FinalizationRegistry === 'undefined') {
465 return { unregister () {} };
466 }
467 return new FinalizationRegistry(unregister);
468 }
469 ",
470 ),
471
472 Intrinsic::FetchCompile => {
473 if !args.no_nodejs_compat {
474 output.push_str("
475 const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
476 let _fs;
477 async function fetchCompile (url) {
478 if (isNode) {
479 _fs = _fs || await import('node:fs/promises');
480 return WebAssembly.compile(await _fs.readFile(url));
481 }
482 return fetch(url).then(WebAssembly.compileStreaming);
483 }
484 ")
485 } else {
486 output.push_str(
487 "
488 const fetchCompile = url => fetch(url).then(WebAssembly.compileStreaming);
489 ",
490 )
491 }
492 }
493
494 Intrinsic::GetErrorPayload => {
495 let hop = Intrinsic::HasOwnProperty.name();
496 uwrite!(
497 output,
498 "
499 function getErrorPayload(e) {{
500 if (e && {hop}.call(e, 'payload')) return e.payload;
501 if (e instanceof Error) throw e;
502 return e;
503 }}
504 "
505 )
506 }
507
508 Intrinsic::GetErrorPayloadString => {
509 let hop = Intrinsic::HasOwnProperty.name();
510 uwrite!(
511 output,
512 "
513 function getErrorPayloadString(e) {{
514 if (e && {hop}.call(e, 'payload')) return e.payload;
515 if (e instanceof Error) return e.message;
516 return e;
517 }}
518 "
519 )
520 }
521
522 Intrinsic::WebIdl(w) => w.render(&mut output),
523
524 Intrinsic::HandleTables => output.push_str(
525 "
526 const handleTables = [];
527 ",
528 ),
529
530 Intrinsic::HasOwnProperty => output.push_str(
531 "
532 const hasOwnProperty = Object.prototype.hasOwnProperty;
533 ",
534 ),
535
536 Intrinsic::InstantiateCore => {
537 if !args.instantiation {
538 output.push_str(
539 "
540 const instantiateCore = WebAssembly.instantiate;
541 ",
542 )
543 }
544 }
545
546 Intrinsic::IsLE => output.push_str(
547 "
548 const isLE = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
549 ",
550 ),
551
552 Intrinsic::SymbolCabiDispose => output.push_str(
553 "
554 const symbolCabiDispose = Symbol.for('cabiDispose');
555 ",
556 ),
557
558 Intrinsic::SymbolCabiLower => output.push_str(
559 "
560 const symbolCabiLower = Symbol.for('cabiLower');
561 ",
562 ),
563
564 Intrinsic::ScopeId => output.push_str(
565 "
566 let scopeId = 0;
567 ",
568 ),
569
570 Intrinsic::SymbolResourceHandle => output.push_str(
571 "
572 const symbolRscHandle = Symbol('handle');
573 ",
574 ),
575
576 Intrinsic::SymbolResourceRep => output.push_str(
577 "
578 const symbolRscRep = Symbol.for('cabiRep');
579 ",
580 ),
581
582 Intrinsic::SymbolDispose => output.push_str(
583 "
584 const symbolDispose = Symbol.dispose || Symbol.for('dispose');
585 ",
586 ),
587
588 Intrinsic::ThrowInvalidBool => output.push_str(
589 "
590 function throwInvalidBool() {
591 throw new TypeError('invalid variant discriminant for bool');
592 }
593 ",
594 ),
595
596 Intrinsic::ThrowUninitialized => output.push_str(
597 "
598 function throwUninitialized() {
599 throw new TypeError('Wasm uninitialized use `await $init` first');
600 }
601 ",
602 ),
603
604 Intrinsic::DebugLog => {
605 let fn_name = Intrinsic::DebugLog.name();
606 output.push_str(&format!(
607 "
608 const {fn_name} = (...args) => {{
609 if (!globalThis?.process?.env?.JCO_DEBUG) {{ return; }}
610 console.debug(...args);
611 }}
612 "
613 ));
614 }
615
616 Intrinsic::PromiseWithResolversPolyfill => {
617 output.push_str(
618 r#"
619 if (!Promise.withResolvers) {
620 Promise.withResolvers = () => {
621 let resolve;
622 let reject;
623 const promise = new Promise((res, rej) => {
624 resolve = res;
625 reject = rej;
626 });
627 return { promise, resolve, reject };
628 };
629 }
630 "#,
631 );
632 }
633
634 Intrinsic::AsyncEventCodeEnum => {
635 let name = Intrinsic::AsyncEventCodeEnum.name();
636 output.push_str(&format!(
637 "
638 const {name} = {{
639 NONE: 'none',
640 TASK_CANCELLED: 'task-cancelled',
641 STREAM_READ: 'stream-read',
642 STREAM_WRITE: 'stream-write',
643 FUTURE_READ: 'future-read',
644 FUTURE_WRITE: 'future-write',
645 }};
646 "
647 ));
648 }
649
650 Intrinsic::IsBorrowedType => {
651 let debug_log_fn = Intrinsic::DebugLog.name();
652 let is_borrowed_type_fn = Intrinsic::IsBorrowedType.name();
653 let defined_resource_tables = Intrinsic::DefinedResourceTables.name();
654 output.push_str(&format!("
655 function {is_borrowed_type_fn}(componentInstanceID, typeIdx) {{
656 {debug_log_fn}('[{is_borrowed_type_fn}()] args', {{ componentInstanceID, typeIdx }});
657 const table = {defined_resource_tables}[componentInstanceID];
658 if (!table) {{ return false; }}
659 const handle = table[(typeIdx << 1) + 1];
660 if (!handle) {{ return false; }}
661 const isOwned = (handle & T_FLAG) !== 0;
662 return !isOwned;
663 }}
664 "));
665 }
666
667 Intrinsic::ManagedBufferClass => {
668 let debug_log_fn = Intrinsic::DebugLog.name();
669 let managed_buffer_class = Intrinsic::ManagedBufferClass.name();
670 output.push_str(&format!(
671 "
672 class {managed_buffer_class} {{
673 constructor(args) {{
674 {debug_log_fn}('[{managed_buffer_class}#constructor()] args', args);
675 }}
676 }}
677 "
678 ));
679 }
680
681 Intrinsic::BufferManagerClass => {
682 let debug_log_fn = Intrinsic::DebugLog.name();
683 let buffer_manager_class = Intrinsic::BufferManagerClass.name();
684 let managed_buffer_class = Intrinsic::ManagedBufferClass.name();
685 output.push_str(&format!("
686 class {buffer_manager_class} {{
687 #buffers = new Map();
688 #bufferIDs = new Map();
689
690 private constructor() {{ }}
691
692 getNextBufferID(componentInstanceID) {{
693 const current = this.#bufferIDs.get(args.componentInstanceID, 0);
694 if (typeof current === 'undefined') {{
695 this.#bufferIDs.set(args.componentInstanceID, 1);
696 return 0;
697 }}
698 this.#bufferIDs.set(args.componentInstanceID, current + 1);
699 return current;
700 }}
701
702 createBuffer(args) {{
703 {debug_log_fn}('[{buffer_manager_class}#create()] args', args);
704 if (!args || typeof args !== 'object') {{ throw new TypeError('missing/invalid argument object'); }}
705 if (!args.componentInstanceID) {{ throw new TypeError('missing/invalid component instance ID'); }}
706 if (!args.start) {{ throw new TypeError('missing/invalid start pointer'); }}
707 if (!args.len) {{ throw new TypeError('missing/invalid buffer length'); }}
708 const {{ componentInstanceID, start, len, typeIdx }} = args;
709
710 if (!this.#buffers.has(componentInstanceID)) {{
711 this.#buffers.set(componentInstanceID, new Map());
712 }}
713 const instanceBuffers = this.#buffers.get(componentInstanceID);
714
715 const nextBufID = this.getNextBufferID(args.componentInstanceID);
716
717 // TODO: check alignment and bounds, if typeIdx is present
718 instanceBuffers.set(nextBufID, new {managed_buffer_class}());
719
720 return nextBufID;
721 }}
722 }}
723 "));
724 }
725
726 Intrinsic::GlobalBufferManager => {
727 let global_buffer_manager = Intrinsic::GlobalBufferManager.name();
728 let buffer_manager_class = Intrinsic::BufferManagerClass.name();
729 output.push_str(&format!(
730 "
731 const {global_buffer_manager} = new {buffer_manager_class}();
732 "
733 ));
734 }
735
736 Intrinsic::WriteAsyncEventToMemory => {
737 let debug_log_fn = Intrinsic::DebugLog.name();
738 let write_async_event_to_memory_fn = Intrinsic::WriteAsyncEventToMemory.name();
739 output.push_str(&format!("
740 function {write_async_event_to_memory_fn}(memory, task, event, ptr) {{
741 {debug_log_fn}('[{write_async_event_to_memory_fn}()] args', {{ memory, task, event, ptr }});
742 throw new Error('{write_async_event_to_memory_fn}() not implemented');
743 }}
744 "));
745 }
746
747 Intrinsic::RepTableClass => {
748 let debug_log_fn = Intrinsic::DebugLog.name();
749 let rep_table_class = Intrinsic::RepTableClass.name();
750 output.push_str(&format!("
751 class {rep_table_class} {{
752 #data = [0, null];
753
754 insert(val) {{
755 {debug_log_fn}('[{rep_table_class}#insert()] args', {{ val }});
756 const freeIdx = this.#data[0];
757 if (freeIdx === 0) {{
758 this.#data.push(val);
759 this.#data.push(null);
760 return (this.#data.length >> 1) - 1;
761 }}
762 this.#data[0] = this.#data[freeIdx];
763 const newFreeIdx = freeIdx << 1;
764 this.#data[newFreeIdx] = val;
765 this.#data[newFreeIdx + 1] = null;
766 return free;
767 }}
768
769 get(rep) {{
770 {debug_log_fn}('[{rep_table_class}#insert()] args', {{ rep }});
771 const baseIdx = idx << 1;
772 const val = this.#data[baseIdx];
773 return val;
774 }}
775
776 contains(rep) {{
777 {debug_log_fn}('[{rep_table_class}#insert()] args', {{ rep }});
778 const baseIdx = idx << 1;
779 return !!this.#data[baseIdx];
780 }}
781
782 remove(rep) {{
783 {debug_log_fn}('[{rep_table_class}#insert()] args', {{ idx }});
784 if (this.#data.length === 2) {{ throw new Error('invalid'); }}
785
786 const baseIdx = idx << 1;
787 const val = this.#data[baseIdx];
788 if (val === 0) {{ throw new Error('invalid resource rep (cannot be 0)'); }}
789 this.#data[baseIdx] = this.#data[0];
790 this.#data[0] = idx;
791 return val;
792 }}
793
794 clear() {{
795 this.#data = [0, null];
796 }}
797 }}
798 "));
799 }
800 }
801 }
802
803 output
804}
805
806impl Intrinsic {
807 pub fn get_global_names() -> impl IntoIterator<Item = &'static str> {
808 JsHelperIntrinsic::get_global_names()
809 .into_iter()
810 .chain(vec![
811 "base64Compile",
813 "clampGuest",
814 "ComponentError",
815 "definedResourceTables",
816 "fetchCompile",
817 "finalizationRegistryCreate",
818 "getErrorPayload",
819 "handleTables",
820 "hasOwnProperty",
821 "imports",
822 "instantiateCore",
823 "isLE",
824 "scopeId",
825 "symbolCabiDispose",
826 "symbolCabiLower",
827 "symbolDispose",
828 "symbolRscHandle",
829 "symbolRscRep",
830 "T_FLAG",
831 "throwInvalidBool",
832 "throwUninitialized",
833 "ArrayBuffer",
835 "BigInt",
836 "BigInt64Array",
837 "DataView",
838 "dv",
839 "emptyFunc",
840 "Error",
841 "fetch",
842 "Float32Array",
843 "Float64Array",
844 "Int32Array",
845 "Object",
846 "process",
847 "String",
848 "TextDecoder",
849 "TextEncoder",
850 "TypeError",
851 "Uint16Array",
852 "Uint8Array",
853 "URL",
854 "WebAssembly",
855 ])
856 }
857
858 pub fn name(&self) -> &'static str {
859 match self {
860 Intrinsic::JsHelper(i) => i.name(),
861 Intrinsic::Conversion(i) => i.name(),
862 Intrinsic::WebIdl(i) => i.name(),
863 Intrinsic::String(i) => i.name(),
864 Intrinsic::ErrCtx(i) => i.name(),
865 Intrinsic::AsyncTask(i) => i.name(),
866 Intrinsic::Waitable(i) => i.name(),
867 Intrinsic::Resource(i) => i.name(),
868 Intrinsic::Lift(i) => i.name(),
869 Intrinsic::AsyncStream(i) => i.name(),
870 Intrinsic::AsyncFuture(i) => i.name(),
871 Intrinsic::Component(i) => i.name(),
872
873 Intrinsic::Base64Compile => "base64Compile",
874 Intrinsic::ClampGuest => "clampGuest",
875 Intrinsic::ComponentError => "ComponentError",
876 Intrinsic::DefinedResourceTables => "definedResourceTables",
877 Intrinsic::FetchCompile => "fetchCompile",
878 Intrinsic::FinalizationRegistryCreate => "finalizationRegistryCreate",
879 Intrinsic::GetErrorPayload => "getErrorPayload",
880 Intrinsic::GetErrorPayloadString => "getErrorPayloadString",
881 Intrinsic::HandleTables => "handleTables",
882 Intrinsic::HasOwnProperty => "hasOwnProperty",
883 Intrinsic::InstantiateCore => "instantiateCore",
884 Intrinsic::IsLE => "isLE",
885 Intrinsic::ScopeId => "scopeId",
886 Intrinsic::SymbolCabiDispose => "symbolCabiDispose",
887 Intrinsic::SymbolCabiLower => "symbolCabiLower",
888 Intrinsic::SymbolDispose => "symbolDispose",
889 Intrinsic::SymbolResourceHandle => "symbolRscHandle",
890 Intrinsic::SymbolResourceRep => "symbolRscRep",
891 Intrinsic::ThrowInvalidBool => "throwInvalidBool",
892 Intrinsic::ThrowUninitialized => "throwUninitialized",
893
894 Intrinsic::DebugLog => "_debugLog",
896 Intrinsic::PromiseWithResolversPolyfill => unreachable!(),
897
898 Intrinsic::ConstantI32Min => "I32_MIN",
900 Intrinsic::ConstantI32Max => "I32_MAX",
901 Intrinsic::TypeCheckValidI32 => "_typeCheckValidI32",
902 Intrinsic::IsBorrowedType => "_isBorrowedType",
903
904 Intrinsic::GlobalAsyncDeterminism => "ASYNC_DETERMINISM",
906 Intrinsic::AwaitableClass => "Awaitable",
907 Intrinsic::CoinFlip => "_coinFlip",
908
909 Intrinsic::RepTableClass => "RepTable",
911
912 Intrinsic::ManagedBufferClass => "ManagedBuffer",
914 Intrinsic::BufferManagerClass => "BufferManager",
915 Intrinsic::GlobalBufferManager => "BUFFER_MGR",
916
917 Intrinsic::AsyncEventCodeEnum => "ASYNC_EVENT_CODE",
919 Intrinsic::WriteAsyncEventToMemory => "writeAsyncEventToMemory",
920 }
921 }
922}