@scriptc/compiler 0.0.25 → 0.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ambient/scriptc-node-fallback.d.ts +15 -7
- package/dist/backend/cc.d.ts +22 -0
- package/dist/backend/cc.js +128 -10
- package/dist/backend/cc.js.map +1 -1
- package/dist/backend/emission/emit-exprs.js +81 -10
- package/dist/backend/emission/emit-exprs.js.map +1 -1
- package/dist/backend/emission/emitter.d.ts +14 -1
- package/dist/backend/emission/emitter.js +126 -13
- package/dist/backend/emission/emitter.js.map +1 -1
- package/dist/backend/emission/may-throw.js +11 -1
- package/dist/backend/emission/may-throw.js.map +1 -1
- package/dist/backend/ffi-callbacks.d.ts +11 -0
- package/dist/backend/ffi-callbacks.js +33 -0
- package/dist/backend/ffi-callbacks.js.map +1 -0
- package/dist/backend/llvm/classes.js +21 -21
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +7 -4
- package/dist/backend/llvm/dyn.js +145 -141
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +7 -1
- package/dist/backend/llvm/emitter.js +961 -303
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/shapes.d.ts +4 -0
- package/dist/backend/llvm/shapes.js +26 -24
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/unsupported.js +1 -1
- package/dist/backend/llvm/unsupported.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +2 -0
- package/dist/backend/llvm/walkers.js +50 -46
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/coverage/surface-manifest.js +1 -1
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +1 -1
- package/dist/diagnostics/diagnostic.js +3 -2
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/ffi/profile.d.ts +20 -2
- package/dist/ffi/profile.js +130 -6
- package/dist/ffi/profile.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +58 -22
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +17 -7
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +5 -0
- package/dist/frontend/lowering/lower-server.js +129 -37
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +8 -1
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +3 -2
- package/dist/frontend/lowering/surfaces.js +4 -3
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm.d.ts +16 -0
- package/dist/frontend/npm.js +257 -0
- package/dist/frontend/npm.js.map +1 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +188 -5
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +54 -13
- package/dist/ir/nodes.js +49 -7
- package/dist/ir/nodes.js.map +1 -1
- package/dist/ir/validate.js +10 -22
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/profile.d.ts +11 -0
- package/dist/library/profile.js +74 -2
- package/dist/library/profile.js.map +1 -1
- package/dist/wasi-paths.d.ts +5 -0
- package/dist/wasi-paths.js +22 -0
- package/dist/wasi-paths.js.map +1 -0
- package/package.json +2 -2
- package/surface-manifest.json +2 -2
|
@@ -1,5 +1,69 @@
|
|
|
1
|
-
|
|
1
|
+
/* IR → LLVM IR text (.ll). The LLVM backend consumes the SAME in-memory
|
|
2
|
+
* IrModule the C backend does (never the JSON dump — see the -0 lesson in
|
|
3
|
+
* the survey) and produces a textual module that rides compileC's
|
|
4
|
+
* program-TU seat: clang compiles .ll on the exact command line that
|
|
5
|
+
* compiles the .c, linking the same scr_* runtime with the same C ABI.
|
|
6
|
+
*
|
|
7
|
+
* Phase 1 was the TRIVIAL TIER: f64/bool/string locals and params, the
|
|
8
|
+
* scalar operator set, structured control flow, direct calls, interned
|
|
9
|
+
* string literals, and the console protocol. Phase 2 adds the VOLUME
|
|
10
|
+
* TIER: module globals and locals of every in-tier ref kind (arrays,
|
|
11
|
+
* record shapes, unions, function values/closures), the full array and
|
|
12
|
+
* string intrinsic surfaces, per-record-shape RC helpers (cycle headers
|
|
13
|
+
* included — the C emitter's fixpoint, ported in shapes.ts), tagged-union
|
|
14
|
+
* construction/narrowing/equality with interned immortal unit instances,
|
|
15
|
+
* capture boxes and the closure calling convention, switch/for-of
|
|
16
|
+
* lowering, and the non-throwing slice of the libCall table. EVERYTHING
|
|
17
|
+
* ELSE REFUSES loudly at the first unhandled node (LlvmUnsupportedError
|
|
18
|
+
* naming the kind) — this backend never guesses and never emits wrong
|
|
19
|
+
* code for a construct it does not model. compile() surfaces the refusal
|
|
20
|
+
* as diagnostic SC3001.
|
|
21
|
+
*
|
|
22
|
+
* RC ownership discipline: the frame/scope release-point machinery is
|
|
23
|
+
* ported from CEmitter (docs/ir.md) — every refcounted temp holds an owned
|
|
24
|
+
* +1 reference; varDecl/assign/return/call-argument MOVE that ownership;
|
|
25
|
+
* each statement releases its remaining refcounted temps when it ends;
|
|
26
|
+
* each scope releases the refcounted locals declared in it when it exits;
|
|
27
|
+
* callees own their params; return/break/continue release everything the
|
|
28
|
+
* jump bypasses (releaseForJump). Releases are type-directed through
|
|
29
|
+
* shapes.ts (the releaseCallC table's LLVM twin); frame entries can be
|
|
30
|
+
* SLOT-based (the entry names a pointer whose CURRENT value releases —
|
|
31
|
+
* conditional results like optional chains need that indirection).
|
|
32
|
+
*
|
|
33
|
+
* Exceptions (phase 4): the pending-flag unwind protocol, ported from the
|
|
34
|
+
* C emitter. `throw` moves its payload into the runtime's exception cell
|
|
35
|
+
* (scr_throw_*) and unwinds; after every call that can raise (per the
|
|
36
|
+
* SAME computeMayThrow analysis the C backend runs) a pending check tests
|
|
37
|
+
* scr_exc_pending() and unwinds — releasing frames/scopes down to the
|
|
38
|
+
* innermost try handler's depths and branching to its label, or releasing
|
|
39
|
+
* everything and returning a dummy value (never read: callers of a
|
|
40
|
+
* may-throw function test the flag before using the result). No
|
|
41
|
+
* setjmp/longjmp: longjmp would skip the emitted RC releases. try/catch
|
|
42
|
+
* follows emit-stmts.ts's shape exactly — a compile-time tryStack entry
|
|
43
|
+
* per region, the catch block taking the exception (scr_exc_take into the
|
|
44
|
+
* binding's snapshot box, or scr_exc_clear for the bindingless form), the
|
|
45
|
+
* finally body emitted once per path (normal, exception-with-stash,
|
|
46
|
+
* pending-return) with fresh temps each time. Catch bindings ride
|
|
47
|
+
* ScrCaught snapshot boxes (caughtTest/caughtNarrow/caughtCheck read
|
|
48
|
+
* them); TDZ reads test the box's payload slot and throw Node's
|
|
49
|
+
* ReferenceError. main() gains the uncaught epilogue when the entry
|
|
50
|
+
* function may throw.
|
|
51
|
+
*
|
|
52
|
+
* The dyn surface (phase 5): ScrDyn dyn values are in the tier — dyn.ts
|
|
53
|
+
* ports emit-walkers.ts's dyn slice (match/check/toDyn walkers, the
|
|
54
|
+
* String(unknown)/caught→dyn/keyed-read singletons, the checked-dynamic
|
|
55
|
+
* function boundary's thunk/box/adapter triple) and the emitter lowers
|
|
56
|
+
* the dyn expression kinds (dynFrom/dynCall/dynInvoke/dynTest/dynKeyGet/
|
|
57
|
+
* dynCheck/destructuring), the JSON.parse family, dyn record fields and
|
|
58
|
+
* overflow maps, dyn capture boxes, and generator unknown channels.
|
|
59
|
+
* The island surface (jsval/jsExit and embedded npm tables) is in the
|
|
60
|
+
* tier too; the module text and resolution tables use the same compressed,
|
|
61
|
+
* lazy-inflate representation as the C debugging backend.
|
|
62
|
+
*/
|
|
63
|
+
import { deflateRawSync } from "node:zlib";
|
|
64
|
+
import { canMarshalFuncIntoIsland, CAUGHT, DYN, F64, ffiCallbackType, islandCallbackRet, islandPromisePayloadTag, isFfiCallbackParam, isFfiContextParam, isRefCounted, isUnitType, MAY_THROW_LIB_FNS, moduleEmbedsBuiltin, moduleEmbedsCompressedNpm, moduleUsesDynInvoke, moduleUsesFetch, moduleUsesFsWatch, moduleUsesHttpServer, moduleUsesNet, moduleUsesNodeTest, moduleUsesProcessEvents, moduleUsesStream, moduleUsesTls, moduleUsesTlsCa, NPM_COMPRESS_MIN, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, STRING, typeEquals, typeKey, VOID } from "../../ir/nodes.js";
|
|
2
65
|
import { matchIntegerBytesForLoop } from "../../ir/integer-loops.js";
|
|
66
|
+
import { allocateFfiCallbackAdapters } from "../ffi-callbacks.js";
|
|
3
67
|
import { computeMayThrow } from "../emission/may-throw.js";
|
|
4
68
|
import { mangleArgPack, mangleAsyncSpawn, mangleClassNew, mangleClassObj, mangleClassRetain, mangleFnClosure, mangleFunction, mangleGenDrop, mangleGenResThunk, mangleGenSpawn, mangleGlobal, mangleLocal, mangleRecordNew, mangleRecordStruct, mangleResolveThunk, mangleTrampoline, mangleVtStruct, mangleWrapper } from "../mangle.js";
|
|
5
69
|
import { BlockBuilder } from "./blocks.js";
|
|
@@ -7,10 +71,41 @@ import { buildClassGraph, classFieldIndex, classStructSym, emitClassObjDefs, emi
|
|
|
7
71
|
import { DK, LlDyn } from "./dyn.js";
|
|
8
72
|
import { LlvmUnsupportedError } from "./unsupported.js";
|
|
9
73
|
import { LlWalkers } from "./walkers.js";
|
|
74
|
+
function ffiNativeTypeLl(cls) {
|
|
75
|
+
switch (cls) {
|
|
76
|
+
case "f64":
|
|
77
|
+
return "double";
|
|
78
|
+
case "bool":
|
|
79
|
+
case "u8":
|
|
80
|
+
return "i8";
|
|
81
|
+
case "u32":
|
|
82
|
+
case "i32":
|
|
83
|
+
return "i32";
|
|
84
|
+
case "string":
|
|
85
|
+
case "bytes":
|
|
86
|
+
throw new Error(`llvm emitter bug: span class '${cls}' has no scalar LLVM type`);
|
|
87
|
+
case "void":
|
|
88
|
+
return "void";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function ffiCallbackDummyLl(callback) {
|
|
92
|
+
switch (callback.returns) {
|
|
93
|
+
case "void":
|
|
94
|
+
return "void";
|
|
95
|
+
case "f64":
|
|
96
|
+
return "double 0.0";
|
|
97
|
+
case "bool":
|
|
98
|
+
case "u8":
|
|
99
|
+
return "i8 0";
|
|
100
|
+
case "u32":
|
|
101
|
+
case "i32":
|
|
102
|
+
return "i32 0";
|
|
103
|
+
}
|
|
104
|
+
}
|
|
10
105
|
import { arrNewCall, boxAccess, boxNewCall, computeTraced, elemAccess, emitRecordShapes, FN_ATTRS, llFieldType, mapKeyAccess, mapKeyKindNum, mapValKindNum, releaseSym, retainSym, traceAdapter, traceArg, vAdapters, } from "./shapes.js";
|
|
11
106
|
export { LlvmUnsupportedError } from "./unsupported.js";
|
|
12
|
-
export function emitLlvmModule(mod) {
|
|
13
|
-
return new LlEmitter(mod).emit();
|
|
107
|
+
export function emitLlvmModule(mod, options = {}) {
|
|
108
|
+
return new LlEmitter(mod, options).emit();
|
|
14
109
|
}
|
|
15
110
|
/** Exact double literal: LLVM's 16-digit hex form round-trips every f64
|
|
16
111
|
* bit pattern (−0 and the full denormal range included). */
|
|
@@ -22,8 +117,7 @@ function f64Lit(n) {
|
|
|
22
117
|
const F64_INF = f64Lit(Infinity);
|
|
23
118
|
/** LLVM c"..." payload for a UTF-8 literal, NUL-terminated like the C
|
|
24
119
|
* emitter's flexible-array-member initializer. */
|
|
25
|
-
function
|
|
26
|
-
const bytes = Buffer.from(text, "utf8");
|
|
120
|
+
function llBytes(bytes) {
|
|
27
121
|
let s = "";
|
|
28
122
|
for (const b of bytes) {
|
|
29
123
|
s +=
|
|
@@ -33,6 +127,9 @@ function llStrBytes(text) {
|
|
|
33
127
|
}
|
|
34
128
|
return `${s}\\00`;
|
|
35
129
|
}
|
|
130
|
+
function llStrBytes(text) {
|
|
131
|
+
return llBytes(Buffer.from(text, "utf8"));
|
|
132
|
+
}
|
|
36
133
|
/** The non-throwing libCall slice the tier claims: IrLibFn → runtime
|
|
37
134
|
* symbol, called generically (LLVM arg/result types derive from the call
|
|
38
135
|
* site's IR types, which is exactly the contract the C prototypes pin).
|
|
@@ -549,6 +646,9 @@ const LIB_FN_SYMS = {
|
|
|
549
646
|
"http.resWriteHeadPairs": "scr_http_res_write_head_pairs",
|
|
550
647
|
"http.resWriteHeadDyn": "scr_http_res_write_head_dyn",
|
|
551
648
|
"http.serverJoinDupHeaders": "scr_http_server_join_duplicate_headers",
|
|
649
|
+
"http.serverTimeoutGet": "scr_net_server_timeout_get",
|
|
650
|
+
"http.serverTimeoutSet": "scr_net_server_timeout_set",
|
|
651
|
+
"http.serverTimeoutOptionSet": "scr_net_server_timeout_option_set",
|
|
552
652
|
"http.clientWrite": "scr_http_client_write_str",
|
|
553
653
|
"http.clientWriteBytes": "scr_http_client_write_bytes",
|
|
554
654
|
"http.clientEnd": "scr_http_client_end",
|
|
@@ -771,6 +871,9 @@ const DV_SET_KIND = {
|
|
|
771
871
|
};
|
|
772
872
|
class LlEmitter {
|
|
773
873
|
mod;
|
|
874
|
+
sizeType;
|
|
875
|
+
cycleColorOffset;
|
|
876
|
+
wasi;
|
|
774
877
|
/** Interned string literals: UTF-8 text → { symbol, byte length } —
|
|
775
878
|
* first-use order, the C emitter's determinism discipline. */
|
|
776
879
|
literals = new Map();
|
|
@@ -811,6 +914,9 @@ class LlEmitter {
|
|
|
811
914
|
fnByName = new Map();
|
|
812
915
|
/** Manifest-bound native imports, used by ffiCall emission. */
|
|
813
916
|
ffiByName = new Map();
|
|
917
|
+
/** C-ABI callback trampolines and (for raw/no-userdata callbacks) their
|
|
918
|
+
* distinct call-scoped TLS closure slots. */
|
|
919
|
+
ffiCallbackAdapters;
|
|
814
920
|
globalTypes = new Map();
|
|
815
921
|
/** May-throw analysis (the C emitter's computeMayThrow, shared): pending
|
|
816
922
|
* checks are emitted only after calls that can actually raise. */
|
|
@@ -873,7 +979,7 @@ class LlEmitter {
|
|
|
873
979
|
jumpTargets = [];
|
|
874
980
|
currentLocals = new Map();
|
|
875
981
|
captureIds = new Set();
|
|
876
|
-
/** Active canonical byte-loop induction bindings: local id →
|
|
982
|
+
/** Active canonical byte-loop induction bindings: local id → size_t slot. */
|
|
877
983
|
integerLoopBindings = new Map();
|
|
878
984
|
/** Enclosing try-with-FINALLY regions, innermost last: a `return`
|
|
879
985
|
* inside one runs every crossed finally (innermost first) before the
|
|
@@ -894,6 +1000,9 @@ class LlEmitter {
|
|
|
894
1000
|
/** Return type of the function being emitted — the unwind path returns
|
|
895
1001
|
* a dummy of this type (never read: callers check the flag first). */
|
|
896
1002
|
currentReturnType = VOID;
|
|
1003
|
+
/** Active only while emitting a wasm32 async body lowered with LLVM's
|
|
1004
|
+
* switched-coroutine intrinsics. */
|
|
1005
|
+
currentWasiCoro = null;
|
|
897
1006
|
/** The generator channels of the function being emitted (null outside
|
|
898
1007
|
* generator bodies): yieldExpr emission reads them, and emitTryCatch's
|
|
899
1008
|
* catch prologue emits the GENRET sentinel re-unwind exactly here. */
|
|
@@ -901,12 +1010,20 @@ class LlEmitter {
|
|
|
901
1010
|
/** Active optional-chain bind slots, by chain id (chainRecv reads). */
|
|
902
1011
|
chainSlots = new Map();
|
|
903
1012
|
logArgSlots = 0;
|
|
904
|
-
constructor(mod) {
|
|
1013
|
+
constructor(mod, options) {
|
|
905
1014
|
this.mod = mod;
|
|
1015
|
+
this.sizeType = options.pointerBits === 32 ? "i32" : "i64";
|
|
1016
|
+
this.wasi = options.wasi === true;
|
|
1017
|
+
// ScrCycHdr is { ptr trace; ptr free; i32 color; i16 buffered;
|
|
1018
|
+
// i16 gen; size_t buf_index }. The object follows it, so color is 12
|
|
1019
|
+
// bytes behind a wasm32 object and 16 bytes behind a 64-bit object.
|
|
1020
|
+
this.cycleColorOffset = options.pointerBits === 32 ? 12 : 16;
|
|
1021
|
+
this.ffiCallbackAdapters = allocateFfiCallbackAdapters(mod.ffiImports ?? []);
|
|
906
1022
|
for (const fn of mod.functions)
|
|
907
1023
|
this.fnByName.set(fn.name, fn);
|
|
908
|
-
for (const entry of mod.ffiImports ?? [])
|
|
1024
|
+
for (const entry of mod.ffiImports ?? []) {
|
|
909
1025
|
this.ffiByName.set(entry.name, entry);
|
|
1026
|
+
}
|
|
910
1027
|
const mt = computeMayThrow(mod);
|
|
911
1028
|
this.mayThrow = mt.fns;
|
|
912
1029
|
this.indirectMayThrow = mt.indirect;
|
|
@@ -978,9 +1095,9 @@ class LlEmitter {
|
|
|
978
1095
|
lib: rec.lib,
|
|
979
1096
|
});
|
|
980
1097
|
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1098
|
+
}
|
|
1099
|
+
abiOffset(native64, wasm32) {
|
|
1100
|
+
return this.sizeType === "i32" ? wasm32 : native64;
|
|
984
1101
|
}
|
|
985
1102
|
// ── types ───────────────────────────────────────────────────────────────
|
|
986
1103
|
llType(t) {
|
|
@@ -1037,6 +1154,93 @@ class LlEmitter {
|
|
|
1037
1154
|
}
|
|
1038
1155
|
}
|
|
1039
1156
|
// ── module assembly ─────────────────────────────────────────────────────
|
|
1157
|
+
ffiCallbackAdapter(binding, id) {
|
|
1158
|
+
const adapter = this.ffiCallbackAdapters.get(`${binding}:${id}`);
|
|
1159
|
+
if (!adapter)
|
|
1160
|
+
throw new Error(`llvm emitter bug: no callback adapter for ${binding}:${id}`);
|
|
1161
|
+
return adapter;
|
|
1162
|
+
}
|
|
1163
|
+
/** C-callable scalar callback trampolines. A callback with an explicit
|
|
1164
|
+
* context entry receives the closure at that exact ABI position. A raw
|
|
1165
|
+
* callback loads it from a call-scoped TLS slot installed around the
|
|
1166
|
+
* outer native call. */
|
|
1167
|
+
emitFfiCallbackDefs() {
|
|
1168
|
+
const globals = [];
|
|
1169
|
+
const defs = [];
|
|
1170
|
+
if (this.ffiCallbackAdapters.size === 0)
|
|
1171
|
+
return { globals, defs };
|
|
1172
|
+
this.declare(`declare zeroext i1 @scr_exc_pending()`);
|
|
1173
|
+
this.declare(`declare void @scr_trap(ptr)`);
|
|
1174
|
+
const expired = this.cstr("scriptc: native callback invoked outside its call-scoped lifetime\n");
|
|
1175
|
+
for (const adapter of this.ffiCallbackAdapters.values()) {
|
|
1176
|
+
const cb = adapter.callback;
|
|
1177
|
+
if (adapter.tls !== null)
|
|
1178
|
+
globals.push(`@${adapter.tls} = internal thread_local global ptr null`);
|
|
1179
|
+
const params = cb.params.map((param, i) => isFfiContextParam(param) ? `ptr %ctx` : `${ffiNativeTypeLl(param)} %a${i}`);
|
|
1180
|
+
const ret = ffiNativeTypeLl(cb.returns);
|
|
1181
|
+
defs.push(`define internal ${ret} @${adapter.symbol}(${params.join(", ")}) ${FN_ATTRS} {`, `entry:`, adapter.tls === null ? ` %cb = getelementptr inbounds i8, ptr %ctx, i64 0` : ` %cb = load ptr, ptr @${adapter.tls}`, ` %missing = icmp eq ptr %cb, null`, ` br i1 %missing, label %expired, label %ready`, `expired:`, ` call void @scr_trap(ptr ${expired})`, ` unreachable`, `ready:`, ` %pending = call zeroext i1 @scr_exc_pending()`, ` br i1 %pending, label %skip, label %invoke`, `skip:`, ` ret ${ffiCallbackDummyLl(cb)}`, `invoke:`, ` %fnp = getelementptr inbounds %ScrClosure, ptr %cb, i64 0, i32 1`, ` %fn = load ptr, ptr %fnp`);
|
|
1182
|
+
const scriptArgs = [];
|
|
1183
|
+
for (let i = 0; i < cb.params.length; i++) {
|
|
1184
|
+
const param = cb.params[i];
|
|
1185
|
+
if (isFfiContextParam(param))
|
|
1186
|
+
continue;
|
|
1187
|
+
switch (param) {
|
|
1188
|
+
case "f64":
|
|
1189
|
+
scriptArgs.push(`double %a${i}`);
|
|
1190
|
+
break;
|
|
1191
|
+
case "bool":
|
|
1192
|
+
defs.push(` %s${i} = icmp ne i8 %a${i}, 0`);
|
|
1193
|
+
scriptArgs.push(`i1 %s${i}`);
|
|
1194
|
+
break;
|
|
1195
|
+
case "u8":
|
|
1196
|
+
defs.push(` %s${i} = uitofp i8 %a${i} to double`);
|
|
1197
|
+
scriptArgs.push(`double %s${i}`);
|
|
1198
|
+
break;
|
|
1199
|
+
case "u32":
|
|
1200
|
+
defs.push(` %s${i} = uitofp i32 %a${i} to double`);
|
|
1201
|
+
scriptArgs.push(`double %s${i}`);
|
|
1202
|
+
break;
|
|
1203
|
+
case "i32":
|
|
1204
|
+
defs.push(` %s${i} = sitofp i32 %a${i} to double`);
|
|
1205
|
+
scriptArgs.push(`double %s${i}`);
|
|
1206
|
+
break;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
const ft = ffiCallbackType(cb);
|
|
1210
|
+
const internalRet = this.llType(ft.ret);
|
|
1211
|
+
const callArgs = [`ptr %cb`, ...scriptArgs].join(", ");
|
|
1212
|
+
if (cb.returns === "void") {
|
|
1213
|
+
defs.push(` call void %fn(${callArgs})`, ` ret void`, `}`, ``);
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1216
|
+
defs.push(` %result = call ${internalRet} %fn(${callArgs})`);
|
|
1217
|
+
switch (cb.returns) {
|
|
1218
|
+
case "f64":
|
|
1219
|
+
defs.push(` ret double %result`);
|
|
1220
|
+
break;
|
|
1221
|
+
case "bool":
|
|
1222
|
+
defs.push(` %out = zext i1 %result to i8`, ` ret i8 %out`);
|
|
1223
|
+
break;
|
|
1224
|
+
case "u8":
|
|
1225
|
+
case "u32":
|
|
1226
|
+
this.declare(`declare double @scr_bit_ushr(double, double)`);
|
|
1227
|
+
defs.push(` %coerced = call double @scr_bit_ushr(double %result, double ${f64Lit(0)})`, ` %wide = fptoui double %coerced to i32`);
|
|
1228
|
+
if (cb.returns === "u8") {
|
|
1229
|
+
defs.push(` %out = trunc i32 %wide to i8`, ` ret i8 %out`);
|
|
1230
|
+
}
|
|
1231
|
+
else {
|
|
1232
|
+
defs.push(` ret i32 %wide`);
|
|
1233
|
+
}
|
|
1234
|
+
break;
|
|
1235
|
+
case "i32":
|
|
1236
|
+
this.declare(`declare double @scr_bit_or(double, double)`);
|
|
1237
|
+
defs.push(` %coerced = call double @scr_bit_or(double %result, double ${f64Lit(0)})`, ` %out = fptosi double %coerced to i32`, ` ret i32 %out`);
|
|
1238
|
+
break;
|
|
1239
|
+
}
|
|
1240
|
+
defs.push(`}`, ``);
|
|
1241
|
+
}
|
|
1242
|
+
return { globals, defs };
|
|
1243
|
+
}
|
|
1040
1244
|
emit() {
|
|
1041
1245
|
// Function bodies first (the literal/unit/fn-value tables fill as they
|
|
1042
1246
|
// emit), then the file assembles around them — the C emitter's order.
|
|
@@ -1048,6 +1252,24 @@ class LlEmitter {
|
|
|
1048
1252
|
const classObjDefs = emitClassObjDefs(this, this.classMeta, this.classObjs, this.fnByName, (t) => this.llType(t));
|
|
1049
1253
|
const wrappers = this.emitFnValueDefs();
|
|
1050
1254
|
const asyncDefs = this.emitAsyncScaffolding();
|
|
1255
|
+
const ffiCallbacks = this.emitFfiCallbackDefs();
|
|
1256
|
+
const embedded = this.mod.embedded;
|
|
1257
|
+
const usesIsland = embedded !== undefined && embedded.modules.length > 0;
|
|
1258
|
+
const storeNpmText = (text) => {
|
|
1259
|
+
const plain = Buffer.from(text, "utf8");
|
|
1260
|
+
if (text.length < NPM_COMPRESS_MIN)
|
|
1261
|
+
return { bytes: plain, raw: 0 };
|
|
1262
|
+
const deflated = deflateRawSync(plain, { level: 9 });
|
|
1263
|
+
return deflated.length < plain.length
|
|
1264
|
+
? { bytes: deflated, raw: plain.length }
|
|
1265
|
+
: { bytes: plain, raw: 0 };
|
|
1266
|
+
};
|
|
1267
|
+
const npmStored = usesIsland
|
|
1268
|
+
? embedded.modules.map((m) => ({
|
|
1269
|
+
src: storeNpmText(m.source),
|
|
1270
|
+
esm: m.esm === undefined ? null : storeNpmText(m.esm),
|
|
1271
|
+
}))
|
|
1272
|
+
: [];
|
|
1051
1273
|
// Module globals, FIRST OCCURRENCE per id: a class-expression static
|
|
1052
1274
|
// instantiated through several mixin applications registers one global
|
|
1053
1275
|
// id several times (2041-mixin-values) — C's tentative definitions
|
|
@@ -1107,8 +1329,20 @@ class LlEmitter {
|
|
|
1107
1329
|
// any island entry (the engine's lazy boot consults it) — cc.ts
|
|
1108
1330
|
// compiles scr_fetch.c on the same predicate.
|
|
1109
1331
|
const usesFetch = moduleUsesFetch(this.mod);
|
|
1110
|
-
const
|
|
1332
|
+
const embedsZlib = moduleEmbedsBuiltin(this.mod, "node:zlib");
|
|
1333
|
+
const embedsNet = moduleEmbedsBuiltin(this.mod, "node:http") ||
|
|
1334
|
+
moduleEmbedsBuiltin(this.mod, "node:https") ||
|
|
1335
|
+
moduleEmbedsBuiltin(this.mod, "node:net") ||
|
|
1336
|
+
moduleEmbedsBuiltin(this.mod, "node:tls");
|
|
1337
|
+
const snapshotsTlsCa = moduleUsesTls(this.mod) || moduleUsesTlsCa(this.mod) ||
|
|
1338
|
+
moduleEmbedsBuiltin(this.mod, "node:https") ||
|
|
1339
|
+
moduleEmbedsBuiltin(this.mod, "node:tls");
|
|
1111
1340
|
const hasRefGlobals = globals.some((g) => isRefCounted(g.type)) || fnValueProps.length > 0;
|
|
1341
|
+
// The process verdict has the same precedence as the C reference
|
|
1342
|
+
// emitter: node:test owns the final status when present; otherwise an
|
|
1343
|
+
// embedded process.exitCode owns it; ordinary programs return zero.
|
|
1344
|
+
const usesNodeTest = moduleUsesNodeTest(this.mod);
|
|
1345
|
+
const programExitUsesIsland = !usesNodeTest && usesIsland;
|
|
1112
1346
|
// Declared NOW — the extern block flushes before main assembles.
|
|
1113
1347
|
if (usesEvents)
|
|
1114
1348
|
this.declare(`declare void @scr_events_install()`);
|
|
@@ -1124,6 +1358,20 @@ class LlEmitter {
|
|
|
1124
1358
|
this.declare(`declare void @scr_http_dyn_install()`);
|
|
1125
1359
|
if (usesFetch)
|
|
1126
1360
|
this.declare(`declare void @scr_fetch_install()`);
|
|
1361
|
+
if (embedsZlib)
|
|
1362
|
+
this.declare(`declare void @scr_zlib_island_install()`);
|
|
1363
|
+
if (embedsNet)
|
|
1364
|
+
this.declare(`declare void @scr_net_island_install()`);
|
|
1365
|
+
if (usesIsland) {
|
|
1366
|
+
this.declare(`declare void @scr_island_modules(ptr, ${this.sizeType}, ptr, ${this.sizeType})`);
|
|
1367
|
+
this.declare(`declare i32 @scr_island_exit_code()`);
|
|
1368
|
+
if (moduleEmbedsCompressedNpm(this.mod)) {
|
|
1369
|
+
this.declare(`declare void @scr_island_set_inflate(ptr)`);
|
|
1370
|
+
this.declare(`declare zeroext i1 @scr_zlib_inflate_exact(ptr, ${this.sizeType}, ptr, ${this.sizeType})`);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
if (usesNodeTest)
|
|
1374
|
+
this.declare(`declare i32 @scr_test_exit_code()`);
|
|
1127
1375
|
if (snapshotsTlsCa) {
|
|
1128
1376
|
this.declare(`declare void @scr_tls_ca_install()`);
|
|
1129
1377
|
}
|
|
@@ -1145,11 +1393,12 @@ class LlEmitter {
|
|
|
1145
1393
|
const entryMayThrow = this.mayThrow.has(this.mod.entry);
|
|
1146
1394
|
// The event loop runs when timers appeared OR any async/generator
|
|
1147
1395
|
// function exists (the C main's hasAsync || hasGenerators ||
|
|
1148
|
-
// usesTimers gate
|
|
1396
|
+
// usesTimers gate). Generator programs run
|
|
1149
1397
|
// the loop too: its exit accounting notes still-suspended generator
|
|
1150
1398
|
// fibers as abandoned, so the RC audit downgrades exactly like the
|
|
1151
1399
|
// async loop-exhaustion story.
|
|
1152
1400
|
const runsLoop = this.usesTimers ||
|
|
1401
|
+
usesIsland ||
|
|
1153
1402
|
this.mod.functions.some((f) => f.async === true || f.generator !== undefined);
|
|
1154
1403
|
const uncaughtReleases = entryMayThrow && !asyncEntry ? globalReleaseLines("gu") : [];
|
|
1155
1404
|
const loopReleasesU = runsLoop ? globalReleaseLines("gl") : [];
|
|
@@ -1171,7 +1420,40 @@ class LlEmitter {
|
|
|
1171
1420
|
this.declare(`declare i32 @scr_promise_finish_top_level(ptr)`);
|
|
1172
1421
|
this.declare(`declare void @scr_promise_rethrow_top_level(ptr)`);
|
|
1173
1422
|
this.declare(`declare void @scr_promise_release(ptr)`);
|
|
1423
|
+
this.declare(`declare void @scr_exit_code_note(i32)`);
|
|
1424
|
+
if (programExitUsesIsland && usesEvents && hasRefGlobals) {
|
|
1425
|
+
this.declare(`declare ${this.sizeType} @scr_island_exit_code_version()`);
|
|
1426
|
+
}
|
|
1174
1427
|
}
|
|
1428
|
+
const topPendingExitLines = () => {
|
|
1429
|
+
if (!asyncEntry)
|
|
1430
|
+
return [];
|
|
1431
|
+
const lines = [];
|
|
1432
|
+
if (usesNodeTest) {
|
|
1433
|
+
lines.push(` %tla_program_exit = call i32 @scr_test_exit_code()`);
|
|
1434
|
+
}
|
|
1435
|
+
else if (usesIsland) {
|
|
1436
|
+
lines.push(` %tla_program_exit = call i32 @scr_island_exit_code()`);
|
|
1437
|
+
}
|
|
1438
|
+
if (usesNodeTest || usesIsland) {
|
|
1439
|
+
lines.push(` %tla_program_exit_zero = icmp eq i32 %tla_program_exit, 0`, ` %tla_exit_status = select i1 %tla_program_exit_zero, i32 %tla_status, i32 %tla_program_exit`);
|
|
1440
|
+
}
|
|
1441
|
+
const exitStatus = usesNodeTest || usesIsland ? "%tla_exit_status" : "%tla_status";
|
|
1442
|
+
const tracksIslandExit = programExitUsesIsland && usesEvents && hasRefGlobals;
|
|
1443
|
+
if (tracksIslandExit) {
|
|
1444
|
+
lines.push(` %tla_exit_version = call ${this.sizeType} @scr_island_exit_code_version()`);
|
|
1445
|
+
}
|
|
1446
|
+
// finish_top_level initially notes 13. Replace that hint before exit
|
|
1447
|
+
// listeners run when a higher-priority verdict was already selected.
|
|
1448
|
+
lines.push(` call void @scr_exit_code_note(i32 ${exitStatus})`);
|
|
1449
|
+
lines.push(...exitListenerLines("xp"));
|
|
1450
|
+
if (tracksIslandExit) {
|
|
1451
|
+
lines.push(` %tla_exit_version_after = call ${this.sizeType} @scr_island_exit_code_version()`, ` %tla_exit_changed = icmp ne ${this.sizeType} %tla_exit_version_after, %tla_exit_version`, ` br i1 %tla_exit_changed, label %tla_exit_updated, label %tla_exit_unchanged`, `tla_exit_updated:`, ` %tla_listener_exit = call i32 @scr_island_exit_code()`, ` call void @scr_exit_code_note(i32 %tla_listener_exit)`, ` br label %tla_exit_done`, `tla_exit_unchanged:`, ` br label %tla_exit_done`, `tla_exit_done:`, ` %tla_final_exit = phi i32 [ %tla_listener_exit, %tla_exit_updated ], [ ${exitStatus}, %tla_exit_unchanged ]`);
|
|
1452
|
+
}
|
|
1453
|
+
lines.push(...topPendingReleases);
|
|
1454
|
+
lines.push(` ret i32 ${tracksIslandExit ? "%tla_final_exit" : exitStatus}`);
|
|
1455
|
+
return lines;
|
|
1456
|
+
};
|
|
1175
1457
|
// LIBRARY mode: the runtime entry points the generated library
|
|
1176
1458
|
// symbols delegate to — declared before the extern block flushes.
|
|
1177
1459
|
if (this.mod.lib !== undefined) {
|
|
@@ -1182,10 +1464,10 @@ class LlEmitter {
|
|
|
1182
1464
|
this.declare(`declare void @scr_library_arena_reset()`);
|
|
1183
1465
|
this.declare(`declare void @scr_library_collect()`);
|
|
1184
1466
|
if (this.mod.lib.exports.some((e) => e.params.includes("string"))) {
|
|
1185
|
-
this.declare(`declare ptr @scr_library_str_in(ptr,
|
|
1467
|
+
this.declare(`declare ptr @scr_library_str_in(ptr, ${this.sizeType})`);
|
|
1186
1468
|
}
|
|
1187
1469
|
if (this.mod.lib.exports.some((e) => e.params.includes("bytes"))) {
|
|
1188
|
-
this.declare(`declare ptr @scr_library_bytes_in(ptr,
|
|
1470
|
+
this.declare(`declare ptr @scr_library_bytes_in(ptr, ${this.sizeType}, ptr)`);
|
|
1189
1471
|
}
|
|
1190
1472
|
if (this.mod.lib.exports.some((e) => e.params.includes("i64"))) {
|
|
1191
1473
|
this.declare(`declare double @scr_library_i64_in(i64, ptr)`);
|
|
@@ -1212,59 +1494,69 @@ class LlEmitter {
|
|
|
1212
1494
|
// the C layout (4 bytes padding after the tag). ScrUnion/ScrClosure
|
|
1213
1495
|
// mirror scr_runtime.h field-for-field (tag reads, slot peeks, the
|
|
1214
1496
|
// fn pointer, and the caps[] tail all address through them).
|
|
1215
|
-
`%ScrStr = type {
|
|
1497
|
+
`%ScrStr = type { ${this.sizeType}, ${this.sizeType}, ${this.sizeType} }`,
|
|
1216
1498
|
`%ScrLogArg = type { i32, i64 }`,
|
|
1217
|
-
`%ScrVt = type {
|
|
1218
|
-
`%ScrUnion = type {
|
|
1219
|
-
`%ScrClosure = type {
|
|
1220
|
-
`%ScrRegex = type {
|
|
1499
|
+
`%ScrVt = type { ${this.sizeType}, ${this.sizeType}, ptr }`,
|
|
1500
|
+
`%ScrUnion = type { ${this.sizeType}, i32, ptr, ptr, ptr, i64 }`,
|
|
1501
|
+
`%ScrClosure = type { ${this.sizeType}, ptr, ${this.sizeType}, ptr }`,
|
|
1502
|
+
`%ScrRegex = type { ${this.sizeType}, ptr, ptr, ptr }`,
|
|
1221
1503
|
// ScrArr mirror { rc, len, cap, elem(i32+pad), elem_retain,
|
|
1222
1504
|
// elem_release, elem_trace, data } — the immortal tagged-template
|
|
1223
1505
|
// strings objects lay out through it (nothing GEPs into live heap
|
|
1224
1506
|
// arrays; those stay behind the runtime's own entry points).
|
|
1225
|
-
`%ScrArr = type {
|
|
1507
|
+
`%ScrArr = type { ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, i32, ptr, ptr, ptr, ptr }`,
|
|
1226
1508
|
// The runtime error prefix { rc, vt, name, message, code } and the
|
|
1227
1509
|
// class-object shape { rc, pre, post, ctor, name } — field reads on
|
|
1228
1510
|
// builtin errors and classval loads GEP through these.
|
|
1229
|
-
`%ScrError = type {
|
|
1230
|
-
`%ScrClassObj = type {
|
|
1511
|
+
`%ScrError = type { ${this.sizeType}, ptr, ptr, ptr, ptr }`,
|
|
1512
|
+
`%ScrClassObj = type { ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, ptr, ptr }`,
|
|
1231
1513
|
// The runtime emitter prefix { rc, vt, reg, cls } — user subclasses
|
|
1232
1514
|
// embed it (classes.ts), and bare-emitter GEPs address through it.
|
|
1233
|
-
`%ScrEmitter = type {
|
|
1515
|
+
`%ScrEmitter = type { ${this.sizeType}, ptr, ptr, ptr }`,
|
|
1234
1516
|
// The runtime stream layout { rc, vt, reg, cls, st } — one struct
|
|
1235
1517
|
// for all five stream classes; stream subclasses embed it.
|
|
1236
|
-
`%ScrStream = type {
|
|
1518
|
+
`%ScrStream = type { ${this.sizeType}, ptr, ptr, ptr, ptr }`,
|
|
1237
1519
|
// The catch-binding snapshot box { rc, kind, f64, b, payload,
|
|
1238
1520
|
// retain_fn, release_fn, trace_fn } — caughtTest kind reads and
|
|
1239
1521
|
// caughtNarrow payload extraction GEP through it (offsets match
|
|
1240
1522
|
// scr_runtime.h's natural alignment: kind at 8, f64 at 16, b at 24,
|
|
1241
1523
|
// payload at 32).
|
|
1242
|
-
`%ScrCaught = type {
|
|
1524
|
+
`%ScrCaught = type { ${this.sizeType}, i32, double, i8, ptr, ptr, ptr, ptr }`,
|
|
1243
1525
|
// ScrBytes { rc, len, elem(i32+pad), data, backing }. Indexed
|
|
1244
1526
|
// typed-array access GEPs through this directly: the IR type already
|
|
1245
1527
|
// fixes elem, so the hot path needs neither a runtime kind load nor
|
|
1246
1528
|
// the generic scr_bytes_get/set call.
|
|
1247
|
-
`%ScrBytes = type {
|
|
1529
|
+
`%ScrBytes = type { ${this.sizeType}, ${this.sizeType}, i32, ptr, ptr }`,
|
|
1248
1530
|
// The capture box { rc, kind, obj_retain, obj_release, obj_trace,
|
|
1249
1531
|
// slot } — TDZ reads peek the payload slot (offset 40) directly.
|
|
1250
|
-
`%ScrBox = type {
|
|
1532
|
+
`%ScrBox = type { ${this.sizeType}, i32, ptr, ptr, ptr, i64 }`,
|
|
1251
1533
|
// The stack buffer of the emitted JSON serializers { data, len, cap }.
|
|
1252
|
-
`%ScrJsonBuf = type { ptr,
|
|
1534
|
+
`%ScrJsonBuf = type { ptr, ${this.sizeType}, ${this.sizeType}, ptr, ${this.sizeType}, ${this.sizeType} }`,
|
|
1253
1535
|
// The dynCheck error-path spine { parent, key, index } — the emitted
|
|
1254
1536
|
// builders stack-allocate one per recursion level (dyn.ts).
|
|
1255
|
-
`%ScrDynPath = type { ptr, ptr,
|
|
1537
|
+
`%ScrDynPath = type { ptr, ptr, ${this.sizeType} }`,
|
|
1538
|
+
`%ScrIslandModule = type { ptr, ptr, ${this.sizeType}, ${this.sizeType}, i32, ptr, ${this.sizeType}, ${this.sizeType} }`,
|
|
1539
|
+
`%ScrIslandEdge = type { ptr, ptr, ptr, i32 }`,
|
|
1256
1540
|
];
|
|
1257
1541
|
out.push(...shapes.typeDefs);
|
|
1258
1542
|
out.push(...classShapes.typeDefs);
|
|
1259
|
-
|
|
1543
|
+
// Thread-instanced library state (abi.instance_per_thread): the
|
|
1544
|
+
// program TU's mutable globals — module globals, run-once guards, the
|
|
1545
|
+
// lazily-compiled regex literal caches — and the runtime globals its
|
|
1546
|
+
// init stamps live in thread-local storage, matching the runtime
|
|
1547
|
+
// objects compiled with -DSCR_THREAD_INSTANCES. Immutable interned
|
|
1548
|
+
// data (string literals, unit arms, template arrays, vtables) stays
|
|
1549
|
+
// shared.
|
|
1550
|
+
const tl = this.mod.lib?.threadInstances === true ? "thread_local " : "";
|
|
1551
|
+
out.push(``, `@scr_error_vts = external ${tl}global [5 x %ScrVt]`, `declare void @scr_init()`, `declare void @scr_lib_init(i32, ptr)`);
|
|
1260
1552
|
for (const d of this.decls)
|
|
1261
1553
|
out.push(d);
|
|
1262
1554
|
out.push(``);
|
|
1263
1555
|
for (const [text, lit] of this.literals) {
|
|
1264
1556
|
// Immortal interned ScrStr: { rc = SIZE_MAX, len, cap = len, bytes\0 } —
|
|
1265
1557
|
// the C emitter's static table, retain/release skip rc == SIZE_MAX.
|
|
1266
|
-
out.push(`@${lit.sym} = internal global {
|
|
1267
|
-
`{
|
|
1558
|
+
out.push(`@${lit.sym} = internal global { ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, [${lit.len + 1} x i8] } ` +
|
|
1559
|
+
`{ ${this.sizeType} -1, ${this.sizeType} ${lit.len}, ${this.sizeType} ${lit.len}, [${lit.len + 1} x i8] c"${llStrBytes(text)}" }`);
|
|
1268
1560
|
}
|
|
1269
1561
|
if (this.literals.size > 0)
|
|
1270
1562
|
out.push(``);
|
|
@@ -1273,7 +1565,7 @@ class LlEmitter {
|
|
|
1273
1565
|
// slot and RC entry points zero — retain/release/collector all skip
|
|
1274
1566
|
// rc == SIZE_MAX, so these never join the RC audit or a trace walk.
|
|
1275
1567
|
const [unionId, tag] = key.split(":");
|
|
1276
|
-
out.push(`@${sym} = internal global %ScrUnion {
|
|
1568
|
+
out.push(`@${sym} = internal global %ScrUnion { ${this.sizeType} -1, i32 ${tag}, ptr null, ptr null, ptr null, i64 0 } ; ${unionId} unit arm`);
|
|
1277
1569
|
}
|
|
1278
1570
|
if (this.unitInstances.size > 0)
|
|
1279
1571
|
out.push(``);
|
|
@@ -1281,7 +1573,7 @@ class LlEmitter {
|
|
|
1281
1573
|
// One immortal ScrRegex per (pattern, flags) literal, pointing at
|
|
1282
1574
|
// the interned source/flags strings. The bc slot starts null (lazy
|
|
1283
1575
|
// compile, cached by the runtime) — a mutable global, not constant.
|
|
1284
|
-
out.push(`@${re.sym} = internal global %ScrRegex {
|
|
1576
|
+
out.push(`@${re.sym} = internal ${tl}global %ScrRegex { ${this.sizeType} -1, ptr ${re.src}, ptr ${re.fl}, ptr null } ; ${key.replace(/\n/g, "\\n")}`);
|
|
1285
1577
|
}
|
|
1286
1578
|
if (this.regexInstances.size > 0)
|
|
1287
1579
|
out.push(``);
|
|
@@ -1291,7 +1583,7 @@ class LlEmitter {
|
|
|
1291
1583
|
// over it (rc == SIZE_MAX, len == cap, SCR_ELEM_STR = 2, no REF
|
|
1292
1584
|
// entry points). Reads retain immortal strings — a no-op.
|
|
1293
1585
|
const n = inst.slots.length;
|
|
1294
|
-
out.push(`@${inst.sym}_data = internal constant [${n} x ptr] [ ${inst.slots.map((s) => `ptr ${s}`).join(", ")} ]`, `@${inst.sym} = internal global %ScrArr {
|
|
1586
|
+
out.push(`@${inst.sym}_data = internal constant [${n} x ptr] [ ${inst.slots.map((s) => `ptr ${s}`).join(", ")} ]`, `@${inst.sym} = internal global %ScrArr { ${this.sizeType} -1, ${this.sizeType} ${n}, ${this.sizeType} ${n}, i32 2, ptr null, ptr null, ptr null, ptr @${inst.sym}_data }`);
|
|
1295
1587
|
}
|
|
1296
1588
|
if (this.templateStringsInstances.size > 0)
|
|
1297
1589
|
out.push(``);
|
|
@@ -1302,14 +1594,52 @@ class LlEmitter {
|
|
|
1302
1594
|
}
|
|
1303
1595
|
if (this.cstrs.size > 0)
|
|
1304
1596
|
out.push(``);
|
|
1597
|
+
if (usesIsland) {
|
|
1598
|
+
const fmt = { esm: 0, cjs: 1, json: 2 };
|
|
1599
|
+
const edgeKind = { any: 0, import: 1, require: 2 };
|
|
1600
|
+
embedded.modules.forEach((m, i) => {
|
|
1601
|
+
const stored = npmStored[i];
|
|
1602
|
+
const key = Buffer.from(m.key, "utf8");
|
|
1603
|
+
out.push(`@sc_npm_key_${i} = internal constant [${key.length + 1} x i8] c"${llBytes(key)}"`, `@sc_npm_src_${i} = internal constant [${stored.src.bytes.length + 1} x i8] c"${llBytes(stored.src.bytes)}"`);
|
|
1604
|
+
if (stored.esm !== null) {
|
|
1605
|
+
out.push(`@sc_npm_esm_${i} = internal constant [${stored.esm.bytes.length + 1} x i8] c"${llBytes(stored.esm.bytes)}"`);
|
|
1606
|
+
}
|
|
1607
|
+
});
|
|
1608
|
+
const moduleRows = embedded.modules.map((m, i) => {
|
|
1609
|
+
const stored = npmStored[i];
|
|
1610
|
+
const esm = stored.esm === null
|
|
1611
|
+
? `ptr null, ${this.sizeType} 0, ${this.sizeType} 0`
|
|
1612
|
+
: `ptr @sc_npm_esm_${i}, ${this.sizeType} ${stored.esm.bytes.length}, ${this.sizeType} ${stored.esm.raw}`;
|
|
1613
|
+
return `%ScrIslandModule { ptr @sc_npm_key_${i}, ptr @sc_npm_src_${i}, ` +
|
|
1614
|
+
`${this.sizeType} ${stored.src.bytes.length}, ${this.sizeType} ${stored.src.raw}, ` +
|
|
1615
|
+
`i32 ${fmt[m.format]}, ${esm} }`;
|
|
1616
|
+
});
|
|
1617
|
+
out.push(`@sc_npm_modules = internal constant [${moduleRows.length} x %ScrIslandModule] [ ${moduleRows.join(", ")} ]`);
|
|
1618
|
+
embedded.edges.forEach((edge, i) => {
|
|
1619
|
+
for (const [part, text] of [["from", edge.from], ["spec", edge.specifier], ["to", edge.to]]) {
|
|
1620
|
+
const bytes = Buffer.from(text, "utf8");
|
|
1621
|
+
out.push(`@sc_npm_edge_${i}_${part} = internal constant [${bytes.length + 1} x i8] c"${llBytes(bytes)}"`);
|
|
1622
|
+
}
|
|
1623
|
+
});
|
|
1624
|
+
if (embedded.edges.length > 0) {
|
|
1625
|
+
const edgeRows = embedded.edges.map((edge, i) => `%ScrIslandEdge { ptr @sc_npm_edge_${i}_from, ptr @sc_npm_edge_${i}_spec, ` +
|
|
1626
|
+
`ptr @sc_npm_edge_${i}_to, i32 ${edgeKind[edge.kind]} }`);
|
|
1627
|
+
out.push(`@sc_npm_edges = internal constant [${edgeRows.length} x %ScrIslandEdge] [ ${edgeRows.join(", ")} ]`);
|
|
1628
|
+
}
|
|
1629
|
+
out.push(``);
|
|
1630
|
+
}
|
|
1631
|
+
out.push(...ffiCallbacks.globals);
|
|
1632
|
+
if (ffiCallbacks.globals.length > 0)
|
|
1633
|
+
out.push(``);
|
|
1305
1634
|
for (const g of globals) {
|
|
1306
1635
|
const ty = this.llType(g.type);
|
|
1307
1636
|
const zero = ty === "double" ? f64Lit(0) : ty === "ptr" ? "null" : "false";
|
|
1308
|
-
out.push(`@${mangleGlobal(g.id)} = internal global ${ty} ${zero} ; ${g.name}`);
|
|
1637
|
+
out.push(`@${mangleGlobal(g.id)} = internal ${tl}global ${ty} ${zero} ; ${g.name}`);
|
|
1309
1638
|
}
|
|
1310
1639
|
if (globals.length > 0)
|
|
1311
1640
|
out.push(``);
|
|
1312
1641
|
out.push(...helpers);
|
|
1642
|
+
out.push(...ffiCallbacks.defs);
|
|
1313
1643
|
out.push(...shapes.defs);
|
|
1314
1644
|
out.push(...classShapes.defs);
|
|
1315
1645
|
out.push(...classObjDefs);
|
|
@@ -1327,22 +1657,22 @@ class LlEmitter {
|
|
|
1327
1657
|
const stamps = [];
|
|
1328
1658
|
for (const iv of this.errorIntervals) {
|
|
1329
1659
|
for (const [field, value] of [[0, iv.pre], [1, iv.post]]) {
|
|
1330
|
-
stamps.push(` store
|
|
1660
|
+
stamps.push(` store ${this.sizeType} ${value}, ptr getelementptr inbounds ([5 x %ScrVt], ptr @scr_error_vts, i64 0, i64 ${iv.kind}, i32 ${field})${field === 1 ? ` ; ${iv.lib}` : ""}`);
|
|
1331
1661
|
}
|
|
1332
1662
|
}
|
|
1333
1663
|
if (this.emitterInterval !== null) {
|
|
1334
1664
|
// The runtime emitter vtable's interval (emitterVtStampLines): bare
|
|
1335
1665
|
// EventEmitter instances answer instanceof and dispatch dynamic
|
|
1336
1666
|
// teardown under THIS module's preorder numbering.
|
|
1337
|
-
out.push(`@scr_emitter_vt = external global %ScrVt`, ``);
|
|
1338
|
-
stamps.push(` store
|
|
1667
|
+
out.push(`@scr_emitter_vt = external ${tl}global %ScrVt`, ``);
|
|
1668
|
+
stamps.push(` store ${this.sizeType} ${this.emitterInterval.pre}, ptr getelementptr inbounds (%ScrVt, ptr @scr_emitter_vt, i64 0, i32 0)`, ` store ${this.sizeType} ${this.emitterInterval.post}, ptr getelementptr inbounds (%ScrVt, ptr @scr_emitter_vt, i64 0, i32 1) ; EventEmitter`);
|
|
1339
1669
|
}
|
|
1340
1670
|
for (const iv of this.streamIntervals) {
|
|
1341
1671
|
// The runtime stream vtables' intervals (streamVtStampLines) — the
|
|
1342
1672
|
// emitter story: instanceof and dynamic teardown dispatch through
|
|
1343
1673
|
// them.
|
|
1344
1674
|
out.push(`@${iv.vt} = external global %ScrVt`);
|
|
1345
|
-
stamps.push(` store
|
|
1675
|
+
stamps.push(` store ${this.sizeType} ${iv.pre}, ptr getelementptr inbounds (%ScrVt, ptr @${iv.vt}, i64 0, i32 0)`, ` store ${this.sizeType} ${iv.post}, ptr getelementptr inbounds (%ScrVt, ptr @${iv.vt}, i64 0, i32 1) ; ${iv.lib}`);
|
|
1346
1676
|
}
|
|
1347
1677
|
if (this.streamIntervals.length > 0)
|
|
1348
1678
|
out.push(``);
|
|
@@ -1366,17 +1696,28 @@ class LlEmitter {
|
|
|
1366
1696
|
// LIBRARY mode: no @main — the profile-declared external
|
|
1367
1697
|
// symbols instead, from the same IR facts the C emission consumes.
|
|
1368
1698
|
out.push(...this.emitLibDefs(globals, globalReleaseLines, stamps));
|
|
1369
|
-
out.push(`attributes #0 = { sanitize_address }
|
|
1699
|
+
out.push(`attributes #0 = { sanitize_address }`);
|
|
1700
|
+
if (this.wasi)
|
|
1701
|
+
out.push(`attributes #1 = { sanitize_address presplitcoroutine }`);
|
|
1702
|
+
out.push(``);
|
|
1370
1703
|
return out.join("\n");
|
|
1371
1704
|
}
|
|
1372
|
-
out.push(`define i32
|
|
1705
|
+
out.push(`define i32 @${this.wasi ? "__main_argc_argv" : "main"}(i32 %argc, ptr %argv) ${FN_ATTRS} {`, `entry:`, ` call void @scr_init()`, ...stamps,
|
|
1373
1706
|
// Event-surface programs (signal/exit listeners) fill the loop's
|
|
1374
1707
|
// nullable event hooks before %main — scr_events.c links only when
|
|
1375
1708
|
// this line is emitted (cc.ts gates on the same predicate).
|
|
1376
1709
|
...(usesEvents ? [` call void @scr_events_install()`] : []),
|
|
1377
1710
|
// fs.watch programs fill the loop's watch hooks the same way —
|
|
1378
1711
|
// scr_watch.c links only when this line is emitted.
|
|
1379
|
-
...(usesFsWatch ? [` call void @scr_watch_install()`] : []), ...(snapshotsTlsCa ? [` call void @scr_tls_ca_install()`] : []), ...(usesFetch ? [` call void @scr_fetch_install()`] : []), ...(usesNet ? [` call void @scr_net_install()`, ` call void @scr_net_dyn_install()`] : []), ...(usesHttp ? [` call void @scr_http_dyn_install()`] : []), ...(usesStream ? [` call void @scr_stream_install()`] : []), ` call void @scr_lib_init(i32 %argc, ptr %argv)`, ...(
|
|
1712
|
+
...(usesFsWatch ? [` call void @scr_watch_install()`] : []), ...(snapshotsTlsCa ? [` call void @scr_tls_ca_install()`] : []), ...(usesFetch ? [` call void @scr_fetch_install()`] : []), ...(embedsZlib ? [` call void @scr_zlib_island_install()`] : []), ...(embedsNet ? [` call void @scr_net_island_install()`] : []), ...(usesNet ? [` call void @scr_net_install()`, ` call void @scr_net_dyn_install()`] : []), ...(usesHttp ? [` call void @scr_http_dyn_install()`] : []), ...(usesStream ? [` call void @scr_stream_install()`] : []), ` call void @scr_lib_init(i32 %argc, ptr %argv)`, ...(usesIsland
|
|
1713
|
+
? [
|
|
1714
|
+
...(moduleEmbedsCompressedNpm(this.mod)
|
|
1715
|
+
? [` call void @scr_island_set_inflate(ptr @scr_zlib_inflate_exact)`]
|
|
1716
|
+
: []),
|
|
1717
|
+
` call void @scr_island_modules(ptr @sc_npm_modules, ${this.sizeType} ${embedded.modules.length}, ` +
|
|
1718
|
+
`ptr ${embedded.edges.length > 0 ? "@sc_npm_edges" : "null"}, ${this.sizeType} ${embedded.edges.length})`,
|
|
1719
|
+
]
|
|
1720
|
+
: []), ...(asyncEntry
|
|
1380
1721
|
? [` %top = call ptr @${mangleAsyncSpawn(this.mod.entry)}()`]
|
|
1381
1722
|
: [` call void @${mangleFunction(this.mod.entry)}()`]),
|
|
1382
1723
|
// Uncaught exception from top-level code: Node exits 1.
|
|
@@ -1447,18 +1788,20 @@ class LlEmitter {
|
|
|
1447
1788
|
` %tla_pending = icmp eq i32 %tla_status, 13`,
|
|
1448
1789
|
` br i1 %tla_pending, label %tla_stuck, label %tla_ok`,
|
|
1449
1790
|
`tla_stuck:`,
|
|
1450
|
-
...
|
|
1451
|
-
...topPendingReleases,
|
|
1452
|
-
` ret i32 13`,
|
|
1791
|
+
...topPendingExitLines(),
|
|
1453
1792
|
`tla_ok:`,
|
|
1454
1793
|
]
|
|
1455
1794
|
: []),
|
|
1456
1795
|
]
|
|
1457
|
-
: []), ...exitListenerLines("xn"), ...globalReleases,
|
|
1796
|
+
: []), ...exitListenerLines("xn"), ...globalReleases, ...(usesNodeTest
|
|
1797
|
+
? [` %test_exit = call i32 @scr_test_exit_code()`, ` ret i32 %test_exit`]
|
|
1798
|
+
: usesIsland
|
|
1799
|
+
? [` %island_exit = call i32 @scr_island_exit_code()`, ` ret i32 %island_exit`]
|
|
1800
|
+
: [` ret i32 0`]), `}`, ``,
|
|
1458
1801
|
// sanitize_address is inert under the plain pipeline; the sanitized
|
|
1459
1802
|
// lane's -fsanitize=address link activates instrumentation over the
|
|
1460
1803
|
// emitted functions too (the runtime TUs get theirs from clang).
|
|
1461
|
-
`attributes #0 = { sanitize_address }`, ``);
|
|
1804
|
+
`attributes #0 = { sanitize_address }`, ...(this.wasi ? [`attributes #1 = { sanitize_address presplitcoroutine }`] : []), ``);
|
|
1462
1805
|
return out.join("\n");
|
|
1463
1806
|
}
|
|
1464
1807
|
/** LIBRARY mode: the profile-declared external definitions — the
|
|
@@ -1510,7 +1853,7 @@ class LlEmitter {
|
|
|
1510
1853
|
});
|
|
1511
1854
|
out.push(ovlCells.length === 0
|
|
1512
1855
|
? `@scr_library_trap_overlays = constant [1 x ptr] zeroinitializer`
|
|
1513
|
-
: `@scr_library_trap_overlays = constant [${ovlCells.length} x ptr] [${ovlCells.join(", ")}]`, `@scr_library_trap_overlays_len = constant
|
|
1856
|
+
: `@scr_library_trap_overlays = constant [${ovlCells.length} x ptr] [${ovlCells.join(", ")}]`, `@scr_library_trap_overlays_len = constant ${this.sizeType} ${lib.trapOverlays.length}`, ``);
|
|
1514
1857
|
// The init entry: full deterministic reset-and-reevaluate. Program
|
|
1515
1858
|
// globals release and zero first (run-once guards included), then the
|
|
1516
1859
|
// runtime session reset, the error-vt interval stamps verbatim from
|
|
@@ -1596,13 +1939,13 @@ class LlEmitter {
|
|
|
1596
1939
|
args.push(`double %c${i}`);
|
|
1597
1940
|
break;
|
|
1598
1941
|
case "string":
|
|
1599
|
-
params.push(`ptr %a${i}_ptr`,
|
|
1600
|
-
body.push(` %c${i} = call ptr @scr_library_str_in(ptr %a${i}_ptr,
|
|
1942
|
+
params.push(`ptr %a${i}_ptr`, `${this.sizeType} %a${i}_len`);
|
|
1943
|
+
body.push(` %c${i} = call ptr @scr_library_str_in(ptr %a${i}_ptr, ${this.sizeType} %a${i}_len)`);
|
|
1601
1944
|
args.push(`ptr %c${i}`);
|
|
1602
1945
|
break;
|
|
1603
1946
|
case "bytes":
|
|
1604
|
-
params.push(`ptr %a${i}_ptr`,
|
|
1605
|
-
body.push(` %c${i} = call ptr @scr_library_bytes_in(ptr %a${i}_ptr,
|
|
1947
|
+
params.push(`ptr %a${i}_ptr`, `${this.sizeType} %a${i}_len`);
|
|
1948
|
+
body.push(` %c${i} = call ptr @scr_library_bytes_in(ptr %a${i}_ptr, ${this.sizeType} %a${i}_len, ptr @sc_lib_bytes_trap_${e.symbol})`);
|
|
1606
1949
|
args.push(`ptr %c${i}`);
|
|
1607
1950
|
break;
|
|
1608
1951
|
}
|
|
@@ -1676,7 +2019,7 @@ class LlEmitter {
|
|
|
1676
2019
|
// scr_box_retain is a static inline (increment-unless-immortal, then
|
|
1677
2020
|
// mark the cycle header live — every box is collector-headered);
|
|
1678
2021
|
// emitted once with internal linkage, like the record retains.
|
|
1679
|
-
defs.push(`define internal ptr @sc_retain_box(ptr %b) ${FN_ATTRS} {`, `entry:`, ` %rc = load
|
|
2022
|
+
defs.push(`define internal ptr @sc_retain_box(ptr %b) ${FN_ATTRS} {`, `entry:`, ` %rc = load ${this.sizeType}, ptr %b`, ` %imm = icmp eq ${this.sizeType} %rc, -1`, ` br i1 %imm, label %done, label %inc`, `inc:`, ` %n = add ${this.sizeType} %rc, 1`, ` store ${this.sizeType} %n, ptr %b`, ` %colorp = getelementptr i8, ptr %b, ${this.sizeType} -${this.cycleColorOffset}`, ` store i32 0, ptr %colorp ; mark live`, ` br label %done`, `done:`, ` ret ptr %b`, `}`, ``);
|
|
1680
2023
|
}
|
|
1681
2024
|
// The declarations these helpers added must land in the extern block,
|
|
1682
2025
|
// which already flushed — append here instead (LLVM is order-free).
|
|
@@ -1696,7 +2039,7 @@ class LlEmitter {
|
|
|
1696
2039
|
// never the inner return type.
|
|
1697
2040
|
const ret = fn.async === true || fn.generator !== undefined ? "ptr" : this.llType(fn.returnType);
|
|
1698
2041
|
const call = `call ${ret} @${this.callTarget(name)}(${args})`;
|
|
1699
|
-
out.push(`define internal ${ret} @${mangleWrapper(name)}(ptr %env${params.length ? ", " + params.join(", ") : ""}) ${FN_ATTRS} { ; ${name} as a value`, `entry:`, ret === "void" ? ` ${call}` : ` %r = ${call}`, ret === "void" ? ` ret void` : ` ret ${ret} %r`, `}`, `@${mangleFnClosure(name)} = internal global %ScrClosure {
|
|
2042
|
+
out.push(`define internal ${ret} @${mangleWrapper(name)}(ptr %env${params.length ? ", " + params.join(", ") : ""}) ${FN_ATTRS} { ; ${name} as a value`, `entry:`, ret === "void" ? ` ${call}` : ` %r = ${call}`, ret === "void" ? ` ret void` : ` ret ${ret} %r`, `}`, `@${mangleFnClosure(name)} = internal global %ScrClosure { ${this.sizeType} -1, ptr @${mangleWrapper(name)}, ${this.sizeType} 0, ptr null }`, ``);
|
|
1700
2043
|
}
|
|
1701
2044
|
return out;
|
|
1702
2045
|
}
|
|
@@ -1709,6 +2052,11 @@ class LlEmitter {
|
|
|
1709
2052
|
* fiber eagerly to its first suspension and returns the promise). */
|
|
1710
2053
|
emitAsyncScaffolding() {
|
|
1711
2054
|
const out = [];
|
|
2055
|
+
if (this.wasi) {
|
|
2056
|
+
this.declare(`declare void @llvm.coro.resume(ptr)`);
|
|
2057
|
+
this.declare(`declare void @llvm.coro.destroy(ptr)`);
|
|
2058
|
+
out.push(`define void @scr_wasi_coro_resume(ptr %handle) ${FN_ATTRS} {`, `entry:`, ` call void @llvm.coro.resume(ptr %handle)`, ` ret void`, `}`, `define void @scr_wasi_coro_destroy(ptr %handle) ${FN_ATTRS} {`, `entry:`, ` call void @llvm.coro.destroy(ptr %handle)`, ` ret void`, `}`, ``);
|
|
2059
|
+
}
|
|
1712
2060
|
for (const fn of this.mod.functions) {
|
|
1713
2061
|
if (fn.async !== true)
|
|
1714
2062
|
continue;
|
|
@@ -1716,9 +2064,9 @@ class LlEmitter {
|
|
|
1716
2064
|
const lifted = fn.captures !== undefined;
|
|
1717
2065
|
const fieldTys = [...(lifted ? ["ptr"] : []), ...fn.params.map((p) => this.llType(p.type))];
|
|
1718
2066
|
out.push(`%${pack} = type { ${fieldTys.join(", ") || "i8"} } ; ${fn.name} args`);
|
|
1719
|
-
const sizeOf = `ptrtoint (ptr getelementptr (%${pack}, ptr null, i32 1) to
|
|
2067
|
+
const sizeOf = `ptrtoint (ptr getelementptr (%${pack}, ptr null, i32 1) to ${this.sizeType})`;
|
|
1720
2068
|
this.declare(`declare void @free(ptr)`);
|
|
1721
|
-
this.declare(`declare ptr @malloc(
|
|
2069
|
+
this.declare(`declare ptr @malloc(${this.sizeType})`);
|
|
1722
2070
|
this.declare(`declare zeroext i1 @scr_exc_pending()`);
|
|
1723
2071
|
this.declare(`declare ptr @scr_fiber_promise(ptr)`);
|
|
1724
2072
|
this.declare(`declare ptr @scr_async_spawn(ptr, ptr)`);
|
|
@@ -1738,41 +2086,49 @@ class LlEmitter {
|
|
|
1738
2086
|
const retTy = this.llType(ret);
|
|
1739
2087
|
const bodyCall = `call ${retTy} @${mangleFunction(fn.name)}(${loads.join(", ")})`;
|
|
1740
2088
|
tr.push(retTy === "void" ? ` ${bodyCall}` : ` %r = ${bodyCall}`);
|
|
1741
|
-
if (
|
|
1742
|
-
|
|
1743
|
-
|
|
2089
|
+
if (this.wasi) {
|
|
2090
|
+
// The coroutine body settles its own promise and owns the retained
|
|
2091
|
+
// lifted environment until final suspension. Its initial call
|
|
2092
|
+
// returns here at the first suspend (or final suspend).
|
|
2093
|
+
tr.push(` ret void`, `}`, ``);
|
|
1744
2094
|
}
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
tr.push(` call void @scr_promise_fulfill_void(ptr %pr)`);
|
|
1750
|
-
break;
|
|
1751
|
-
case "f64":
|
|
1752
|
-
case "date":
|
|
1753
|
-
this.declare(`declare void @scr_promise_fulfill_f64(ptr, double)`);
|
|
1754
|
-
tr.push(` call void @scr_promise_fulfill_f64(ptr %pr, double %r)`);
|
|
1755
|
-
break;
|
|
1756
|
-
case "bool":
|
|
1757
|
-
this.declare(`declare void @scr_promise_fulfill_bool(ptr, i1 zeroext)`);
|
|
1758
|
-
tr.push(` call void @scr_promise_fulfill_bool(ptr %pr, i1 %r)`);
|
|
1759
|
-
break;
|
|
1760
|
-
case "string":
|
|
1761
|
-
this.declare(`declare void @scr_promise_fulfill_str(ptr, ptr)`);
|
|
1762
|
-
tr.push(` call void @scr_promise_fulfill_str(ptr %pr, ptr %r) ; moves in`);
|
|
1763
|
-
break;
|
|
1764
|
-
default: {
|
|
1765
|
-
const v = vAdapters(this, ret);
|
|
1766
|
-
this.declare(`declare void @scr_promise_fulfill_ref(ptr, ptr, ptr, ptr, ptr)`);
|
|
1767
|
-
tr.push(` call void @scr_promise_fulfill_ref(ptr %pr, ptr %r, ptr ${v.retain}, ptr ${v.release}, ptr ${traceArg(this, ret)})`);
|
|
2095
|
+
else {
|
|
2096
|
+
if (lifted) {
|
|
2097
|
+
this.declare(`declare void @scr_closure_release(ptr)`);
|
|
2098
|
+
tr.push(` call void @scr_closure_release(ptr %a0)`);
|
|
1768
2099
|
}
|
|
2100
|
+
tr.push(` %pend = call zeroext i1 @scr_exc_pending()`, ` br i1 %pend, label %thrown, label %clean`, `clean:`, ` %pr = call ptr @scr_fiber_promise(ptr %self)`);
|
|
2101
|
+
switch (ret.kind) {
|
|
2102
|
+
case "void":
|
|
2103
|
+
this.declare(`declare void @scr_promise_fulfill_void(ptr)`);
|
|
2104
|
+
tr.push(` call void @scr_promise_fulfill_void(ptr %pr)`);
|
|
2105
|
+
break;
|
|
2106
|
+
case "f64":
|
|
2107
|
+
case "date":
|
|
2108
|
+
this.declare(`declare void @scr_promise_fulfill_f64(ptr, double)`);
|
|
2109
|
+
tr.push(` call void @scr_promise_fulfill_f64(ptr %pr, double %r)`);
|
|
2110
|
+
break;
|
|
2111
|
+
case "bool":
|
|
2112
|
+
this.declare(`declare void @scr_promise_fulfill_bool(ptr, i1 zeroext)`);
|
|
2113
|
+
tr.push(` call void @scr_promise_fulfill_bool(ptr %pr, i1 %r)`);
|
|
2114
|
+
break;
|
|
2115
|
+
case "string":
|
|
2116
|
+
this.declare(`declare void @scr_promise_fulfill_str(ptr, ptr)`);
|
|
2117
|
+
tr.push(` call void @scr_promise_fulfill_str(ptr %pr, ptr %r) ; moves in`);
|
|
2118
|
+
break;
|
|
2119
|
+
default: {
|
|
2120
|
+
const v = vAdapters(this, ret);
|
|
2121
|
+
this.declare(`declare void @scr_promise_fulfill_ref(ptr, ptr, ptr, ptr, ptr)`);
|
|
2122
|
+
tr.push(` call void @scr_promise_fulfill_ref(ptr %pr, ptr %r, ptr ${v.retain}, ptr ${v.release}, ptr ${traceArg(this, ret)})`);
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
tr.push(` ret void`, `thrown:`);
|
|
2126
|
+
if (ret.kind !== "void" && isRefCounted(ret)) {
|
|
2127
|
+
// An escaping throw means %r is the never-read dummy (NULL).
|
|
2128
|
+
tr.push(` call void ${releaseSym(this, ret)}(ptr %r)`);
|
|
2129
|
+
}
|
|
2130
|
+
tr.push(` ret void`, `}`, ``);
|
|
1769
2131
|
}
|
|
1770
|
-
tr.push(` ret void`, `thrown:`);
|
|
1771
|
-
if (ret.kind !== "void" && isRefCounted(ret)) {
|
|
1772
|
-
// An escaping throw means %r is the never-read dummy (NULL).
|
|
1773
|
-
tr.push(` call void ${releaseSym(this, ret)}(ptr %r)`);
|
|
1774
|
-
}
|
|
1775
|
-
tr.push(` ret void`, `}`, ``);
|
|
1776
2132
|
out.push(...tr);
|
|
1777
2133
|
// Spawn wrapper: pack the args (+1 moves in), spawn the fiber.
|
|
1778
2134
|
const params = fieldTys.map((ty, i) => `${ty} %a${i}`);
|
|
@@ -1799,7 +2155,7 @@ class LlEmitter {
|
|
|
1799
2155
|
`cache_miss:`,
|
|
1800
2156
|
]
|
|
1801
2157
|
: []),
|
|
1802
|
-
` %ap = call ptr @malloc(
|
|
2158
|
+
` %ap = call ptr @malloc(${this.sizeType} ${sizeOf})`,
|
|
1803
2159
|
` %isnull = icmp eq ptr %ap, null`,
|
|
1804
2160
|
` br i1 %isnull, label %oom, label %ok`,
|
|
1805
2161
|
`oom:`,
|
|
@@ -1867,9 +2223,9 @@ class LlEmitter {
|
|
|
1867
2223
|
const lifted = fn.captures !== undefined;
|
|
1868
2224
|
const fieldTys = [...(lifted ? ["ptr"] : []), ...fn.params.map((p) => this.llType(p.type))];
|
|
1869
2225
|
out.push(`%${pack} = type { ${fieldTys.join(", ") || "i8"} } ; ${fn.name} args`);
|
|
1870
|
-
const sizeOf = `ptrtoint (ptr getelementptr (%${pack}, ptr null, i32 1) to
|
|
2226
|
+
const sizeOf = `ptrtoint (ptr getelementptr (%${pack}, ptr null, i32 1) to ${this.sizeType})`;
|
|
1871
2227
|
this.declare(`declare void @free(ptr)`);
|
|
1872
|
-
this.declare(`declare ptr @malloc(
|
|
2228
|
+
this.declare(`declare ptr @malloc(${this.sizeType})`);
|
|
1873
2229
|
this.declare(`declare zeroext i1 @scr_exc_pending()`);
|
|
1874
2230
|
this.declare(`declare zeroext i1 @scr_exc_genret_pending()`);
|
|
1875
2231
|
this.declare(`declare void @scr_exc_clear()`);
|
|
@@ -1891,7 +2247,7 @@ class LlEmitter {
|
|
|
1891
2247
|
const retTy = this.llType(ret);
|
|
1892
2248
|
const bodyCall = `call ${retTy} @${mangleFunction(fn.name)}(${loads.join(", ")})`;
|
|
1893
2249
|
tr.push(retTy === "void" ? ` ${bodyCall}` : ` %r = ${bodyCall}`);
|
|
1894
|
-
if (lifted) {
|
|
2250
|
+
if (lifted && !this.wasi) {
|
|
1895
2251
|
this.declare(`declare void @scr_closure_release(ptr)`);
|
|
1896
2252
|
tr.push(` call void @scr_closure_release(ptr %a0)`);
|
|
1897
2253
|
}
|
|
@@ -1899,31 +2255,36 @@ class LlEmitter {
|
|
|
1899
2255
|
// with the NONE slot — JS's undefined done-value. A GENRET unwind
|
|
1900
2256
|
// consumes the sentinel and promotes the parked .return value; a
|
|
1901
2257
|
// real exception stays pending (the consumer-side resume moves it).
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
case "void":
|
|
1905
|
-
tr.push(` br label %done ; void body: the done value is undefined (NONE)`);
|
|
1906
|
-
break;
|
|
1907
|
-
case "f64":
|
|
1908
|
-
case "date":
|
|
1909
|
-
this.declare(`declare void @scr_gen_out_f64(ptr, double)`);
|
|
1910
|
-
tr.push(` call void @scr_gen_out_f64(ptr %g, double %r)`, ` br label %done`);
|
|
1911
|
-
break;
|
|
1912
|
-
case "bool":
|
|
1913
|
-
this.declare(`declare void @scr_gen_out_bool(ptr, i1 zeroext)`);
|
|
1914
|
-
tr.push(` call void @scr_gen_out_bool(ptr %g, i1 %r)`, ` br label %done`);
|
|
1915
|
-
break;
|
|
1916
|
-
default: {
|
|
1917
|
-
const v = vAdapters(this, ret);
|
|
1918
|
-
this.declare(`declare void @scr_gen_out_ref(ptr, ptr, ptr)`);
|
|
1919
|
-
tr.push(` call void @scr_gen_out_ref(ptr %g, ptr %r, ptr ${v.release})`, ` br label %done`);
|
|
1920
|
-
}
|
|
2258
|
+
if (this.wasi) {
|
|
2259
|
+
tr.push(` ret void`, `}`, ``);
|
|
1921
2260
|
}
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2261
|
+
else {
|
|
2262
|
+
tr.push(` %g = call ptr @scr_gen_of_fiber(ptr %self)`, ` %pend = call zeroext i1 @scr_exc_pending()`, ` br i1 %pend, label %thrown, label %clean`, `clean:`);
|
|
2263
|
+
switch (ret.kind) {
|
|
2264
|
+
case "void":
|
|
2265
|
+
tr.push(` br label %done ; void body: the done value is undefined (NONE)`);
|
|
2266
|
+
break;
|
|
2267
|
+
case "f64":
|
|
2268
|
+
case "date":
|
|
2269
|
+
this.declare(`declare void @scr_gen_out_f64(ptr, double)`);
|
|
2270
|
+
tr.push(` call void @scr_gen_out_f64(ptr %g, double %r)`, ` br label %done`);
|
|
2271
|
+
break;
|
|
2272
|
+
case "bool":
|
|
2273
|
+
this.declare(`declare void @scr_gen_out_bool(ptr, i1 zeroext)`);
|
|
2274
|
+
tr.push(` call void @scr_gen_out_bool(ptr %g, i1 %r)`, ` br label %done`);
|
|
2275
|
+
break;
|
|
2276
|
+
default: {
|
|
2277
|
+
const v = vAdapters(this, ret);
|
|
2278
|
+
this.declare(`declare void @scr_gen_out_ref(ptr, ptr, ptr)`);
|
|
2279
|
+
tr.push(` call void @scr_gen_out_ref(ptr %g, ptr %r, ptr ${v.release})`, ` br label %done`);
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
tr.push(`thrown:`, ` %genret = call zeroext i1 @scr_exc_genret_pending()`, ` br i1 %genret, label %promote, label %dropdummy`, `promote:`, ` call void @scr_exc_clear()`, ` call void @scr_gen_ret_to_out(ptr %g)`, ` br label %dropdummy`, `dropdummy:`);
|
|
2283
|
+
if (ret.kind !== "void" && isRefCounted(ret)) {
|
|
2284
|
+
tr.push(` call void ${releaseSym(this, ret)}(ptr %r) ; unwound: the never-read dummy`);
|
|
2285
|
+
}
|
|
2286
|
+
tr.push(` br label %done`, `done:`, ` ret void`, `}`, ``);
|
|
1925
2287
|
}
|
|
1926
|
-
tr.push(` br label %done`, `done:`, ` ret void`, `}`, ``);
|
|
1927
2288
|
out.push(...tr);
|
|
1928
2289
|
// The never-started teardown: drop the packed (+1) arguments.
|
|
1929
2290
|
const dr = [
|
|
@@ -1952,7 +2313,7 @@ class LlEmitter {
|
|
|
1952
2313
|
const sp = [
|
|
1953
2314
|
`define internal ptr @${mangleGenSpawn(fn.name)}(${params.join(", ")}) ${FN_ATTRS} { ; gen spawn ${fn.name}`,
|
|
1954
2315
|
`entry:`,
|
|
1955
|
-
` %ap = call ptr @malloc(
|
|
2316
|
+
` %ap = call ptr @malloc(${this.sizeType} ${sizeOf})`,
|
|
1956
2317
|
` %isnull = icmp eq ptr %ap, null`,
|
|
1957
2318
|
` br i1 %isnull, label %oom, label %ok`,
|
|
1958
2319
|
`oom:`,
|
|
@@ -2124,6 +2485,10 @@ class LlEmitter {
|
|
|
2124
2485
|
return;
|
|
2125
2486
|
}
|
|
2126
2487
|
this.releaseForJump(0, 0);
|
|
2488
|
+
if (this.currentWasiCoro !== null) {
|
|
2489
|
+
this.B.terminate(`br label %${this.currentWasiCoro.finalLabel}`);
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2127
2492
|
const t = this.currentReturnType;
|
|
2128
2493
|
if (t.kind === "void")
|
|
2129
2494
|
this.B.terminate("ret void");
|
|
@@ -2207,8 +2572,8 @@ class LlEmitter {
|
|
|
2207
2572
|
const len = B.tmp();
|
|
2208
2573
|
const t = B.tmp();
|
|
2209
2574
|
B.line(`${lenp} = getelementptr inbounds %ScrStr, ptr ${v.name}, i64 0, i32 1`);
|
|
2210
|
-
B.line(`${len} = load
|
|
2211
|
-
B.line(`${t} = icmp ne
|
|
2575
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenp}`);
|
|
2576
|
+
B.line(`${t} = icmp ne ${this.sizeType} ${len}, 0`);
|
|
2212
2577
|
return t;
|
|
2213
2578
|
}
|
|
2214
2579
|
case "date":
|
|
@@ -2303,8 +2668,8 @@ class LlEmitter {
|
|
|
2303
2668
|
const len = B.tmp();
|
|
2304
2669
|
const t = B.tmp();
|
|
2305
2670
|
B.line(`${lenp} = getelementptr inbounds %ScrStr, ptr ${p}, i64 0, i32 1`);
|
|
2306
|
-
B.line(`${len} = load
|
|
2307
|
-
B.line(`${t} = icmp ne
|
|
2671
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenp}`);
|
|
2672
|
+
B.line(`${t} = icmp ne ${this.sizeType} ${len}, 0`);
|
|
2308
2673
|
B.line(`store i1 ${t}, ptr ${slot}`);
|
|
2309
2674
|
break;
|
|
2310
2675
|
}
|
|
@@ -2459,7 +2824,7 @@ class LlEmitter {
|
|
|
2459
2824
|
B.line(`${vtp} = getelementptr inbounds %${classStructSym(staticClassName)}, ptr ${objName}, i64 0, i32 1`);
|
|
2460
2825
|
B.line(`${vt} = load ptr, ptr ${vtp}`);
|
|
2461
2826
|
B.line(`${prep} = getelementptr inbounds %ScrVt, ptr ${vt}, i64 0, i32 0`);
|
|
2462
|
-
B.line(`${pre} = load
|
|
2827
|
+
B.line(`${pre} = load ${this.sizeType}, ptr ${prep}`);
|
|
2463
2828
|
return pre;
|
|
2464
2829
|
}
|
|
2465
2830
|
/** The class object's static symbol (classes as values), registering it
|
|
@@ -2652,6 +3017,93 @@ class LlEmitter {
|
|
|
2652
3017
|
return mangleGenSpawn(fnName);
|
|
2653
3018
|
return mangleFunction(fnName);
|
|
2654
3019
|
}
|
|
3020
|
+
/** Queue the current wasm coroutine and suspend it. The runtime decides
|
|
3021
|
+
* whether the promise waiter list or the ready FIFO owns the continuation;
|
|
3022
|
+
* LLVM keeps all live locals in the coroutine frame. */
|
|
3023
|
+
emitWasiSuspend(promise) {
|
|
3024
|
+
const coro = this.currentWasiCoro;
|
|
3025
|
+
if (coro === null)
|
|
3026
|
+
throw new Error("llvm emitter bug: wasm suspension outside async body");
|
|
3027
|
+
if (promise === null) {
|
|
3028
|
+
this.declare(`declare void @scr_wasi_await_hop_prepare(ptr)`);
|
|
3029
|
+
this.B.line(`call void @scr_wasi_await_hop_prepare(ptr ${coro.self})`);
|
|
3030
|
+
}
|
|
3031
|
+
else {
|
|
3032
|
+
this.declare(`declare void @scr_wasi_await_prepare(ptr, ptr)`);
|
|
3033
|
+
this.B.line(`call void @scr_wasi_await_prepare(ptr ${coro.self}, ptr ${promise})`);
|
|
3034
|
+
}
|
|
3035
|
+
this.emitWasiSuspendPrepared();
|
|
3036
|
+
}
|
|
3037
|
+
/** Suspend after a target-specific runtime helper already queued the
|
|
3038
|
+
* continuation (used by module awaits, which skip the hop when settled). */
|
|
3039
|
+
emitWasiSuspendPrepared() {
|
|
3040
|
+
const coro = this.currentWasiCoro;
|
|
3041
|
+
if (coro === null)
|
|
3042
|
+
throw new Error("llvm emitter bug: wasm suspension outside async body");
|
|
3043
|
+
const save = this.B.tmp();
|
|
3044
|
+
const state = this.B.tmp();
|
|
3045
|
+
const resume = this.B.newLabel("coro.resume");
|
|
3046
|
+
this.B.line(`${save} = call token @llvm.coro.save(ptr ${coro.handle})`);
|
|
3047
|
+
this.B.line(`${state} = call i8 @llvm.coro.suspend(token ${save}, i1 false)`);
|
|
3048
|
+
this.B.terminate(`switch i8 ${state}, label %${coro.suspendLabel} [ i8 0, label %${resume} i8 1, label %${coro.cleanupLabel} ]`);
|
|
3049
|
+
this.B.startBlock(resume);
|
|
3050
|
+
}
|
|
3051
|
+
/** Move a clean async return value into the current fiber's promise. */
|
|
3052
|
+
emitWasiFulfill(v) {
|
|
3053
|
+
const coro = this.currentWasiCoro;
|
|
3054
|
+
if (coro === null)
|
|
3055
|
+
throw new Error("llvm emitter bug: wasm fulfillment outside async body");
|
|
3056
|
+
const ret = this.currentReturnType;
|
|
3057
|
+
if (coro.kind === "generator") {
|
|
3058
|
+
this.declare(`declare ptr @scr_gen_of_fiber(ptr)`);
|
|
3059
|
+
const gen = this.B.tmp();
|
|
3060
|
+
this.B.line(`${gen} = call ptr @scr_gen_of_fiber(ptr ${coro.self})`);
|
|
3061
|
+
switch (ret.kind) {
|
|
3062
|
+
case "void":
|
|
3063
|
+
return;
|
|
3064
|
+
case "f64":
|
|
3065
|
+
case "date":
|
|
3066
|
+
this.declare(`declare void @scr_gen_out_f64(ptr, double)`);
|
|
3067
|
+
this.B.line(`call void @scr_gen_out_f64(ptr ${gen}, double ${v.name})`);
|
|
3068
|
+
return;
|
|
3069
|
+
case "bool":
|
|
3070
|
+
this.declare(`declare void @scr_gen_out_bool(ptr, i1 zeroext)`);
|
|
3071
|
+
this.B.line(`call void @scr_gen_out_bool(ptr ${gen}, i1 ${v.name})`);
|
|
3072
|
+
return;
|
|
3073
|
+
default:
|
|
3074
|
+
this.declare(`declare void @scr_gen_out_ref(ptr, ptr, ptr)`);
|
|
3075
|
+
this.B.line(`call void @scr_gen_out_ref(ptr ${gen}, ptr ${v.name}, ptr ${vAdapters(this, ret).release})`);
|
|
3076
|
+
return;
|
|
3077
|
+
}
|
|
3078
|
+
}
|
|
3079
|
+
this.declare(`declare ptr @scr_fiber_promise(ptr)`);
|
|
3080
|
+
const pr = this.B.tmp();
|
|
3081
|
+
this.B.line(`${pr} = call ptr @scr_fiber_promise(ptr ${coro.self})`);
|
|
3082
|
+
switch (ret.kind) {
|
|
3083
|
+
case "void":
|
|
3084
|
+
this.declare(`declare void @scr_promise_fulfill_void(ptr)`);
|
|
3085
|
+
this.B.line(`call void @scr_promise_fulfill_void(ptr ${pr})`);
|
|
3086
|
+
break;
|
|
3087
|
+
case "f64":
|
|
3088
|
+
case "date":
|
|
3089
|
+
this.declare(`declare void @scr_promise_fulfill_f64(ptr, double)`);
|
|
3090
|
+
this.B.line(`call void @scr_promise_fulfill_f64(ptr ${pr}, double ${v.name})`);
|
|
3091
|
+
break;
|
|
3092
|
+
case "bool":
|
|
3093
|
+
this.declare(`declare void @scr_promise_fulfill_bool(ptr, i1 zeroext)`);
|
|
3094
|
+
this.B.line(`call void @scr_promise_fulfill_bool(ptr ${pr}, i1 ${v.name})`);
|
|
3095
|
+
break;
|
|
3096
|
+
case "string":
|
|
3097
|
+
this.declare(`declare void @scr_promise_fulfill_str(ptr, ptr)`);
|
|
3098
|
+
this.B.line(`call void @scr_promise_fulfill_str(ptr ${pr}, ptr ${v.name}) ; moves in`);
|
|
3099
|
+
break;
|
|
3100
|
+
default: {
|
|
3101
|
+
const rc = vAdapters(this, ret);
|
|
3102
|
+
this.declare(`declare void @scr_promise_fulfill_ref(ptr, ptr, ptr, ptr, ptr)`);
|
|
3103
|
+
this.B.line(`call void @scr_promise_fulfill_ref(ptr ${pr}, ptr ${v.name}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${traceArg(this, ret)})`);
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
2655
3107
|
emitFunction(fn) {
|
|
2656
3108
|
const B = new BlockBuilder();
|
|
2657
3109
|
this.B = B;
|
|
@@ -2666,7 +3118,41 @@ class LlEmitter {
|
|
|
2666
3118
|
this.tryStack = [];
|
|
2667
3119
|
this.currentReturnType = fn.returnType;
|
|
2668
3120
|
this.currentGenerator = fn.generator ?? null;
|
|
3121
|
+
this.currentWasiCoro = null;
|
|
2669
3122
|
this.logArgSlots = 0;
|
|
3123
|
+
if (this.wasi && (fn.async === true || fn.generator !== undefined)) {
|
|
3124
|
+
this.declare(`declare token @llvm.coro.id(i32, ptr, ptr, ptr)`);
|
|
3125
|
+
this.declare(`declare ${this.sizeType} @llvm.coro.size.${this.sizeType}()`);
|
|
3126
|
+
this.declare(`declare ptr @llvm.coro.begin(token, ptr)`);
|
|
3127
|
+
this.declare(`declare token @llvm.coro.save(ptr)`);
|
|
3128
|
+
this.declare(`declare i8 @llvm.coro.suspend(token, i1)`);
|
|
3129
|
+
this.declare(`declare ptr @llvm.coro.free(token, ptr)`);
|
|
3130
|
+
this.declare(`declare i1 @llvm.coro.end(ptr, i1, token)`);
|
|
3131
|
+
this.declare(`declare ptr @malloc(${this.sizeType})`);
|
|
3132
|
+
this.declare(`declare void @free(ptr)`);
|
|
3133
|
+
this.declare(`declare void @scr_wasi_coro_started(ptr)`);
|
|
3134
|
+
this.declare(`declare ptr @scr_fiber_self()`);
|
|
3135
|
+
const id = B.tmp();
|
|
3136
|
+
const size = B.tmp();
|
|
3137
|
+
const mem = B.tmp();
|
|
3138
|
+
const handle = B.tmp();
|
|
3139
|
+
const self = B.tmp();
|
|
3140
|
+
B.line(`${id} = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)`);
|
|
3141
|
+
B.line(`${size} = call ${this.sizeType} @llvm.coro.size.${this.sizeType}()`);
|
|
3142
|
+
B.line(`${mem} = call ptr @malloc(${this.sizeType} ${size})`);
|
|
3143
|
+
B.line(`${handle} = call ptr @llvm.coro.begin(token ${id}, ptr ${mem})`);
|
|
3144
|
+
B.line(`call void @scr_wasi_coro_started(ptr ${handle})`);
|
|
3145
|
+
B.line(`${self} = call ptr @scr_fiber_self()`);
|
|
3146
|
+
this.currentWasiCoro = {
|
|
3147
|
+
kind: fn.async === true ? "async" : "generator",
|
|
3148
|
+
id,
|
|
3149
|
+
handle,
|
|
3150
|
+
self,
|
|
3151
|
+
finalLabel: B.newLabel("coro.final"),
|
|
3152
|
+
cleanupLabel: B.newLabel("coro.cleanup"),
|
|
3153
|
+
suspendLabel: B.newLabel("coro.suspend"),
|
|
3154
|
+
};
|
|
3155
|
+
}
|
|
2670
3156
|
const paramIds = new Set(fn.params.map((p) => p.localId));
|
|
2671
3157
|
for (const local of fn.locals) {
|
|
2672
3158
|
// Boxed locals' slots hold their capture BOX (a ptr); captured
|
|
@@ -2688,9 +3174,11 @@ class LlEmitter {
|
|
|
2688
3174
|
// Captured bindings come in through the environment — borrowed for the
|
|
2689
3175
|
// whole call (the closure owns them): bound here, never released here.
|
|
2690
3176
|
(fn.captures ?? []).forEach((c, i) => {
|
|
3177
|
+
const caps = B.tmp();
|
|
2691
3178
|
const p = B.tmp();
|
|
2692
3179
|
const box = B.tmp();
|
|
2693
|
-
B.line(`${
|
|
3180
|
+
B.line(`${caps} = getelementptr inbounds %ScrClosure, ptr %sc_env, i64 1 ; caps`);
|
|
3181
|
+
B.line(`${p} = getelementptr inbounds ptr, ptr ${caps}, ${this.sizeType} ${i} ; caps[${i}]`);
|
|
2694
3182
|
B.line(`${box} = load ptr, ptr ${p}`);
|
|
2695
3183
|
B.line(`store ptr ${box}, ptr %${mangleLocal(c.localId)} ; captured ${c.name}`);
|
|
2696
3184
|
});
|
|
@@ -2720,9 +3208,51 @@ class LlEmitter {
|
|
|
2720
3208
|
// whose unwind released everything down to depth 0).
|
|
2721
3209
|
if (fn.returnType.kind === "void" && !B.isTerminated()) {
|
|
2722
3210
|
this.releaseScope(this.scopes[0]);
|
|
2723
|
-
|
|
3211
|
+
if (this.currentWasiCoro !== null) {
|
|
3212
|
+
this.emitWasiFulfill(null);
|
|
3213
|
+
B.terminate(`br label %${this.currentWasiCoro.finalLabel}`);
|
|
3214
|
+
}
|
|
3215
|
+
else {
|
|
3216
|
+
B.terminate("ret void");
|
|
3217
|
+
}
|
|
2724
3218
|
}
|
|
2725
3219
|
this.scopes.pop();
|
|
3220
|
+
const coro = this.currentWasiCoro;
|
|
3221
|
+
if (coro !== null) {
|
|
3222
|
+
B.startBlock(coro.finalLabel);
|
|
3223
|
+
if (fn.captures !== undefined) {
|
|
3224
|
+
this.declare(`declare void @scr_closure_release(ptr)`);
|
|
3225
|
+
B.line(`call void @scr_closure_release(ptr %sc_env)`);
|
|
3226
|
+
}
|
|
3227
|
+
if (coro.kind === "generator") {
|
|
3228
|
+
this.declare(`declare void @scr_wasi_gen_finish(ptr)`);
|
|
3229
|
+
B.line(`call void @scr_wasi_gen_finish(ptr ${coro.self})`);
|
|
3230
|
+
}
|
|
3231
|
+
else {
|
|
3232
|
+
this.declare(`declare void @scr_wasi_async_finish(ptr)`);
|
|
3233
|
+
B.line(`call void @scr_wasi_async_finish(ptr ${coro.self})`);
|
|
3234
|
+
}
|
|
3235
|
+
const finalState = B.tmp();
|
|
3236
|
+
B.line(`${finalState} = call i8 @llvm.coro.suspend(token none, i1 true)`);
|
|
3237
|
+
B.terminate(`switch i8 ${finalState}, label %${coro.suspendLabel} [ i8 1, label %${coro.cleanupLabel} ]`);
|
|
3238
|
+
B.startBlock(coro.cleanupLabel);
|
|
3239
|
+
const frame = B.tmp();
|
|
3240
|
+
B.line(`${frame} = call ptr @llvm.coro.free(token ${coro.id}, ptr ${coro.handle})`);
|
|
3241
|
+
B.line(`call void @free(ptr ${frame})`);
|
|
3242
|
+
B.br(coro.suspendLabel);
|
|
3243
|
+
B.startBlock(coro.suspendLabel);
|
|
3244
|
+
const ended = B.tmp();
|
|
3245
|
+
B.line(`${ended} = call i1 @llvm.coro.end(ptr ${coro.handle}, i1 false, token none)`);
|
|
3246
|
+
const ret = this.llType(fn.returnType);
|
|
3247
|
+
if (ret === "void")
|
|
3248
|
+
B.terminate(`ret void`);
|
|
3249
|
+
else if (ret === "double")
|
|
3250
|
+
B.terminate(`ret double ${f64Lit(0)}`);
|
|
3251
|
+
else if (ret === "i1")
|
|
3252
|
+
B.terminate(`ret i1 false`);
|
|
3253
|
+
else
|
|
3254
|
+
B.terminate(`ret ptr null`);
|
|
3255
|
+
}
|
|
2726
3256
|
if (this.logArgSlots > 0) {
|
|
2727
3257
|
B.entryAllocas.push(`%logargs = alloca [${this.logArgSlots} x %ScrLogArg]`);
|
|
2728
3258
|
}
|
|
@@ -2731,7 +3261,8 @@ class LlEmitter {
|
|
|
2731
3261
|
if (fn.captures !== undefined)
|
|
2732
3262
|
params.unshift("ptr %sc_env");
|
|
2733
3263
|
const ret = this.llType(fn.returnType);
|
|
2734
|
-
|
|
3264
|
+
const attrs = coro !== null ? "#1" : FN_ATTRS;
|
|
3265
|
+
return `define internal ${ret} @${mangleFunction(fn.name)}(${params.join(", ")}) ${attrs} { ; ${fn.name}\n${B.render()}\n}`;
|
|
2735
3266
|
}
|
|
2736
3267
|
// ── statements ──────────────────────────────────────────────────────────
|
|
2737
3268
|
emitStmts(stmts) {
|
|
@@ -2960,7 +3491,7 @@ class LlEmitter {
|
|
|
2960
3491
|
B.line(`${kp} = getelementptr inbounds %ScrDynPath, ptr ${pathSlot}, i64 0, i32 1`);
|
|
2961
3492
|
B.line(`store ptr ${this.cstr(f.name)}, ptr ${kp}`);
|
|
2962
3493
|
B.line(`${ip} = getelementptr inbounds %ScrDynPath, ptr ${pathSlot}, i64 0, i32 2`);
|
|
2963
|
-
B.line(`store
|
|
3494
|
+
B.line(`store ${this.sizeType} 0, ptr ${ip}`);
|
|
2964
3495
|
const helper = this.dyn.dynCheckHelper(f.type);
|
|
2965
3496
|
const fty = this.llType(f.type);
|
|
2966
3497
|
const nv = B.tmp();
|
|
@@ -3129,8 +3660,8 @@ class LlEmitter {
|
|
|
3129
3660
|
let integerSlot = null;
|
|
3130
3661
|
if (integerLoop) {
|
|
3131
3662
|
integerSlot = B.slot();
|
|
3132
|
-
B.entryAllocas.push(`${integerSlot} = alloca
|
|
3133
|
-
B.line(`store
|
|
3663
|
+
B.entryAllocas.push(`${integerSlot} = alloca ${this.sizeType} ; integer induction ${this.currentLocals.get(integerLoop.localId).name}`);
|
|
3664
|
+
B.line(`store ${this.sizeType} 0, ptr ${integerSlot}`);
|
|
3134
3665
|
this.integerLoopBindings.set(integerLoop.localId, integerSlot);
|
|
3135
3666
|
}
|
|
3136
3667
|
else if (s.init) {
|
|
@@ -3156,9 +3687,9 @@ class LlEmitter {
|
|
|
3156
3687
|
const index = B.tmp();
|
|
3157
3688
|
const inBounds = B.tmp();
|
|
3158
3689
|
B.line(`${lenPtr} = getelementptr inbounds %ScrBytes, ptr ${receiver.name}, i64 0, i32 1`);
|
|
3159
|
-
B.line(`${len} = load
|
|
3160
|
-
B.line(`${index} = load
|
|
3161
|
-
B.line(`${inBounds} = icmp ult
|
|
3690
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}`);
|
|
3691
|
+
B.line(`${index} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
3692
|
+
B.line(`${inBounds} = icmp ult ${this.sizeType} ${index}, ${len}`);
|
|
3162
3693
|
B.condBr(inBounds, lb, le);
|
|
3163
3694
|
}
|
|
3164
3695
|
else if (s.cond)
|
|
@@ -3196,9 +3727,9 @@ class LlEmitter {
|
|
|
3196
3727
|
if (integerLoop && integerSlot) {
|
|
3197
3728
|
const old = B.tmp();
|
|
3198
3729
|
const next = B.tmp();
|
|
3199
|
-
B.line(`${old} = load
|
|
3200
|
-
B.line(`${next} = add nuw
|
|
3201
|
-
B.line(`store
|
|
3730
|
+
B.line(`${old} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
3731
|
+
B.line(`${next} = add nuw ${this.sizeType} ${old}, 1`);
|
|
3732
|
+
B.line(`store ${this.sizeType} ${next}, ptr ${integerSlot}`);
|
|
3202
3733
|
}
|
|
3203
3734
|
else if (s.update)
|
|
3204
3735
|
this.emitStmt(s.update);
|
|
@@ -3376,10 +3907,16 @@ class LlEmitter {
|
|
|
3376
3907
|
else {
|
|
3377
3908
|
this.releaseForJump(0, 0);
|
|
3378
3909
|
}
|
|
3379
|
-
if (
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3910
|
+
if (!B.isTerminated()) {
|
|
3911
|
+
if (this.currentWasiCoro !== null) {
|
|
3912
|
+
this.emitWasiFulfill(v);
|
|
3913
|
+
B.terminate(`br label %${this.currentWasiCoro.finalLabel}`);
|
|
3914
|
+
}
|
|
3915
|
+
else if (v === null)
|
|
3916
|
+
B.terminate("ret void");
|
|
3917
|
+
else
|
|
3918
|
+
B.terminate(`ret ${this.llType(s.value.type)} ${v.name}`);
|
|
3919
|
+
}
|
|
3383
3920
|
break;
|
|
3384
3921
|
}
|
|
3385
3922
|
case "throw": {
|
|
@@ -3408,8 +3945,8 @@ class LlEmitter {
|
|
|
3408
3945
|
// the construct (message) with the SC code stamped on `code`,
|
|
3409
3946
|
// then unwind exactly like `throw`. SCR_ERR_ERROR = 0.
|
|
3410
3947
|
const bytes = Buffer.byteLength(s.message, "utf8");
|
|
3411
|
-
this.declare(`declare void @scr_throw_error_msg_code(i32, ptr,
|
|
3412
|
-
B.line(`call void @scr_throw_error_msg_code(i32 0, ptr ${this.cstr(s.message)},
|
|
3948
|
+
this.declare(`declare void @scr_throw_error_msg_code(i32, ptr, ${this.sizeType}, ptr)`);
|
|
3949
|
+
B.line(`call void @scr_throw_error_msg_code(i32 0, ptr ${this.cstr(s.message)}, ${this.sizeType} ${bytes}, ptr ${this.cstr(s.code)})`);
|
|
3413
3950
|
this.emitUnwind();
|
|
3414
3951
|
break;
|
|
3415
3952
|
}
|
|
@@ -3689,8 +4226,8 @@ class LlEmitter {
|
|
|
3689
4226
|
if (integerSlot !== undefined) {
|
|
3690
4227
|
const integer = B.tmp();
|
|
3691
4228
|
const number = B.tmp();
|
|
3692
|
-
B.line(`${integer} = load
|
|
3693
|
-
B.line(`${number} = uitofp
|
|
4229
|
+
B.line(`${integer} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
4230
|
+
B.line(`${number} = uitofp ${this.sizeType} ${integer} to double`);
|
|
3694
4231
|
return { name: number, type: e.type };
|
|
3695
4232
|
}
|
|
3696
4233
|
const b = this.binding(e.localId);
|
|
@@ -4817,15 +5354,17 @@ class LlEmitter {
|
|
|
4817
5354
|
}
|
|
4818
5355
|
// Lifted async lambdas enter through their spawn wrapper (which
|
|
4819
5356
|
// takes sc_env first, like every lifted function).
|
|
4820
|
-
this.declare(`declare ptr @scr_closure_new(ptr,
|
|
5357
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
4821
5358
|
const c = B.tmp();
|
|
4822
|
-
B.line(`${c} = call ptr @scr_closure_new(ptr @${this.callTarget(e.fnName)},
|
|
5359
|
+
B.line(`${c} = call ptr @scr_closure_new(ptr @${this.callTarget(e.fnName)}, ${this.sizeType} ${e.captures.length})`);
|
|
4823
5360
|
const out = this.own({ name: c, type: e.type });
|
|
4824
5361
|
e.captures.forEach((localId, i) => {
|
|
4825
5362
|
const box = this.loadBox(`%${mangleLocal(localId)}`);
|
|
4826
5363
|
const retained = this.retainBox(box);
|
|
5364
|
+
const caps = B.tmp();
|
|
4827
5365
|
const capp = B.tmp();
|
|
4828
|
-
B.line(`${
|
|
5366
|
+
B.line(`${caps} = getelementptr inbounds %ScrClosure, ptr ${c}, i64 1 ; caps`);
|
|
5367
|
+
B.line(`${capp} = getelementptr inbounds ptr, ptr ${caps}, ${this.sizeType} ${i} ; caps[${i}]`);
|
|
4829
5368
|
B.line(`store ptr ${retained}, ptr ${capp}`);
|
|
4830
5369
|
});
|
|
4831
5370
|
return out;
|
|
@@ -4904,11 +5443,49 @@ class LlEmitter {
|
|
|
4904
5443
|
if (!entry)
|
|
4905
5444
|
throw new Error(`llvm emitter bug: unknown FFI import ${e.import}`);
|
|
4906
5445
|
const args = e.args.map((arg) => this.emitExpr(arg));
|
|
5446
|
+
const sourceArgs = new Map();
|
|
5447
|
+
const callbackArgs = new Map();
|
|
5448
|
+
let sourceIndex = 0;
|
|
5449
|
+
entry.params.forEach((param, abiIndex) => {
|
|
5450
|
+
if (isFfiContextParam(param))
|
|
5451
|
+
return;
|
|
5452
|
+
const arg = args[sourceIndex++];
|
|
5453
|
+
sourceArgs.set(abiIndex, arg);
|
|
5454
|
+
if (isFfiCallbackParam(param))
|
|
5455
|
+
callbackArgs.set(param.callback.id, arg);
|
|
5456
|
+
});
|
|
5457
|
+
const rawContexts = [];
|
|
5458
|
+
for (const param of entry.params) {
|
|
5459
|
+
if (!isFfiCallbackParam(param))
|
|
5460
|
+
continue;
|
|
5461
|
+
const adapter = this.ffiCallbackAdapter(entry.name, param.callback.id);
|
|
5462
|
+
if (adapter.tls === null)
|
|
5463
|
+
continue;
|
|
5464
|
+
const callback = callbackArgs.get(param.callback.id);
|
|
5465
|
+
const previous = B.tmp();
|
|
5466
|
+
B.line(`${previous} = load ptr, ptr @${adapter.tls}`);
|
|
5467
|
+
B.line(`store ptr ${callback.name}, ptr @${adapter.tls}`);
|
|
5468
|
+
rawContexts.push({ tls: adapter.tls, previous });
|
|
5469
|
+
}
|
|
4907
5470
|
const nativeArgs = [];
|
|
4908
5471
|
const nativeParamTypes = [];
|
|
4909
|
-
entry.params.forEach((
|
|
4910
|
-
|
|
4911
|
-
|
|
5472
|
+
entry.params.forEach((param, i) => {
|
|
5473
|
+
if (isFfiCallbackParam(param)) {
|
|
5474
|
+
const adapter = this.ffiCallbackAdapter(entry.name, param.callback.id);
|
|
5475
|
+
nativeParamTypes.push("ptr");
|
|
5476
|
+
nativeArgs.push(`ptr @${adapter.symbol}`);
|
|
5477
|
+
return;
|
|
5478
|
+
}
|
|
5479
|
+
if (isFfiContextParam(param)) {
|
|
5480
|
+
const callback = callbackArgs.get(param.context);
|
|
5481
|
+
if (!callback)
|
|
5482
|
+
throw new Error(`llvm emitter bug: FFI context '${param.context}' has no callback arg`);
|
|
5483
|
+
nativeParamTypes.push("ptr");
|
|
5484
|
+
nativeArgs.push(`ptr ${callback.name}`);
|
|
5485
|
+
return;
|
|
5486
|
+
}
|
|
5487
|
+
const arg = sourceArgs.get(i);
|
|
5488
|
+
switch (param) {
|
|
4912
5489
|
case "f64":
|
|
4913
5490
|
nativeParamTypes.push("double");
|
|
4914
5491
|
nativeArgs.push(`double ${arg.name}`);
|
|
@@ -4927,7 +5504,7 @@ class LlEmitter {
|
|
|
4927
5504
|
const asU32 = B.tmp();
|
|
4928
5505
|
B.line(`${asDouble} = call double @scr_bit_ushr(double ${arg.name}, double ${f64Lit(0)})`);
|
|
4929
5506
|
B.line(`${asU32} = fptoui double ${asDouble} to i32`);
|
|
4930
|
-
if (
|
|
5507
|
+
if (param === "u8") {
|
|
4931
5508
|
const asU8 = B.tmp();
|
|
4932
5509
|
B.line(`${asU8} = trunc i32 ${asU32} to i8`);
|
|
4933
5510
|
nativeParamTypes.push("i8");
|
|
@@ -4975,29 +5552,47 @@ class LlEmitter {
|
|
|
4975
5552
|
}
|
|
4976
5553
|
}
|
|
4977
5554
|
});
|
|
4978
|
-
const retTy = entry.returns
|
|
4979
|
-
: entry.returns === "bool" || entry.returns === "u8" ? "i8"
|
|
4980
|
-
: entry.returns === "u32" || entry.returns === "i32" ? "i32"
|
|
4981
|
-
: "void";
|
|
5555
|
+
const retTy = ffiNativeTypeLl(entry.returns);
|
|
4982
5556
|
this.declare(`declare ${retTy} @${entry.symbol}(${nativeParamTypes.join(", ")})`);
|
|
4983
5557
|
const call = `call ${retTy} @${entry.symbol}(${nativeArgs.join(", ")})`;
|
|
5558
|
+
const restoreRawContexts = () => {
|
|
5559
|
+
for (let i = rawContexts.length - 1; i >= 0; i--) {
|
|
5560
|
+
const saved = rawContexts[i];
|
|
5561
|
+
B.line(`store ptr ${saved.previous}, ptr @${saved.tls}`);
|
|
5562
|
+
}
|
|
5563
|
+
};
|
|
5564
|
+
const callbacksMayThrow = callbackArgs.size > 0;
|
|
4984
5565
|
if (entry.returns === "void") {
|
|
4985
5566
|
B.line(call);
|
|
5567
|
+
restoreRawContexts();
|
|
5568
|
+
if (callbacksMayThrow)
|
|
5569
|
+
this.emitPendingCheck();
|
|
4986
5570
|
return { name: "", type: e.type };
|
|
4987
5571
|
}
|
|
4988
5572
|
const raw = B.tmp();
|
|
4989
5573
|
B.line(`${raw} = ${call}`);
|
|
4990
|
-
|
|
4991
|
-
|
|
5574
|
+
restoreRawContexts();
|
|
5575
|
+
if (entry.returns === "f64") {
|
|
5576
|
+
const result = { name: raw, type: e.type };
|
|
5577
|
+
if (callbacksMayThrow)
|
|
5578
|
+
this.emitPendingCheck();
|
|
5579
|
+
return result;
|
|
5580
|
+
}
|
|
4992
5581
|
if (entry.returns === "bool") {
|
|
4993
5582
|
const value = B.tmp();
|
|
4994
5583
|
B.line(`${value} = icmp ne i8 ${raw}, 0`);
|
|
4995
|
-
|
|
5584
|
+
const result = { name: value, type: e.type };
|
|
5585
|
+
if (callbacksMayThrow)
|
|
5586
|
+
this.emitPendingCheck();
|
|
5587
|
+
return result;
|
|
4996
5588
|
}
|
|
4997
5589
|
const value = B.tmp();
|
|
4998
5590
|
const op = entry.returns === "i32" ? "sitofp" : "uitofp";
|
|
4999
5591
|
B.line(`${value} = ${op} ${retTy} ${raw} to double`);
|
|
5000
|
-
|
|
5592
|
+
const result = { name: value, type: e.type };
|
|
5593
|
+
if (callbacksMayThrow)
|
|
5594
|
+
this.emitPendingCheck();
|
|
5595
|
+
return result;
|
|
5001
5596
|
}
|
|
5002
5597
|
case "new": {
|
|
5003
5598
|
// Allocate (fields zeroed, vt stamped), then run the ctor. The
|
|
@@ -5116,8 +5711,8 @@ class LlEmitter {
|
|
|
5116
5711
|
const ge = B.tmp();
|
|
5117
5712
|
const le = B.tmp();
|
|
5118
5713
|
const t = B.tmp();
|
|
5119
|
-
B.line(`${ge} = icmp sge
|
|
5120
|
-
B.line(`${le} = icmp sle
|
|
5714
|
+
B.line(`${ge} = icmp sge ${this.sizeType} ${pre}, ${target.pre}`);
|
|
5715
|
+
B.line(`${le} = icmp sle ${this.sizeType} ${pre}, ${target.post}`);
|
|
5121
5716
|
B.line(`${t} = and i1 ${ge}, ${le} ; instanceof ${e.className}`);
|
|
5122
5717
|
return { name: t, type: e.type };
|
|
5123
5718
|
}
|
|
@@ -5135,14 +5730,14 @@ class LlEmitter {
|
|
|
5135
5730
|
const tpostp = B.tmp();
|
|
5136
5731
|
const tpost = B.tmp();
|
|
5137
5732
|
B.line(`${tprep} = getelementptr inbounds %ScrClassObj, ptr ${target.name}, i64 0, i32 1`);
|
|
5138
|
-
B.line(`${tpre} = load
|
|
5733
|
+
B.line(`${tpre} = load ${this.sizeType}, ptr ${tprep}`);
|
|
5139
5734
|
B.line(`${tpostp} = getelementptr inbounds %ScrClassObj, ptr ${target.name}, i64 0, i32 2`);
|
|
5140
|
-
B.line(`${tpost} = load
|
|
5735
|
+
B.line(`${tpost} = load ${this.sizeType}, ptr ${tpostp}`);
|
|
5141
5736
|
const ge = B.tmp();
|
|
5142
5737
|
const le = B.tmp();
|
|
5143
5738
|
const t = B.tmp();
|
|
5144
|
-
B.line(`${ge} = icmp sge
|
|
5145
|
-
B.line(`${le} = icmp sle
|
|
5739
|
+
B.line(`${ge} = icmp sge ${this.sizeType} ${pre}, ${tpre}`);
|
|
5740
|
+
B.line(`${le} = icmp sle ${this.sizeType} ${pre}, ${tpost}`);
|
|
5146
5741
|
B.line(`${t} = and i1 ${ge}, ${le}`);
|
|
5147
5742
|
return { name: t, type: e.type };
|
|
5148
5743
|
}
|
|
@@ -5154,9 +5749,9 @@ class LlEmitter {
|
|
|
5154
5749
|
const c = this.emitExpr(e.value);
|
|
5155
5750
|
if (e.test === "instanceof") {
|
|
5156
5751
|
const target = this.classMetaOf(e.className);
|
|
5157
|
-
this.declare(`declare zeroext i1 @scr_caught_instanceof(ptr,
|
|
5752
|
+
this.declare(`declare zeroext i1 @scr_caught_instanceof(ptr, ${this.sizeType}, ${this.sizeType})`);
|
|
5158
5753
|
const t = B.tmp();
|
|
5159
|
-
B.line(`${t} = call zeroext i1 @scr_caught_instanceof(ptr ${c.name},
|
|
5754
|
+
B.line(`${t} = call zeroext i1 @scr_caught_instanceof(ptr ${c.name}, ${this.sizeType} ${target.pre}, ${this.sizeType} ${target.post})`);
|
|
5160
5755
|
if (e.negated !== true)
|
|
5161
5756
|
return { name: t, type: e.type };
|
|
5162
5757
|
const n = B.tmp();
|
|
@@ -5221,9 +5816,9 @@ class LlEmitter {
|
|
|
5221
5816
|
const c = this.emitExpr(e.value);
|
|
5222
5817
|
const target = this.classMetaOf(e.className);
|
|
5223
5818
|
const display = e.className.startsWith("%") ? e.className.slice(1) : e.className;
|
|
5224
|
-
this.declare(`declare ptr @scr_caught_check_obj(ptr,
|
|
5819
|
+
this.declare(`declare ptr @scr_caught_check_obj(ptr, ${this.sizeType}, ${this.sizeType}, ptr)`);
|
|
5225
5820
|
const t = B.tmp();
|
|
5226
|
-
B.line(`${t} = call ptr @scr_caught_check_obj(ptr ${c.name},
|
|
5821
|
+
B.line(`${t} = call ptr @scr_caught_check_obj(ptr ${c.name}, ${this.sizeType} ${target.pre}, ${this.sizeType} ${target.post}, ptr ${this.cstr(display)})`);
|
|
5227
5822
|
const out = this.own({ name: t, type: e.type });
|
|
5228
5823
|
this.emitPendingCheck();
|
|
5229
5824
|
return out;
|
|
@@ -5334,7 +5929,7 @@ class LlEmitter {
|
|
|
5334
5929
|
return compact;
|
|
5335
5930
|
const rewriter = this.walkers.jsonIndentHelper();
|
|
5336
5931
|
const t2 = B.tmp();
|
|
5337
|
-
B.line(`${t2} = call ptr @${rewriter}(ptr ${compact.name}, ptr ${this.cstr(indent)},
|
|
5932
|
+
B.line(`${t2} = call ptr @${rewriter}(ptr ${compact.name}, ptr ${this.cstr(indent)}, ${this.sizeType} ${Buffer.byteLength(indent, "utf8")})`);
|
|
5338
5933
|
return this.own({ name: t2, type: e.type });
|
|
5339
5934
|
}
|
|
5340
5935
|
case "bytesNew": {
|
|
@@ -5389,18 +5984,50 @@ class LlEmitter {
|
|
|
5389
5984
|
const v = this.emitExpr(e.value);
|
|
5390
5985
|
const yt = e.value.type;
|
|
5391
5986
|
if (yt.kind === "f64" || yt.kind === "date") {
|
|
5392
|
-
this.
|
|
5393
|
-
|
|
5987
|
+
if (this.wasi) {
|
|
5988
|
+
const coro = this.currentWasiCoro;
|
|
5989
|
+
this.declare(`declare ptr @scr_gen_of_fiber(ptr)`);
|
|
5990
|
+
this.declare(`declare void @scr_gen_out_f64(ptr, double)`);
|
|
5991
|
+
const g = B.tmp();
|
|
5992
|
+
B.line(`${g} = call ptr @scr_gen_of_fiber(ptr ${coro.self})`);
|
|
5993
|
+
B.line(`call void @scr_gen_out_f64(ptr ${g}, double ${v.name})`);
|
|
5994
|
+
}
|
|
5995
|
+
else {
|
|
5996
|
+
this.declare(`declare void @scr_gen_yield_f64(double)`);
|
|
5997
|
+
B.line(`call void @scr_gen_yield_f64(double ${v.name})`);
|
|
5998
|
+
}
|
|
5394
5999
|
}
|
|
5395
6000
|
else if (yt.kind === "bool") {
|
|
5396
|
-
this.
|
|
5397
|
-
|
|
6001
|
+
if (this.wasi) {
|
|
6002
|
+
const coro = this.currentWasiCoro;
|
|
6003
|
+
this.declare(`declare ptr @scr_gen_of_fiber(ptr)`);
|
|
6004
|
+
this.declare(`declare void @scr_gen_out_bool(ptr, i1 zeroext)`);
|
|
6005
|
+
const g = B.tmp();
|
|
6006
|
+
B.line(`${g} = call ptr @scr_gen_of_fiber(ptr ${coro.self})`);
|
|
6007
|
+
B.line(`call void @scr_gen_out_bool(ptr ${g}, i1 ${v.name})`);
|
|
6008
|
+
}
|
|
6009
|
+
else {
|
|
6010
|
+
this.declare(`declare void @scr_gen_yield_bool(i1 zeroext)`);
|
|
6011
|
+
B.line(`call void @scr_gen_yield_bool(i1 ${v.name})`);
|
|
6012
|
+
}
|
|
5398
6013
|
}
|
|
5399
6014
|
else {
|
|
5400
6015
|
this.moveTemp(v); // the OUT slot takes ownership
|
|
5401
|
-
this.
|
|
5402
|
-
|
|
6016
|
+
if (this.wasi) {
|
|
6017
|
+
const coro = this.currentWasiCoro;
|
|
6018
|
+
this.declare(`declare ptr @scr_gen_of_fiber(ptr)`);
|
|
6019
|
+
this.declare(`declare void @scr_gen_out_ref(ptr, ptr, ptr)`);
|
|
6020
|
+
const g = B.tmp();
|
|
6021
|
+
B.line(`${g} = call ptr @scr_gen_of_fiber(ptr ${coro.self})`);
|
|
6022
|
+
B.line(`call void @scr_gen_out_ref(ptr ${g}, ptr ${v.name}, ptr ${vAdapters(this, yt).release})`);
|
|
6023
|
+
}
|
|
6024
|
+
else {
|
|
6025
|
+
this.declare(`declare void @scr_gen_yield_ref(ptr, ptr)`);
|
|
6026
|
+
B.line(`call void @scr_gen_yield_ref(ptr ${v.name}, ptr ${vAdapters(this, yt).release})`);
|
|
6027
|
+
}
|
|
5403
6028
|
}
|
|
6029
|
+
if (this.wasi)
|
|
6030
|
+
this.emitWasiSuspendPrepared();
|
|
5404
6031
|
this.emitPendingCheck();
|
|
5405
6032
|
if (e.type.kind === "void") {
|
|
5406
6033
|
// An undefined next-channel: nothing to read (the frontend
|
|
@@ -5532,6 +6159,8 @@ class LlEmitter {
|
|
|
5532
6159
|
// refcounted results arrive +1 and join the frame pre-check so an
|
|
5533
6160
|
// unwind releases the dummy (NULL) harmlessly.
|
|
5534
6161
|
const pr = this.emitExpr(e.value);
|
|
6162
|
+
if (this.wasi)
|
|
6163
|
+
this.emitWasiSuspend(pr.name);
|
|
5535
6164
|
if (e.type.kind === "void") {
|
|
5536
6165
|
this.declare(`declare void @scr_await_void(ptr)`);
|
|
5537
6166
|
B.line(`call void @scr_await_void(ptr ${pr.name})`);
|
|
@@ -5586,10 +6215,18 @@ class LlEmitter {
|
|
|
5586
6215
|
B.condBr(isP, lp, lh);
|
|
5587
6216
|
B.startBlock(lp);
|
|
5588
6217
|
this.declare(`declare void @scr_await_void(ptr)`);
|
|
5589
|
-
|
|
6218
|
+
{
|
|
6219
|
+
const promise = this.unionPeek(u.name);
|
|
6220
|
+
if (this.wasi)
|
|
6221
|
+
this.emitWasiSuspend(promise);
|
|
6222
|
+
B.line(`call void @scr_await_void(ptr ${promise})`);
|
|
6223
|
+
}
|
|
5590
6224
|
B.br(lj);
|
|
5591
6225
|
B.startBlock(lh);
|
|
5592
|
-
|
|
6226
|
+
if (this.wasi)
|
|
6227
|
+
this.emitWasiSuspend(null);
|
|
6228
|
+
else
|
|
6229
|
+
B.line(`call void @scr_await_hop()`);
|
|
5593
6230
|
B.br(lj);
|
|
5594
6231
|
B.startBlock(lj);
|
|
5595
6232
|
this.emitPendingCheck();
|
|
@@ -5618,6 +6255,8 @@ class LlEmitter {
|
|
|
5618
6255
|
B.condBr(isP, lp, lh);
|
|
5619
6256
|
B.startBlock(lp);
|
|
5620
6257
|
const peek = this.unionPeek(u.name);
|
|
6258
|
+
if (this.wasi)
|
|
6259
|
+
this.emitWasiSuspend(peek);
|
|
5621
6260
|
let awaited;
|
|
5622
6261
|
if (inner.kind === "f64" || inner.kind === "date") {
|
|
5623
6262
|
this.declare(`declare double @scr_await_f64(ptr)`);
|
|
@@ -5646,7 +6285,10 @@ class LlEmitter {
|
|
|
5646
6285
|
B.line(`store ptr ${this.unionNewOwned(innerTag, awaited)}, ptr ${slot}`);
|
|
5647
6286
|
B.br(lj);
|
|
5648
6287
|
B.startBlock(lh);
|
|
5649
|
-
|
|
6288
|
+
if (this.wasi)
|
|
6289
|
+
this.emitWasiSuspend(null);
|
|
6290
|
+
else
|
|
6291
|
+
B.line(`call void @scr_await_hop()`);
|
|
5650
6292
|
const unitTags = def.arms.flatMap((a, i) => (isUnitType(a) ? [i] : []));
|
|
5651
6293
|
if (unitTags.length === 1) {
|
|
5652
6294
|
B.line(`store ptr ${this.unitInstanceRef(resUnionId, resTagOf(def.arms[unitTags[0]]))}, ptr ${slot}`);
|
|
@@ -5772,8 +6414,27 @@ class LlEmitter {
|
|
|
5772
6414
|
// Internal ESM dependency wait: pending promises park the module
|
|
5773
6415
|
// fiber, while settled ones continue synchronously.
|
|
5774
6416
|
const p = this.emitExpr(e.args[0]);
|
|
5775
|
-
this.
|
|
5776
|
-
|
|
6417
|
+
if (this.wasi) {
|
|
6418
|
+
const coro = this.currentWasiCoro;
|
|
6419
|
+
if (coro === null)
|
|
6420
|
+
throw new Error("llvm emitter bug: module await outside wasm coroutine");
|
|
6421
|
+
this.declare(`declare zeroext i1 @scr_wasi_module_await_prepare(ptr, ptr)`);
|
|
6422
|
+
const needsSuspend = B.tmp();
|
|
6423
|
+
const suspend = B.newLabel("ma.suspend");
|
|
6424
|
+
const ready = B.newLabel("ma.ready");
|
|
6425
|
+
B.line(`${needsSuspend} = call zeroext i1 @scr_wasi_module_await_prepare(ptr ${coro.self}, ptr ${p.name})`);
|
|
6426
|
+
B.condBr(needsSuspend, suspend, ready);
|
|
6427
|
+
B.startBlock(suspend);
|
|
6428
|
+
this.emitWasiSuspendPrepared();
|
|
6429
|
+
B.br(ready);
|
|
6430
|
+
B.startBlock(ready);
|
|
6431
|
+
this.declare(`declare void @scr_module_await(ptr)`);
|
|
6432
|
+
B.line(`call void @scr_module_await(ptr ${p.name})`);
|
|
6433
|
+
}
|
|
6434
|
+
else {
|
|
6435
|
+
this.declare(`declare void @scr_module_await(ptr)`);
|
|
6436
|
+
B.line(`call void @scr_module_await(ptr ${p.name})`);
|
|
6437
|
+
}
|
|
5777
6438
|
this.emitPendingCheck();
|
|
5778
6439
|
return { name: "", type: e.type };
|
|
5779
6440
|
}
|
|
@@ -5807,7 +6468,7 @@ class LlEmitter {
|
|
|
5807
6468
|
const len = B.tmp();
|
|
5808
6469
|
const cap = B.tmp();
|
|
5809
6470
|
B.line(`${len} = call double @scr_arr_len(ptr ${ps.name})`);
|
|
5810
|
-
B.line(`${cap} = fptoui double ${len} to
|
|
6471
|
+
B.line(`${cap} = fptoui double ${len} to ${this.sizeType}`);
|
|
5811
6472
|
const vals = B.tmp();
|
|
5812
6473
|
B.line(`${vals} = ${arrNewCall(this, elem, cap)}`);
|
|
5813
6474
|
this.own({ name: vals, type: e.type.inner });
|
|
@@ -5929,8 +6590,8 @@ class LlEmitter {
|
|
|
5929
6590
|
}
|
|
5930
6591
|
});
|
|
5931
6592
|
const fn = e.name === "console.error" ? "scr_console_error" : "scr_console_log";
|
|
5932
|
-
this.declare(`declare void @${fn}(
|
|
5933
|
-
B.line(`call void @${fn}(
|
|
6593
|
+
this.declare(`declare void @${fn}(${this.sizeType}, ptr)`);
|
|
6594
|
+
B.line(`call void @${fn}(${this.sizeType} ${args.length}, ptr %logargs)`);
|
|
5934
6595
|
return { name: "", type: e.type };
|
|
5935
6596
|
}
|
|
5936
6597
|
case "dynFrom": {
|
|
@@ -5972,9 +6633,9 @@ class LlEmitter {
|
|
|
5972
6633
|
this.liveDynRefAdapters.set(key, adapter);
|
|
5973
6634
|
}
|
|
5974
6635
|
const rc = vAdapters(this, v.type);
|
|
5975
|
-
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr,
|
|
6636
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
5976
6637
|
const boxed = B.tmp();
|
|
5977
|
-
B.line(`${boxed} = call ptr @scr_dyn_new_typed_ref(ptr ${v.name}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${this.cstr(key)},
|
|
6638
|
+
B.line(`${boxed} = call ptr @scr_dyn_new_typed_ref(ptr ${v.name}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${this.cstr(key)}, ${this.sizeType} ${Buffer.byteLength(key, "utf8")}, ptr @${adapter.snapshot}, ptr ${adapter.commit})`);
|
|
5978
6639
|
return this.own({ name: boxed, type: e.type });
|
|
5979
6640
|
}
|
|
5980
6641
|
if (v.type.kind === "func") {
|
|
@@ -6075,14 +6736,14 @@ class LlEmitter {
|
|
|
6075
6736
|
B.entryAllocas.push(`${arr} = alloca [${args.length} x ptr]`);
|
|
6076
6737
|
args.forEach((a, i) => {
|
|
6077
6738
|
const p = B.tmp();
|
|
6078
|
-
B.line(`${p} = getelementptr inbounds [${args.length} x ptr], ptr ${arr}, i64 0,
|
|
6739
|
+
B.line(`${p} = getelementptr inbounds [${args.length} x ptr], ptr ${arr}, i64 0, ${this.sizeType} ${i}`);
|
|
6079
6740
|
B.line(`store ptr ${a.name}, ptr ${p}`);
|
|
6080
6741
|
});
|
|
6081
6742
|
argsPtr = arr;
|
|
6082
6743
|
}
|
|
6083
|
-
this.declare(`declare ptr @scr_dyn_call(ptr, ptr,
|
|
6744
|
+
this.declare(`declare ptr @scr_dyn_call(ptr, ptr, ${this.sizeType}, ptr)`);
|
|
6084
6745
|
const t = B.tmp();
|
|
6085
|
-
B.line(`${t} = call ptr @scr_dyn_call(ptr ${callee.name}, ptr ${argsPtr},
|
|
6746
|
+
B.line(`${t} = call ptr @scr_dyn_call(ptr ${callee.name}, ptr ${argsPtr}, ${this.sizeType} ${args.length}, ptr ${this.cstr(e.calleeName)})`);
|
|
6086
6747
|
const out = this.own({ name: t, type: e.type });
|
|
6087
6748
|
this.emitPendingCheck();
|
|
6088
6749
|
return out;
|
|
@@ -6099,14 +6760,14 @@ class LlEmitter {
|
|
|
6099
6760
|
B.entryAllocas.push(`${arr} = alloca [${args.length} x ptr]`);
|
|
6100
6761
|
args.forEach((a, i) => {
|
|
6101
6762
|
const p = B.tmp();
|
|
6102
|
-
B.line(`${p} = getelementptr inbounds [${args.length} x ptr], ptr ${arr}, i64 0,
|
|
6763
|
+
B.line(`${p} = getelementptr inbounds [${args.length} x ptr], ptr ${arr}, i64 0, ${this.sizeType} ${i}`);
|
|
6103
6764
|
B.line(`store ptr ${a.name}, ptr ${p}`);
|
|
6104
6765
|
});
|
|
6105
6766
|
argsPtr = arr;
|
|
6106
6767
|
}
|
|
6107
|
-
this.declare(`declare ptr @scr_dyn_invoke(ptr, ptr, ptr,
|
|
6768
|
+
this.declare(`declare ptr @scr_dyn_invoke(ptr, ptr, ptr, ${this.sizeType}, ptr)`);
|
|
6108
6769
|
const t = B.tmp();
|
|
6109
|
-
B.line(`${t} = call ptr @scr_dyn_invoke(ptr ${recv.name}, ptr ${this.cstr(e.method)}, ptr ${argsPtr},
|
|
6770
|
+
B.line(`${t} = call ptr @scr_dyn_invoke(ptr ${recv.name}, ptr ${this.cstr(e.method)}, ptr ${argsPtr}, ${this.sizeType} ${args.length}, ptr ${this.cstr(e.calleeName)})`);
|
|
6110
6771
|
const out = this.own({ name: t, type: e.type });
|
|
6111
6772
|
this.emitPendingCheck();
|
|
6112
6773
|
return out;
|
|
@@ -6173,11 +6834,11 @@ class LlEmitter {
|
|
|
6173
6834
|
B.line(`${isObj} = icmp eq i32 ${kd}, ${DK.OBJ}`);
|
|
6174
6835
|
B.condBr(isObj, lObj, lNotObj);
|
|
6175
6836
|
B.startBlock(lObj);
|
|
6176
|
-
this.declare(`declare ptr @scr_dyn_obj_get(ptr, ptr,
|
|
6837
|
+
this.declare(`declare ptr @scr_dyn_obj_get(ptr, ptr, ${this.sizeType})`);
|
|
6177
6838
|
const keyBytes = Buffer.byteLength(e.key, "utf8");
|
|
6178
6839
|
const m = B.tmp();
|
|
6179
6840
|
const has = B.tmp();
|
|
6180
|
-
B.line(`${m} = call ptr @scr_dyn_obj_get(ptr ${d.name}, ptr ${this.cstr(e.key)},
|
|
6841
|
+
B.line(`${m} = call ptr @scr_dyn_obj_get(ptr ${d.name}, ptr ${this.cstr(e.key)}, ${this.sizeType} ${keyBytes})`);
|
|
6181
6842
|
B.line(`${has} = icmp ne ptr ${m}, null`);
|
|
6182
6843
|
B.line(`store i1 ${has}, ptr ${slot}`);
|
|
6183
6844
|
B.br(lj);
|
|
@@ -6195,8 +6856,8 @@ class LlEmitter {
|
|
|
6195
6856
|
const len = B.tmp();
|
|
6196
6857
|
const inR = B.tmp();
|
|
6197
6858
|
B.line(`${lenp} = getelementptr inbounds i8, ptr ${d.name}, i64 16 ; ->v.arr.len`);
|
|
6198
|
-
B.line(`${len} = load
|
|
6199
|
-
B.line(`${inR} = icmp ugt
|
|
6859
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenp}`);
|
|
6860
|
+
B.line(`${inR} = icmp ugt ${this.sizeType} ${len}, ${e.key}`);
|
|
6200
6861
|
B.line(`store i1 ${inR}, ptr ${slot}`);
|
|
6201
6862
|
}
|
|
6202
6863
|
B.br(lj);
|
|
@@ -6309,10 +6970,10 @@ class LlEmitter {
|
|
|
6309
6970
|
const lj = B.newLabel("dts.j");
|
|
6310
6971
|
B.condBr(isObj, lObj, lj);
|
|
6311
6972
|
B.startBlock(lObj);
|
|
6312
|
-
this.declare(`declare ptr @scr_dyn_obj_get(ptr, ptr,
|
|
6973
|
+
this.declare(`declare ptr @scr_dyn_obj_get(ptr, ptr, ${this.sizeType})`);
|
|
6313
6974
|
const m = B.tmp();
|
|
6314
6975
|
const has = B.tmp();
|
|
6315
|
-
B.line(`${m} = call ptr @scr_dyn_obj_get(ptr ${d.name}, ptr ${this.cstr("%error")},
|
|
6976
|
+
B.line(`${m} = call ptr @scr_dyn_obj_get(ptr ${d.name}, ptr ${this.cstr("%error")}, ${this.sizeType} 6)`);
|
|
6316
6977
|
B.line(`${has} = icmp ne ptr ${m}, null`);
|
|
6317
6978
|
B.line(`store i1 ${has}, ptr ${slot}`);
|
|
6318
6979
|
B.br(lj);
|
|
@@ -6420,7 +7081,7 @@ class LlEmitter {
|
|
|
6420
7081
|
}
|
|
6421
7082
|
const helper = this.dyn.dynIterNHelper();
|
|
6422
7083
|
const t = B.tmp();
|
|
6423
|
-
B.line(`${t} = call ptr @${helper}(ptr ${v.name},
|
|
7084
|
+
B.line(`${t} = call ptr @${helper}(ptr ${v.name}, ${this.sizeType} ${e.count})`);
|
|
6424
7085
|
const out = this.own({ name: t, type: e.type });
|
|
6425
7086
|
this.emitPendingCheck();
|
|
6426
7087
|
return out;
|
|
@@ -7174,13 +7835,13 @@ class LlEmitter {
|
|
|
7174
7835
|
this.resolveThunkDefs.push(...d);
|
|
7175
7836
|
return sym;
|
|
7176
7837
|
}
|
|
7177
|
-
/** Loads a dyn node's kind tag
|
|
7838
|
+
/** Loads a dyn node's kind tag after its size_t RC word — the dyn expression tests'
|
|
7178
7839
|
* shared read. */
|
|
7179
7840
|
dynKind(d) {
|
|
7180
7841
|
const B = this.B;
|
|
7181
7842
|
const p = B.tmp();
|
|
7182
7843
|
const k = B.tmp();
|
|
7183
|
-
B.line(`${p} = getelementptr inbounds i8, ptr ${d}, i64 8 ; ->kind`);
|
|
7844
|
+
B.line(`${p} = getelementptr inbounds i8, ptr ${d}, i64 ${this.sizeType === "i32" ? 4 : 8} ; ->kind`);
|
|
7184
7845
|
B.line(`${k} = load i32, ptr ${p}`);
|
|
7185
7846
|
return k;
|
|
7186
7847
|
}
|
|
@@ -7486,11 +8147,11 @@ class LlEmitter {
|
|
|
7486
8147
|
}
|
|
7487
8148
|
this.declare(`declare ptr @scr_union_new_f64(i32, double)`);
|
|
7488
8149
|
this.declare(`declare ptr @scr_union_new_ref(i32, ptr, ptr, ptr, ptr)`);
|
|
7489
|
-
this.declare(`declare ptr @scr_str_new(ptr,
|
|
7490
|
-
this.declare(`declare
|
|
8150
|
+
this.declare(`declare ptr @scr_str_new(ptr, ${this.sizeType})`);
|
|
8151
|
+
this.declare(`declare ${this.sizeType} @strlen(ptr)`);
|
|
7491
8152
|
this.declare(`declare ptr @scr_str_retain_v(ptr)`);
|
|
7492
8153
|
this.declare(`declare void @scr_str_release_v(ptr)`);
|
|
7493
|
-
this.resolveThunkDefs.push(`define internal void @${sym}(ptr %cb, i1 zeroext %has, double %code, ptr %sig) ${FN_ATTRS} { ; child exit (code, signal)`, `entry:`, ` %uslot = alloca ptr`, ` %sslot = alloca ptr`, ` br i1 %has, label %num, label %nonum`, `num:`, ` %u1 = call ptr @scr_union_new_f64(i32 ${f64Tag}, double %code)`, ` store ptr %u1, ptr %uslot`, ` br label %sigq`, `nonum:`, ` store ptr ${this.unitInstanceRef(codeParam.unionId, codeNullTag)}, ptr %uslot`, ` br label %sigq`, `sigq:`, ` %hassig = icmp ne ptr %sig, null`, ` br i1 %hassig, label %sigs, label %signull`, `sigs:`, ` %len = call
|
|
8154
|
+
this.resolveThunkDefs.push(`define internal void @${sym}(ptr %cb, i1 zeroext %has, double %code, ptr %sig) ${FN_ATTRS} { ; child exit (code, signal)`, `entry:`, ` %uslot = alloca ptr`, ` %sslot = alloca ptr`, ` br i1 %has, label %num, label %nonum`, `num:`, ` %u1 = call ptr @scr_union_new_f64(i32 ${f64Tag}, double %code)`, ` store ptr %u1, ptr %uslot`, ` br label %sigq`, `nonum:`, ` store ptr ${this.unitInstanceRef(codeParam.unionId, codeNullTag)}, ptr %uslot`, ` br label %sigq`, `sigq:`, ` %hassig = icmp ne ptr %sig, null`, ` br i1 %hassig, label %sigs, label %signull`, `sigs:`, ` %len = call ${this.sizeType} @strlen(ptr %sig)`, ` %ss = call ptr @scr_str_new(ptr %sig, ${this.sizeType} %len)`, ` %su = call ptr @scr_union_new_ref(i32 ${strTag}, ptr %ss, ptr @scr_str_retain_v, ptr @scr_str_release_v, ptr null)`, ` store ptr %su, ptr %sslot`, ` br label %go`, `signull:`, ` store ptr ${this.unitInstanceRef(sigParam.unionId, sigNullTag)}, ptr %sslot`, ` br label %go`, `go:`, ` %u = load ptr, ptr %uslot`, ` %s = load ptr, ptr %sslot`, ` %fnp = getelementptr inbounds %ScrClosure, ptr %cb, i64 0, i32 1`, ` %fn = load ptr, ptr %fnp`, ` call void %fn(ptr %cb, ptr %u, ptr %s)`, ` ret void`, `}`, ``);
|
|
7494
8155
|
return sym;
|
|
7495
8156
|
}
|
|
7496
8157
|
/** Interned per-union child-stream data adapter — emit-async.ts's
|
|
@@ -7521,8 +8182,8 @@ class LlEmitter {
|
|
|
7521
8182
|
* POINTER-SIZE slots off the emit tuple's va_list (textual LLVM IR
|
|
7522
8183
|
* cannot va_arg portably) and calls this function behind the wrapper
|
|
7523
8184
|
* closure's fn. It re-types each slot to the listener's declared
|
|
7524
|
-
* parameter (f64
|
|
7525
|
-
*
|
|
8185
|
+
* parameter (f64/bool scalars load from the emit site's stack slot,
|
|
8186
|
+
* refcounted values retain the direct pointer — the callee owns +1 per the
|
|
7526
8187
|
* universal convention) and calls the ORIGINAL listener held by the
|
|
7527
8188
|
* wrapper's one capture box. A non-void result is discarded (refcounted
|
|
7528
8189
|
* ones released) — Node ignores listener return values. Interned per
|
|
@@ -7556,11 +8217,11 @@ class LlEmitter {
|
|
|
7556
8217
|
cbT.params.forEach((p, i) => {
|
|
7557
8218
|
const ty = this.llType(p);
|
|
7558
8219
|
if (ty === "double") {
|
|
7559
|
-
d.push(` %
|
|
8220
|
+
d.push(` %d${i} = load double, ptr %a${i}`);
|
|
7560
8221
|
passed.push(`double %d${i}`);
|
|
7561
8222
|
}
|
|
7562
8223
|
else if (ty === "i1") {
|
|
7563
|
-
d.push(` %
|
|
8224
|
+
d.push(` %b${i} = load i1, ptr %a${i}`);
|
|
7564
8225
|
passed.push(`i1 %b${i}`);
|
|
7565
8226
|
}
|
|
7566
8227
|
else if (isRefCounted(p)) {
|
|
@@ -7592,11 +8253,11 @@ class LlEmitter {
|
|
|
7592
8253
|
* registration call it feeds always moves it into the registry. */
|
|
7593
8254
|
wrapEmitterListener(target, adapterFn) {
|
|
7594
8255
|
const B = this.B;
|
|
7595
|
-
this.declare(`declare ptr @scr_closure_new(ptr,
|
|
8256
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
7596
8257
|
this.declare(`declare ptr @scr_box_new(i32)`);
|
|
7597
8258
|
this.declare(`declare void @scr_box_set_ref(ptr, ptr)`);
|
|
7598
8259
|
const ad = B.tmp();
|
|
7599
|
-
B.line(`${ad} = call ptr @scr_closure_new(ptr @${adapterFn},
|
|
8260
|
+
B.line(`${ad} = call ptr @scr_closure_new(ptr @${adapterFn}, ${this.sizeType} 1)`);
|
|
7600
8261
|
const bx = B.tmp();
|
|
7601
8262
|
B.line(`${bx} = call ptr @scr_box_new(i32 4) ; SCR_BOX_FUNC`);
|
|
7602
8263
|
const capsp = B.tmp();
|
|
@@ -7672,7 +8333,7 @@ class LlEmitter {
|
|
|
7672
8333
|
throw new Error("llvm emitter bug: bound-close err union lacks its undefined arm");
|
|
7673
8334
|
trampoline = `${sym}_cb`;
|
|
7674
8335
|
this.resolveThunkDefs.push(`define internal void @${trampoline}(ptr %self) ${FN_ATTRS} { ; close cb: fire with no error`, `entry:`, ` %capsp = getelementptr inbounds %ScrClosure, ptr %self, i64 1`, ` %bx = load ptr, ptr %capsp`, ` %inner = call ptr @scr_box_get_ref(ptr %bx) ; +1`, ` %fnp = getelementptr inbounds %ScrClosure, ptr %inner, i64 0, i32 1`, ` %fn = load ptr, ptr %fnp`, ` call void %fn(ptr %inner, ptr ${this.unitInstanceRef(errParam.unionId, undefTag)})`, ` call void @scr_closure_release(ptr %inner)`, ` ret void`, `}`, ``);
|
|
7675
|
-
this.declare(`declare ptr @scr_closure_new(ptr,
|
|
8336
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
7676
8337
|
this.declare(`declare ptr @scr_box_new(i32)`);
|
|
7677
8338
|
this.declare(`declare void @scr_box_set_ref(ptr, ptr)`);
|
|
7678
8339
|
}
|
|
@@ -7695,7 +8356,7 @@ class LlEmitter {
|
|
|
7695
8356
|
` %pv = load ptr, ptr %pp`,
|
|
7696
8357
|
];
|
|
7697
8358
|
if (oneParam) {
|
|
7698
|
-
d.push(` %reg = call ptr @scr_closure_new(ptr @${trampoline},
|
|
8359
|
+
d.push(` %reg = call ptr @scr_closure_new(ptr @${trampoline}, ${this.sizeType} 1)`, ` %rbx = call ptr @scr_box_new(i32 4) ; SCR_BOX_FUNC`, ` %rcp = getelementptr inbounds %ScrClosure, ptr %reg, i64 1`, ` store ptr %rbx, ptr %rcp`, ` %pr = call ptr @scr_closure_retain_v(ptr %pv)`, ` call void @scr_box_set_ref(ptr %rbx, ptr %pr)`, ` store ptr %reg, ptr %regslot`);
|
|
7699
8360
|
}
|
|
7700
8361
|
else {
|
|
7701
8362
|
d.push(` %reg = call ptr @scr_closure_retain_v(ptr %pv)`, ` store ptr %reg, ptr %regslot`);
|
|
@@ -7791,8 +8452,8 @@ class LlEmitter {
|
|
|
7791
8452
|
? "a 'data' listener declaring a Buffer chunk received a string (the stream has an encoding set)"
|
|
7792
8453
|
: "a 'data' listener declaring a string chunk received a Buffer (call setEncoding, or declare the chunk as a Buffer)";
|
|
7793
8454
|
const slot = p.kind === "bytes" ? "%a0" : "%a1";
|
|
7794
|
-
this.declare(`declare void @scr_throw_error_msg(i32, ptr,
|
|
7795
|
-
d.push(` %miss = icmp eq ptr ${slot}, null`, ` br i1 %miss, label %bad, label %ok`, `bad:`, ` call void @scr_throw_error_msg(i32 1, ptr ${this.cstr(msg)},
|
|
8455
|
+
this.declare(`declare void @scr_throw_error_msg(i32, ptr, ${this.sizeType})`);
|
|
8456
|
+
d.push(` %miss = icmp eq ptr ${slot}, null`, ` br i1 %miss, label %bad, label %ok`, `bad:`, ` call void @scr_throw_error_msg(i32 1, ptr ${this.cstr(msg)}, ${this.sizeType} ${Buffer.byteLength(msg, "utf8")})`, ` call void @scr_closure_release(ptr %orig)`, ` ret void`, `ok:`, ` %r0 = call ptr ${retainSym(this, p)}(ptr ${slot})`);
|
|
7796
8457
|
finish("%r0");
|
|
7797
8458
|
d.push(`}`, ``);
|
|
7798
8459
|
}
|
|
@@ -7988,13 +8649,13 @@ class LlEmitter {
|
|
|
7988
8649
|
// The stream-owning completion closure (a 1-cap closure boxing the
|
|
7989
8650
|
// retained stream) — shared by the typed and dyn done shapes.
|
|
7990
8651
|
const doneClosure = (fnRef, tag) => {
|
|
7991
|
-
this.declare(`declare ptr @scr_closure_new(ptr,
|
|
8652
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
7992
8653
|
this.declare(`declare ptr @scr_box_new_obj(ptr, ptr, ptr)`);
|
|
7993
8654
|
this.declare(`declare void @scr_box_set_ref(ptr, ptr)`);
|
|
7994
8655
|
this.declare(`declare ptr @scr_stream_retain_v(ptr)`);
|
|
7995
8656
|
this.declare(`declare void @scr_stream_release_v(ptr)`);
|
|
7996
8657
|
this.declare(`declare void @scr_stream_trace(ptr, ptr, ptr)`);
|
|
7997
|
-
d.push(` %${tag}clo = call ptr @scr_closure_new(ptr ${fnRef},
|
|
8658
|
+
d.push(` %${tag}clo = call ptr @scr_closure_new(ptr ${fnRef}, ${this.sizeType} 1)`, ` %${tag}bx = call ptr @scr_box_new_obj(ptr @scr_stream_retain_v, ptr @scr_stream_release_v, ptr @scr_stream_trace)`, ` %${tag}cp = getelementptr inbounds %ScrClosure, ptr %${tag}clo, i64 1`, ` store ptr %${tag}bx, ptr %${tag}cp`, ` %${tag}sr = call ptr @scr_stream_retain_v(ptr %s)`, ` call void @scr_box_set_ref(ptr %${tag}bx, ptr %${tag}sr)`);
|
|
7998
8659
|
return `%${tag}clo`;
|
|
7999
8660
|
};
|
|
8000
8661
|
for (let i = off; i < declared.length; i++) {
|
|
@@ -8023,10 +8684,10 @@ class LlEmitter {
|
|
|
8023
8684
|
passed.push(`ptr %dc${i}`);
|
|
8024
8685
|
}
|
|
8025
8686
|
else if (isEncPos) {
|
|
8026
|
-
this.declare(`declare ptr @scr_str_new(ptr,
|
|
8687
|
+
this.declare(`declare ptr @scr_str_new(ptr, ${this.sizeType})`);
|
|
8027
8688
|
this.declare(`declare ptr @scr_dyn_new_str(ptr)`);
|
|
8028
8689
|
this.declare(`declare void @scr_str_release(ptr)`);
|
|
8029
|
-
d.push(` %es${i} = call ptr @scr_str_new(ptr ${this.cstr("buffer")},
|
|
8690
|
+
d.push(` %es${i} = call ptr @scr_str_new(ptr ${this.cstr("buffer")}, ${this.sizeType} 6)`, ` %ed${i} = call ptr @scr_dyn_new_str(ptr %es${i})`, ` call void @scr_str_release(ptr %es${i})`);
|
|
8030
8691
|
passed.push(`ptr %ed${i}`);
|
|
8031
8692
|
}
|
|
8032
8693
|
else if (isErrPos) {
|
|
@@ -8048,7 +8709,7 @@ class LlEmitter {
|
|
|
8048
8709
|
}
|
|
8049
8710
|
else if (isDonePos) {
|
|
8050
8711
|
const glue = `scr_stream_done_dyn_${kind}`;
|
|
8051
|
-
this.declare(`declare ptr @${glue}(ptr, ptr,
|
|
8712
|
+
this.declare(`declare ptr @${glue}(ptr, ptr, ${this.sizeType})`);
|
|
8052
8713
|
this.declare(`declare ptr @scr_dyn_new_func(ptr, ptr, i32, ptr, ptr)`);
|
|
8053
8714
|
const clo = doneClosure(`@${glue}`, `dd${i}`);
|
|
8054
8715
|
const arity = kind === "t" || kind === "l" ? 2 : 1;
|
|
@@ -8068,8 +8729,8 @@ class LlEmitter {
|
|
|
8068
8729
|
}
|
|
8069
8730
|
else if (isEncPos) {
|
|
8070
8731
|
// Node's encoding for decoded (Buffer) chunks is 'buffer'.
|
|
8071
|
-
this.declare(`declare ptr @scr_str_new(ptr,
|
|
8072
|
-
d.push(` %en${i} = call ptr @scr_str_new(ptr ${this.cstr("buffer")},
|
|
8732
|
+
this.declare(`declare ptr @scr_str_new(ptr, ${this.sizeType})`);
|
|
8733
|
+
d.push(` %en${i} = call ptr @scr_str_new(ptr ${this.cstr("buffer")}, ${this.sizeType} 6)`);
|
|
8073
8734
|
passed.push(`ptr %en${i}`);
|
|
8074
8735
|
}
|
|
8075
8736
|
else if (isErrPos) {
|
|
@@ -8872,7 +9533,7 @@ class LlEmitter {
|
|
|
8872
9533
|
if (slot === undefined)
|
|
8873
9534
|
return null;
|
|
8874
9535
|
const index = this.B.tmp();
|
|
8875
|
-
this.B.line(`${index} = load
|
|
9536
|
+
this.B.line(`${index} = load ${this.sizeType}, ptr ${slot}`);
|
|
8876
9537
|
return index;
|
|
8877
9538
|
}
|
|
8878
9539
|
/** Bounds-check a typed-array element index without an out-of-line call
|
|
@@ -8884,16 +9545,16 @@ class LlEmitter {
|
|
|
8884
9545
|
const lenPtr = B.tmp();
|
|
8885
9546
|
const len = B.tmp();
|
|
8886
9547
|
B.line(`${lenPtr} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 1`);
|
|
8887
|
-
B.line(`${len} = load
|
|
9548
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}`);
|
|
8888
9549
|
if (integerIndex) {
|
|
8889
9550
|
const inRange = B.tmp();
|
|
8890
|
-
B.line(`${inRange} = icmp ult
|
|
9551
|
+
B.line(`${inRange} = icmp ult ${this.sizeType} ${index}, ${len}`);
|
|
8891
9552
|
const invalid = B.newLabel("bytes.index.invalid");
|
|
8892
9553
|
const valid = B.newLabel("bytes.index.valid");
|
|
8893
9554
|
B.condBr(inRange, valid, invalid);
|
|
8894
9555
|
B.startBlock(invalid);
|
|
8895
9556
|
const indexF64 = B.tmp();
|
|
8896
|
-
B.line(`${indexF64} = uitofp
|
|
9557
|
+
B.line(`${indexF64} = uitofp ${this.sizeType} ${index} to double`);
|
|
8897
9558
|
this.declare(`declare double @scr_bytes_get(ptr, double)`);
|
|
8898
9559
|
B.line(`call double @scr_bytes_get(ptr ${receiver}, double ${indexF64})`);
|
|
8899
9560
|
B.terminate("unreachable");
|
|
@@ -8904,7 +9565,7 @@ class LlEmitter {
|
|
|
8904
9565
|
const nonnegative = B.tmp();
|
|
8905
9566
|
const belowLen = B.tmp();
|
|
8906
9567
|
const inRange = B.tmp();
|
|
8907
|
-
B.line(`${lenF64} = uitofp
|
|
9568
|
+
B.line(`${lenF64} = uitofp ${this.sizeType} ${len} to double`);
|
|
8908
9569
|
B.line(`${nonnegative} = fcmp oge double ${index}, ${f64Lit(0)}`);
|
|
8909
9570
|
B.line(`${belowLen} = fcmp olt double ${index}, ${lenF64}`);
|
|
8910
9571
|
B.line(`${inRange} = and i1 ${nonnegative}, ${belowLen}`);
|
|
@@ -8916,8 +9577,8 @@ class LlEmitter {
|
|
|
8916
9577
|
const idx = B.tmp();
|
|
8917
9578
|
const roundTrip = B.tmp();
|
|
8918
9579
|
const integral = B.tmp();
|
|
8919
|
-
B.line(`${idx} = fptoui double ${index} to
|
|
8920
|
-
B.line(`${roundTrip} = uitofp
|
|
9580
|
+
B.line(`${idx} = fptoui double ${index} to ${this.sizeType}`);
|
|
9581
|
+
B.line(`${roundTrip} = uitofp ${this.sizeType} ${idx} to double`);
|
|
8921
9582
|
B.line(`${integral} = fcmp oeq double ${roundTrip}, ${index}`);
|
|
8922
9583
|
B.condBr(integral, valid, invalid);
|
|
8923
9584
|
B.startBlock(invalid);
|
|
@@ -8941,12 +9602,12 @@ class LlEmitter {
|
|
|
8941
9602
|
const p = B.tmp();
|
|
8942
9603
|
const len = B.tmp();
|
|
8943
9604
|
B.line(`${p} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 1`);
|
|
8944
|
-
B.line(`${len} = load
|
|
9605
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${p}`);
|
|
8945
9606
|
const count = bytes && elem !== "u8" ? B.tmp() : len;
|
|
8946
9607
|
if (count !== len)
|
|
8947
|
-
B.line(`${count} = shl
|
|
9608
|
+
B.line(`${count} = shl ${this.sizeType} ${len}, 2`);
|
|
8948
9609
|
const out = B.tmp();
|
|
8949
|
-
B.line(`${out} = uitofp
|
|
9610
|
+
B.line(`${out} = uitofp ${this.sizeType} ${count} to double`);
|
|
8950
9611
|
return { name: out, type: F64 };
|
|
8951
9612
|
}
|
|
8952
9613
|
/** Kind-specialized typed-array load. */
|
|
@@ -8959,7 +9620,7 @@ class LlEmitter {
|
|
|
8959
9620
|
const raw = B.tmp();
|
|
8960
9621
|
const wide = B.tmp();
|
|
8961
9622
|
const out = B.tmp();
|
|
8962
|
-
B.line(`${p} = getelementptr inbounds i8, ptr ${data},
|
|
9623
|
+
B.line(`${p} = getelementptr inbounds i8, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
8963
9624
|
B.line(`${raw} = load i8, ptr ${p}, align 1`);
|
|
8964
9625
|
B.line(`${wide} = zext i8 ${raw} to i32`);
|
|
8965
9626
|
B.line(`${out} = uitofp i32 ${wide} to double`);
|
|
@@ -8968,14 +9629,14 @@ class LlEmitter {
|
|
|
8968
9629
|
if (elem === "f32") {
|
|
8969
9630
|
const raw = B.tmp();
|
|
8970
9631
|
const out = B.tmp();
|
|
8971
|
-
B.line(`${p} = getelementptr inbounds float, ptr ${data},
|
|
9632
|
+
B.line(`${p} = getelementptr inbounds float, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
8972
9633
|
B.line(`${raw} = load float, ptr ${p}, align 1`);
|
|
8973
9634
|
B.line(`${out} = fpext float ${raw} to double`);
|
|
8974
9635
|
return { name: out, type: F64 };
|
|
8975
9636
|
}
|
|
8976
9637
|
const raw = B.tmp();
|
|
8977
9638
|
const out = B.tmp();
|
|
8978
|
-
B.line(`${p} = getelementptr inbounds i32, ptr ${data},
|
|
9639
|
+
B.line(`${p} = getelementptr inbounds i32, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
8979
9640
|
B.line(`${raw} = load i32, ptr ${p}, align 1`);
|
|
8980
9641
|
B.line(`${out} = ${elem === "i32" ? "sitofp" : "uitofp"} i32 ${raw} to double`);
|
|
8981
9642
|
return { name: out, type: F64 };
|
|
@@ -9053,18 +9714,18 @@ class LlEmitter {
|
|
|
9053
9714
|
if (elem === "u8") {
|
|
9054
9715
|
const byte = B.tmp();
|
|
9055
9716
|
B.line(`${byte} = trunc i32 ${stored} to i8`);
|
|
9056
|
-
B.line(`${p} = getelementptr inbounds i8, ptr ${data},
|
|
9717
|
+
B.line(`${p} = getelementptr inbounds i8, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
9057
9718
|
B.line(`store i8 ${byte}, ptr ${p}, align 1`);
|
|
9058
9719
|
return;
|
|
9059
9720
|
}
|
|
9060
9721
|
if (elem === "f32") {
|
|
9061
9722
|
const narrowed = B.tmp();
|
|
9062
9723
|
B.line(`${narrowed} = fptrunc double ${value} to float`);
|
|
9063
|
-
B.line(`${p} = getelementptr inbounds float, ptr ${data},
|
|
9724
|
+
B.line(`${p} = getelementptr inbounds float, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
9064
9725
|
B.line(`store float ${narrowed}, ptr ${p}, align 1`);
|
|
9065
9726
|
return;
|
|
9066
9727
|
}
|
|
9067
|
-
B.line(`${p} = getelementptr inbounds i32, ptr ${data},
|
|
9728
|
+
B.line(`${p} = getelementptr inbounds i32, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
9068
9729
|
B.line(`store i32 ${stored}, ptr ${p}, align 1`);
|
|
9069
9730
|
}
|
|
9070
9731
|
/** The bytesIntrinsic surface (emit-exprs.ts's switch, .ll flavored).
|
|
@@ -9698,7 +10359,7 @@ class LlEmitter {
|
|
|
9698
10359
|
const commit = `${snapshot}_commit`;
|
|
9699
10360
|
const check = this.dyn.dynCheckHelper(t);
|
|
9700
10361
|
this.declare(`declare void @scr_arr_release(ptr)`);
|
|
9701
|
-
this.resolveThunkDefs.push(`define internal void @${commit}(ptr %target, ptr %d) ${FN_ATTRS} { ; commit live stream element ${typeKey(t)}`, `entry:`, ` %next = call ptr @${check}(ptr %d, ptr null)`, ` %missing = icmp eq ptr %next, null`, ` br i1 %missing, label %done, label %swap`, `swap:`, ` %target_len_ptr = getelementptr inbounds %ScrArr, ptr %target, i64 0, i32 1`, ` %next_len_ptr = getelementptr inbounds %ScrArr, ptr %next, i64 0, i32 1`, ` %target_len = load
|
|
10362
|
+
this.resolveThunkDefs.push(`define internal void @${commit}(ptr %target, ptr %d) ${FN_ATTRS} { ; commit live stream element ${typeKey(t)}`, `entry:`, ` %next = call ptr @${check}(ptr %d, ptr null)`, ` %missing = icmp eq ptr %next, null`, ` br i1 %missing, label %done, label %swap`, `swap:`, ` %target_len_ptr = getelementptr inbounds %ScrArr, ptr %target, i64 0, i32 1`, ` %next_len_ptr = getelementptr inbounds %ScrArr, ptr %next, i64 0, i32 1`, ` %target_len = load ${this.sizeType}, ptr %target_len_ptr`, ` %next_len = load ${this.sizeType}, ptr %next_len_ptr`, ` store ${this.sizeType} %next_len, ptr %target_len_ptr`, ` store ${this.sizeType} %target_len, ptr %next_len_ptr`, ` %target_cap_ptr = getelementptr inbounds %ScrArr, ptr %target, i64 0, i32 2`, ` %next_cap_ptr = getelementptr inbounds %ScrArr, ptr %next, i64 0, i32 2`, ` %target_cap = load ${this.sizeType}, ptr %target_cap_ptr`, ` %next_cap = load ${this.sizeType}, ptr %next_cap_ptr`, ` store ${this.sizeType} %next_cap, ptr %target_cap_ptr`, ` store ${this.sizeType} %target_cap, ptr %next_cap_ptr`, ` %target_data_ptr = getelementptr inbounds %ScrArr, ptr %target, i64 0, i32 7`, ` %next_data_ptr = getelementptr inbounds %ScrArr, ptr %next, i64 0, i32 7`, ` %target_data = load ptr, ptr %target_data_ptr`, ` %next_data = load ptr, ptr %next_data_ptr`, ` store ptr %next_data, ptr %target_data_ptr`, ` store ptr %target_data, ptr %next_data_ptr`, ` call void @scr_arr_release(ptr %next)`, ` br label %done`, `done:`, ` ret void`, `}`, ``);
|
|
9702
10363
|
return `@${commit}`;
|
|
9703
10364
|
}
|
|
9704
10365
|
if (t.kind !== "record")
|
|
@@ -9758,7 +10419,7 @@ class LlEmitter {
|
|
|
9758
10419
|
}
|
|
9759
10420
|
const sym = `sc_ldu_${this.liveDynUnionRefAdapters.size}`;
|
|
9760
10421
|
this.liveDynUnionRefAdapters.set(key, sym);
|
|
9761
|
-
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr,
|
|
10422
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
9762
10423
|
const adapters = new Map();
|
|
9763
10424
|
for (const { arm, tag } of mutableArms) {
|
|
9764
10425
|
const prefix = `${sym}_${tag}`;
|
|
@@ -9782,7 +10443,7 @@ class LlEmitter {
|
|
|
9782
10443
|
const boxed = B.tmp();
|
|
9783
10444
|
B.line(`${payloadPtr} = getelementptr inbounds %ScrUnion, ptr %u, i64 0, i32 5`);
|
|
9784
10445
|
B.line(`${payload} = load ptr, ptr ${payloadPtr}`);
|
|
9785
|
-
B.line(`${boxed} = call ptr @scr_dyn_new_typed_ref(ptr ${payload}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${this.cstr(armKey)},
|
|
10446
|
+
B.line(`${boxed} = call ptr @scr_dyn_new_typed_ref(ptr ${payload}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${this.cstr(armKey)}, ${this.sizeType} ${Buffer.byteLength(armKey, "utf8")}, ptr @${adapter.snapshot}, ptr ${adapter.commit})`);
|
|
9786
10447
|
B.terminate(`ret ptr ${boxed}`);
|
|
9787
10448
|
});
|
|
9788
10449
|
B.startBlock(fallback);
|
|
@@ -9809,8 +10470,8 @@ class LlEmitter {
|
|
|
9809
10470
|
const nested = this.streamTypedRefMaterializeAdapter(t, ctx);
|
|
9810
10471
|
const rc = vAdapters(this, t);
|
|
9811
10472
|
const key = typeKey(t);
|
|
9812
|
-
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr,
|
|
9813
|
-
B.line(`${boxed} = call ptr @scr_dyn_new_typed_ref(ptr ${value}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${this.cstr(key)},
|
|
10473
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
10474
|
+
B.line(`${boxed} = call ptr @scr_dyn_new_typed_ref(ptr ${value}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${this.cstr(key)}, ${this.sizeType} ${Buffer.byteLength(key, "utf8")}, ptr @${nested.snapshot}, ptr ${nested.commit})`);
|
|
9814
10475
|
return boxed;
|
|
9815
10476
|
}
|
|
9816
10477
|
/** LLVM twin of the C stream materializer: mutable reference children
|
|
@@ -9865,7 +10526,7 @@ class LlEmitter {
|
|
|
9865
10526
|
}
|
|
9866
10527
|
else {
|
|
9867
10528
|
this.declare(`declare ptr @scr_dyn_new_obj()`);
|
|
9868
|
-
this.declare(`declare void @scr_dyn_obj_set(ptr, ptr,
|
|
10529
|
+
this.declare(`declare void @scr_dyn_obj_set(ptr, ptr, ${this.sizeType}, ptr)`);
|
|
9869
10530
|
const out = B.tmp();
|
|
9870
10531
|
B.line(`${out} = call ptr @scr_dyn_new_obj()`);
|
|
9871
10532
|
const byName = new Map(shape.fields.map((field) => [field.name, field]));
|
|
@@ -9887,7 +10548,7 @@ class LlEmitter {
|
|
|
9887
10548
|
fieldValue = boolValue;
|
|
9888
10549
|
}
|
|
9889
10550
|
const boxed = this.streamTypedRefBoxValue(B, field.type, fieldValue, ctx);
|
|
9890
|
-
B.line(`call void @scr_dyn_obj_set(ptr ${out}, ptr ${this.cstr(field.name)},
|
|
10551
|
+
B.line(`call void @scr_dyn_obj_set(ptr ${out}, ptr ${this.cstr(field.name)}, ${this.sizeType} ${Buffer.byteLength(field.name, "utf8")}, ptr ${boxed})`);
|
|
9891
10552
|
}
|
|
9892
10553
|
B.terminate(`ret ptr ${out}`);
|
|
9893
10554
|
}
|
|
@@ -9994,7 +10655,7 @@ class LlEmitter {
|
|
|
9994
10655
|
B.line(`${boxed} = call ptr @${this.dyn.toDynHelper(elem)}(ptr ${value})`);
|
|
9995
10656
|
}
|
|
9996
10657
|
else {
|
|
9997
|
-
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr,
|
|
10658
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
9998
10659
|
const boxedSlot = B.slot();
|
|
9999
10660
|
B.entryAllocas.push(`${boxedSlot} = alloca ptr`);
|
|
10000
10661
|
const tagPtr = B.tmp();
|
|
@@ -10016,7 +10677,7 @@ class LlEmitter {
|
|
|
10016
10677
|
const armBoxed = B.tmp();
|
|
10017
10678
|
B.line(`${payloadPtr} = getelementptr inbounds %ScrUnion, ptr ${value}, i64 0, i32 5`);
|
|
10018
10679
|
B.line(`${payload} = load ptr, ptr ${payloadPtr}`);
|
|
10019
|
-
B.line(`${armBoxed} = call ptr @scr_dyn_new_typed_ref(ptr ${payload}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${this.cstr(armKey)},
|
|
10680
|
+
B.line(`${armBoxed} = call ptr @scr_dyn_new_typed_ref(ptr ${payload}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${this.cstr(armKey)}, ${this.sizeType} ${Buffer.byteLength(armKey, "utf8")}, ptr @${armSnapshot}, ptr ${armCommit})`);
|
|
10020
10681
|
B.line(`store ptr ${armBoxed}, ptr ${boxedSlot}`);
|
|
10021
10682
|
B.br(join);
|
|
10022
10683
|
this.resolveThunkDefs.push(`define internal ptr @${armSnapshot}(ptr %p) ${FN_ATTRS} { ; materialize stream union arm ${armKey}`, `entry:`, ` %d = call ptr @${this.dyn.toDynHelper(arm)}(ptr %p)`, ` ret ptr %d`, `}`, ``);
|
|
@@ -10043,8 +10704,8 @@ class LlEmitter {
|
|
|
10043
10704
|
commit = this.streamTypedRefCommitAdapter(elem, snapshot);
|
|
10044
10705
|
this.resolveThunkDefs.push(`define internal ptr @${snapshot}(ptr %p) ${FN_ATTRS} { ; materialize stream element ${key}`, `entry:`, ` %d = call ptr @${this.dyn.toDynHelper(elem)}(ptr %p)`, ` ret ptr %d`, `}`, ``);
|
|
10045
10706
|
}
|
|
10046
|
-
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr,
|
|
10047
|
-
B.line(`${boxed} = call ptr @scr_dyn_new_typed_ref(ptr ${value}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${keyPtr},
|
|
10707
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
10708
|
+
B.line(`${boxed} = call ptr @scr_dyn_new_typed_ref(ptr ${value}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${keyPtr}, ${this.sizeType} ${Buffer.byteLength(key, "utf8")}, ptr @${snapshot}, ptr ${commit})`);
|
|
10048
10709
|
}
|
|
10049
10710
|
else {
|
|
10050
10711
|
boxed = B.tmp();
|
|
@@ -10785,16 +11446,16 @@ class LlEmitter {
|
|
|
10785
11446
|
const tag6 = infoDef.arms.findIndex((a) => a.kind === "record" && this.recordsById.get(a.shapeId)?.fields.find((f) => f.name === "scopeid")?.type.kind === "f64");
|
|
10786
11447
|
const tag4 = 1 - tag6;
|
|
10787
11448
|
this.declare(`declare ptr @scr_os_ifaddrs()`);
|
|
10788
|
-
this.declare(`declare
|
|
10789
|
-
this.declare(`declare ptr @scr_os_ifaddrs_name(ptr,
|
|
10790
|
-
this.declare(`declare ptr @scr_os_ifaddrs_address(ptr,
|
|
10791
|
-
this.declare(`declare ptr @scr_os_ifaddrs_netmask(ptr,
|
|
10792
|
-
this.declare(`declare ptr @scr_os_ifaddrs_family(ptr,
|
|
10793
|
-
this.declare(`declare ptr @scr_os_ifaddrs_mac(ptr,
|
|
10794
|
-
this.declare(`declare zeroext i1 @scr_os_ifaddrs_internal(ptr,
|
|
10795
|
-
this.declare(`declare zeroext i1 @scr_os_ifaddrs_ipv6(ptr,
|
|
10796
|
-
this.declare(`declare ptr @scr_os_ifaddrs_cidr(ptr,
|
|
10797
|
-
this.declare(`declare double @scr_os_ifaddrs_scopeid(ptr,
|
|
11449
|
+
this.declare(`declare ${this.sizeType} @scr_os_ifaddrs_count(ptr)`);
|
|
11450
|
+
this.declare(`declare ptr @scr_os_ifaddrs_name(ptr, ${this.sizeType})`);
|
|
11451
|
+
this.declare(`declare ptr @scr_os_ifaddrs_address(ptr, ${this.sizeType})`);
|
|
11452
|
+
this.declare(`declare ptr @scr_os_ifaddrs_netmask(ptr, ${this.sizeType})`);
|
|
11453
|
+
this.declare(`declare ptr @scr_os_ifaddrs_family(ptr, ${this.sizeType})`);
|
|
11454
|
+
this.declare(`declare ptr @scr_os_ifaddrs_mac(ptr, ${this.sizeType})`);
|
|
11455
|
+
this.declare(`declare zeroext i1 @scr_os_ifaddrs_internal(ptr, ${this.sizeType})`);
|
|
11456
|
+
this.declare(`declare zeroext i1 @scr_os_ifaddrs_ipv6(ptr, ${this.sizeType})`);
|
|
11457
|
+
this.declare(`declare ptr @scr_os_ifaddrs_cidr(ptr, ${this.sizeType})`);
|
|
11458
|
+
this.declare(`declare double @scr_os_ifaddrs_scopeid(ptr, ${this.sizeType})`);
|
|
10798
11459
|
this.declare(`declare void @scr_os_ifaddrs_free(ptr)`);
|
|
10799
11460
|
this.declare(`declare ptr @scr_union_new_ref(i32, ptr, ptr, ptr, ptr)`);
|
|
10800
11461
|
this.declare(`declare ptr @scr_union_retain_v(ptr)`);
|
|
@@ -10813,11 +11474,11 @@ class LlEmitter {
|
|
|
10813
11474
|
const snap = B.tmp();
|
|
10814
11475
|
const cnt = B.tmp();
|
|
10815
11476
|
B.line(`${snap} = call ptr @scr_os_ifaddrs()`);
|
|
10816
|
-
B.line(`${cnt} = call
|
|
11477
|
+
B.line(`${cnt} = call ${this.sizeType} @scr_os_ifaddrs_count(ptr ${snap})`);
|
|
10817
11478
|
const iSlot = B.slot();
|
|
10818
11479
|
const rowSlot = B.slot();
|
|
10819
|
-
B.entryAllocas.push(`${iSlot} = alloca
|
|
10820
|
-
B.line(`store
|
|
11480
|
+
B.entryAllocas.push(`${iSlot} = alloca ${this.sizeType}`, `${rowSlot} = alloca ptr`);
|
|
11481
|
+
B.line(`store ${this.sizeType} 0, ptr ${iSlot}`);
|
|
10821
11482
|
const lc = B.newLabel("ni.c");
|
|
10822
11483
|
const lb = B.newLabel("ni.b");
|
|
10823
11484
|
const le = B.newLabel("ni.e");
|
|
@@ -10825,12 +11486,12 @@ class LlEmitter {
|
|
|
10825
11486
|
B.startBlock(lc);
|
|
10826
11487
|
const i = B.tmp();
|
|
10827
11488
|
const cont = B.tmp();
|
|
10828
|
-
B.line(`${i} = load
|
|
10829
|
-
B.line(`${cont} = icmp ult
|
|
11489
|
+
B.line(`${i} = load ${this.sizeType}, ptr ${iSlot}`);
|
|
11490
|
+
B.line(`${cont} = icmp ult ${this.sizeType} ${i}, ${cnt}`);
|
|
10830
11491
|
B.condBr(cont, lb, le);
|
|
10831
11492
|
B.startBlock(lb);
|
|
10832
11493
|
const isV6 = B.tmp();
|
|
10833
|
-
B.line(`${isV6} = call zeroext i1 @scr_os_ifaddrs_ipv6(ptr ${snap},
|
|
11494
|
+
B.line(`${isV6} = call zeroext i1 @scr_os_ifaddrs_ipv6(ptr ${snap}, ${this.sizeType} ${i})`);
|
|
10834
11495
|
const l6 = B.newLabel("ni.v6");
|
|
10835
11496
|
const l4 = B.newLabel("ni.v4");
|
|
10836
11497
|
const lRow = B.newLabel("ni.r");
|
|
@@ -10857,14 +11518,14 @@ class LlEmitter {
|
|
|
10857
11518
|
["mac", "scr_os_ifaddrs_mac"],
|
|
10858
11519
|
]) {
|
|
10859
11520
|
const v = B.tmp();
|
|
10860
|
-
B.line(`${v} = call ptr @${sym}(ptr ${snap},
|
|
11521
|
+
B.line(`${v} = call ptr @${sym}(ptr ${snap}, ${this.sizeType} ${i}) ; +1`);
|
|
10861
11522
|
B.line(`store ptr ${v}, ptr ${this.recordFieldPtr(r, t.shapeId, field).ptr}`);
|
|
10862
11523
|
}
|
|
10863
11524
|
const internal = B.tmp();
|
|
10864
|
-
B.line(`${internal} = call zeroext i1 @scr_os_ifaddrs_internal(ptr ${snap},
|
|
11525
|
+
B.line(`${internal} = call zeroext i1 @scr_os_ifaddrs_internal(ptr ${snap}, ${this.sizeType} ${i})`);
|
|
10865
11526
|
this.storeField(this.recordFieldPtr(r, t.shapeId, "internal").ptr, { kind: "bool" }, internal);
|
|
10866
11527
|
const cs = B.tmp();
|
|
10867
|
-
B.line(`${cs} = call ptr @scr_os_ifaddrs_cidr(ptr ${snap},
|
|
11528
|
+
B.line(`${cs} = call ptr @scr_os_ifaddrs_cidr(ptr ${snap}, ${this.sizeType} ${i}) ; +1 or null`);
|
|
10868
11529
|
const hasCidr = B.tmp();
|
|
10869
11530
|
B.line(`${hasCidr} = icmp ne ptr ${cs}, null`);
|
|
10870
11531
|
const lcs = B.newLabel("ni.cs");
|
|
@@ -10889,7 +11550,7 @@ class LlEmitter {
|
|
|
10889
11550
|
B.line(`store ptr ${cv}, ptr ${this.recordFieldPtr(r, t.shapeId, "cidr").ptr}`);
|
|
10890
11551
|
if (v6) {
|
|
10891
11552
|
const sc = B.tmp();
|
|
10892
|
-
B.line(`${sc} = call double @scr_os_ifaddrs_scopeid(ptr ${snap},
|
|
11553
|
+
B.line(`${sc} = call double @scr_os_ifaddrs_scopeid(ptr ${snap}, ${this.sizeType} ${i})`);
|
|
10893
11554
|
this.storeField(this.recordFieldPtr(r, t.shapeId, "scopeid").ptr, F64, sc);
|
|
10894
11555
|
}
|
|
10895
11556
|
else {
|
|
@@ -10915,7 +11576,7 @@ class LlEmitter {
|
|
|
10915
11576
|
const row = B.tmp();
|
|
10916
11577
|
B.line(`${row} = load ptr, ptr ${rowSlot}`);
|
|
10917
11578
|
const nm = B.tmp();
|
|
10918
|
-
B.line(`${nm} = call ptr @scr_os_ifaddrs_name(ptr ${snap},
|
|
11579
|
+
B.line(`${nm} = call ptr @scr_os_ifaddrs_name(ptr ${snap}, ${this.sizeType} ${i}) ; +1`);
|
|
10919
11580
|
const cell = B.tmp();
|
|
10920
11581
|
B.line(`${cell} = call ptr @scr_map_get_str_ref(ptr ${ovf}, ptr ${nm})`);
|
|
10921
11582
|
const hasCell = B.tmp();
|
|
@@ -10951,8 +11612,8 @@ class LlEmitter {
|
|
|
10951
11612
|
B.line(`call void @scr_arr_release(ptr ${rows})`);
|
|
10952
11613
|
B.line(`call void @scr_str_release(ptr ${nm})`);
|
|
10953
11614
|
const i2 = B.tmp();
|
|
10954
|
-
B.line(`${i2} = add
|
|
10955
|
-
B.line(`store
|
|
11615
|
+
B.line(`${i2} = add ${this.sizeType} ${i}, 1`);
|
|
11616
|
+
B.line(`store ${this.sizeType} ${i2}, ptr ${iSlot}`);
|
|
10956
11617
|
B.br(lc);
|
|
10957
11618
|
B.startBlock(le);
|
|
10958
11619
|
B.line(`call void @scr_os_ifaddrs_free(ptr ${snap})`);
|
|
@@ -10969,21 +11630,21 @@ class LlEmitter {
|
|
|
10969
11630
|
const recT = e.type.elem;
|
|
10970
11631
|
const path = this.emitExpr(e.args[0]);
|
|
10971
11632
|
this.declare(`declare ptr @scr_fs_scandir(ptr)`);
|
|
10972
|
-
this.declare(`declare
|
|
10973
|
-
this.declare(`declare ptr @scr_fs_scandir_name(ptr,
|
|
10974
|
-
this.declare(`declare double @scr_fs_scandir_type(ptr,
|
|
11633
|
+
this.declare(`declare ${this.sizeType} @scr_fs_scandir_count(ptr)`);
|
|
11634
|
+
this.declare(`declare ptr @scr_fs_scandir_name(ptr, ${this.sizeType})`);
|
|
11635
|
+
this.declare(`declare double @scr_fs_scandir_type(ptr, ${this.sizeType})`);
|
|
10975
11636
|
this.declare(`declare void @scr_fs_scandir_free(ptr)`);
|
|
10976
11637
|
const snap = B.tmp();
|
|
10977
11638
|
B.line(`${snap} = call ptr @scr_fs_scandir(ptr ${path.name})`);
|
|
10978
11639
|
this.emitPendingCheck();
|
|
10979
11640
|
const cnt = B.tmp();
|
|
10980
|
-
B.line(`${cnt} = call
|
|
11641
|
+
B.line(`${cnt} = call ${this.sizeType} @scr_fs_scandir_count(ptr ${snap})`);
|
|
10981
11642
|
const arr = B.tmp();
|
|
10982
11643
|
B.line(`${arr} = ${arrNewCall(this, recT, cnt)}`);
|
|
10983
11644
|
const out = this.own({ name: arr, type: e.type });
|
|
10984
11645
|
const iSlot = B.slot();
|
|
10985
|
-
B.entryAllocas.push(`${iSlot} = alloca
|
|
10986
|
-
B.line(`store
|
|
11646
|
+
B.entryAllocas.push(`${iSlot} = alloca ${this.sizeType}`);
|
|
11647
|
+
B.line(`store ${this.sizeType} 0, ptr ${iSlot}`);
|
|
10987
11648
|
const lc = B.newLabel("sd.c");
|
|
10988
11649
|
const lb = B.newLabel("sd.b");
|
|
10989
11650
|
const le = B.newLabel("sd.e");
|
|
@@ -10991,23 +11652,23 @@ class LlEmitter {
|
|
|
10991
11652
|
B.startBlock(lc);
|
|
10992
11653
|
const i = B.tmp();
|
|
10993
11654
|
const cont = B.tmp();
|
|
10994
|
-
B.line(`${i} = load
|
|
10995
|
-
B.line(`${cont} = icmp ult
|
|
11655
|
+
B.line(`${i} = load ${this.sizeType}, ptr ${iSlot}`);
|
|
11656
|
+
B.line(`${cont} = icmp ult ${this.sizeType} ${i}, ${cnt}`);
|
|
10996
11657
|
B.condBr(cont, lb, le);
|
|
10997
11658
|
B.startBlock(lb);
|
|
10998
11659
|
const row = B.tmp();
|
|
10999
11660
|
B.line(`${row} = call ptr @${mangleRecordNew(recT.shapeId)}()`);
|
|
11000
11661
|
const dt = B.tmp();
|
|
11001
|
-
B.line(`${dt} = call double @scr_fs_scandir_type(ptr ${snap},
|
|
11662
|
+
B.line(`${dt} = call double @scr_fs_scandir_type(ptr ${snap}, ${this.sizeType} ${i})`);
|
|
11002
11663
|
this.storeField(this.recordFieldPtr(row, recT.shapeId, "%dtype").ptr, F64, dt);
|
|
11003
11664
|
const nm = B.tmp();
|
|
11004
|
-
B.line(`${nm} = call ptr @scr_fs_scandir_name(ptr ${snap},
|
|
11665
|
+
B.line(`${nm} = call ptr @scr_fs_scandir_name(ptr ${snap}, ${this.sizeType} ${i}) ; +1`);
|
|
11005
11666
|
B.line(`store ptr ${nm}, ptr ${this.recordFieldPtr(row, recT.shapeId, "name").ptr}`);
|
|
11006
11667
|
B.line(`store ptr ${this.retainValue(path.name, STRING)}, ptr ${this.recordFieldPtr(row, recT.shapeId, "parentPath").ptr}`);
|
|
11007
11668
|
this.arrPush(arr, "ref", row); // push takes ownership of the row
|
|
11008
11669
|
const i2 = B.tmp();
|
|
11009
|
-
B.line(`${i2} = add
|
|
11010
|
-
B.line(`store
|
|
11670
|
+
B.line(`${i2} = add ${this.sizeType} ${i}, 1`);
|
|
11671
|
+
B.line(`store ${this.sizeType} ${i2}, ptr ${iSlot}`);
|
|
11011
11672
|
B.br(lc);
|
|
11012
11673
|
B.startBlock(le);
|
|
11013
11674
|
B.line(`call void @scr_fs_scandir_free(ptr ${snap})`);
|
|
@@ -11077,22 +11738,19 @@ class LlEmitter {
|
|
|
11077
11738
|
}
|
|
11078
11739
|
if (e.fn === "emitter.emit") {
|
|
11079
11740
|
// The variadic dispatch: the event's unified tuple rides the C
|
|
11080
|
-
// variadic tail POINTER-CLASSED
|
|
11081
|
-
//
|
|
11082
|
-
//
|
|
11741
|
+
// variadic tail POINTER-CLASSED. Scalar values ride pointers to
|
|
11742
|
+
// call-lived stack slots, while reference values ride directly; the
|
|
11743
|
+
// fixed shim can therefore read one pointer-width slot per argument
|
|
11744
|
+
// on both wasm32 and native targets. Every argument is borrowed. May
|
|
11083
11745
|
// throw (listeners run inside).
|
|
11084
11746
|
const args = e.args.map((a) => this.emitExpr(a));
|
|
11085
11747
|
const tuple = args.slice(2).map((a) => {
|
|
11086
11748
|
const ty = this.llType(a.type);
|
|
11087
|
-
if (ty === "double") {
|
|
11088
|
-
const
|
|
11089
|
-
B.
|
|
11090
|
-
|
|
11091
|
-
|
|
11092
|
-
if (ty === "i1") {
|
|
11093
|
-
const x = B.tmp();
|
|
11094
|
-
B.line(`${x} = zext i1 ${a.name} to i64`);
|
|
11095
|
-
return `i64 ${x}`;
|
|
11749
|
+
if (ty === "double" || ty === "i1") {
|
|
11750
|
+
const slot = B.slot();
|
|
11751
|
+
B.entryAllocas.push(`${slot} = alloca ${ty} ; EventEmitter scalar argument`);
|
|
11752
|
+
B.line(`store ${ty} ${a.name}, ptr ${slot}`);
|
|
11753
|
+
return `ptr ${slot}`;
|
|
11096
11754
|
}
|
|
11097
11755
|
return `ptr ${a.name}`;
|
|
11098
11756
|
});
|
|
@@ -11681,13 +12339,13 @@ class LlEmitter {
|
|
|
11681
12339
|
throw new Error("llvm emitter bug: net.serverCloseBind result not a func");
|
|
11682
12340
|
const args = e.args.map((a) => this.emitExpr(a));
|
|
11683
12341
|
const fnSym = this.closeBindThunkFor(e.type.params[0], e.type.ret.kind === "netServer");
|
|
11684
|
-
this.declare(`declare ptr @scr_closure_new(ptr,
|
|
12342
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
11685
12343
|
this.declare(`declare ptr @scr_box_new_obj(ptr, ptr, ptr)`);
|
|
11686
12344
|
this.declare(`declare void @scr_box_set_ref(ptr, ptr)`);
|
|
11687
12345
|
this.declare(`declare ptr @scr_net_server_retain_v(ptr)`);
|
|
11688
12346
|
this.declare(`declare void @scr_net_server_release_v(ptr)`);
|
|
11689
12347
|
const bound = B.tmp();
|
|
11690
|
-
B.line(`${bound} = call ptr @scr_closure_new(ptr @${fnSym},
|
|
12348
|
+
B.line(`${bound} = call ptr @scr_closure_new(ptr @${fnSym}, ${this.sizeType} 1)`);
|
|
11691
12349
|
const bx = B.tmp();
|
|
11692
12350
|
B.line(`${bx} = call ptr @scr_box_new_obj(ptr @scr_net_server_retain_v, ptr @scr_net_server_release_v, ptr null)`);
|
|
11693
12351
|
const capp = B.tmp();
|
|
@@ -11988,22 +12646,22 @@ class LlEmitter {
|
|
|
11988
12646
|
if (ca.type.kind === "string") {
|
|
11989
12647
|
caData = B.tmp();
|
|
11990
12648
|
B.line(`${caLenPtr} = getelementptr inbounds %ScrStr, ptr ${ca.name}, i64 0, i32 1`);
|
|
11991
|
-
B.line(`${caLen} = load
|
|
11992
|
-
B.line(`${caData} = getelementptr inbounds i8, ptr ${ca.name}, i64 24`);
|
|
12649
|
+
B.line(`${caLen} = load ${this.sizeType}, ptr ${caLenPtr}`);
|
|
12650
|
+
B.line(`${caData} = getelementptr inbounds i8, ptr ${ca.name}, i64 ${this.abiOffset(24, 12)}`);
|
|
11993
12651
|
}
|
|
11994
12652
|
else if (ca.type.kind === "bytes" && ca.type.elem === "u8") {
|
|
11995
12653
|
const caDataPtr = B.tmp();
|
|
11996
12654
|
caData = B.tmp();
|
|
11997
|
-
B.line(`${caLenPtr} = getelementptr inbounds i8, ptr ${ca.name}, i64 8`);
|
|
11998
|
-
B.line(`${caLen} = load
|
|
11999
|
-
B.line(`${caDataPtr} = getelementptr inbounds i8, ptr ${ca.name}, i64 24`);
|
|
12655
|
+
B.line(`${caLenPtr} = getelementptr inbounds i8, ptr ${ca.name}, i64 ${this.abiOffset(8, 4)}`);
|
|
12656
|
+
B.line(`${caLen} = load ${this.sizeType}, ptr ${caLenPtr}`);
|
|
12657
|
+
B.line(`${caDataPtr} = getelementptr inbounds i8, ptr ${ca.name}, i64 ${this.abiOffset(24, 12)}`);
|
|
12000
12658
|
B.line(`${caData} = load ptr, ptr ${caDataPtr}`);
|
|
12001
12659
|
}
|
|
12002
12660
|
else {
|
|
12003
12661
|
throw new Error(`llvm emitter bug: ${e.fn} CA is not a string or Buffer`);
|
|
12004
12662
|
}
|
|
12005
|
-
callArgs = [...callArgs.slice(0, 8), `ptr ${caData}`,
|
|
12006
|
-
this.declare(`declare ptr @scr_https_request(ptr, double, ptr, ptr, double, ptr, i1 zeroext, i1 zeroext, ptr,
|
|
12663
|
+
callArgs = [...callArgs.slice(0, 8), `ptr ${caData}`, `${this.sizeType} ${caLen}`];
|
|
12664
|
+
this.declare(`declare ptr @scr_https_request(ptr, double, ptr, ptr, double, ptr, i1 zeroext, i1 zeroext, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
12007
12665
|
}
|
|
12008
12666
|
else {
|
|
12009
12667
|
const decls = head.map((a) => (this.llType(a.type) === "i1" ? "i1 zeroext" : this.llType(a.type)));
|