@scriptc/compiler 0.0.25 → 0.0.26
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 +3 -0
- package/dist/backend/cc.js +37 -4
- 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 +117 -11
- 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 +950 -300
- 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 +152 -5
- package/dist/index.js.map +1 -1
- package/dist/ir/nodes.d.ts +48 -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/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,47 +1494,49 @@ 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);
|
|
@@ -1263,8 +1547,8 @@ class LlEmitter {
|
|
|
1263
1547
|
for (const [text, lit] of this.literals) {
|
|
1264
1548
|
// Immortal interned ScrStr: { rc = SIZE_MAX, len, cap = len, bytes\0 } —
|
|
1265
1549
|
// the C emitter's static table, retain/release skip rc == SIZE_MAX.
|
|
1266
|
-
out.push(`@${lit.sym} = internal global {
|
|
1267
|
-
`{
|
|
1550
|
+
out.push(`@${lit.sym} = internal global { ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, [${lit.len + 1} x i8] } ` +
|
|
1551
|
+
`{ ${this.sizeType} -1, ${this.sizeType} ${lit.len}, ${this.sizeType} ${lit.len}, [${lit.len + 1} x i8] c"${llStrBytes(text)}" }`);
|
|
1268
1552
|
}
|
|
1269
1553
|
if (this.literals.size > 0)
|
|
1270
1554
|
out.push(``);
|
|
@@ -1273,7 +1557,7 @@ class LlEmitter {
|
|
|
1273
1557
|
// slot and RC entry points zero — retain/release/collector all skip
|
|
1274
1558
|
// rc == SIZE_MAX, so these never join the RC audit or a trace walk.
|
|
1275
1559
|
const [unionId, tag] = key.split(":");
|
|
1276
|
-
out.push(`@${sym} = internal global %ScrUnion {
|
|
1560
|
+
out.push(`@${sym} = internal global %ScrUnion { ${this.sizeType} -1, i32 ${tag}, ptr null, ptr null, ptr null, i64 0 } ; ${unionId} unit arm`);
|
|
1277
1561
|
}
|
|
1278
1562
|
if (this.unitInstances.size > 0)
|
|
1279
1563
|
out.push(``);
|
|
@@ -1281,7 +1565,7 @@ class LlEmitter {
|
|
|
1281
1565
|
// One immortal ScrRegex per (pattern, flags) literal, pointing at
|
|
1282
1566
|
// the interned source/flags strings. The bc slot starts null (lazy
|
|
1283
1567
|
// compile, cached by the runtime) — a mutable global, not constant.
|
|
1284
|
-
out.push(`@${re.sym} = internal global %ScrRegex {
|
|
1568
|
+
out.push(`@${re.sym} = internal global %ScrRegex { ${this.sizeType} -1, ptr ${re.src}, ptr ${re.fl}, ptr null } ; ${key.replace(/\n/g, "\\n")}`);
|
|
1285
1569
|
}
|
|
1286
1570
|
if (this.regexInstances.size > 0)
|
|
1287
1571
|
out.push(``);
|
|
@@ -1291,7 +1575,7 @@ class LlEmitter {
|
|
|
1291
1575
|
// over it (rc == SIZE_MAX, len == cap, SCR_ELEM_STR = 2, no REF
|
|
1292
1576
|
// entry points). Reads retain immortal strings — a no-op.
|
|
1293
1577
|
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 {
|
|
1578
|
+
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
1579
|
}
|
|
1296
1580
|
if (this.templateStringsInstances.size > 0)
|
|
1297
1581
|
out.push(``);
|
|
@@ -1302,6 +1586,43 @@ class LlEmitter {
|
|
|
1302
1586
|
}
|
|
1303
1587
|
if (this.cstrs.size > 0)
|
|
1304
1588
|
out.push(``);
|
|
1589
|
+
if (usesIsland) {
|
|
1590
|
+
const fmt = { esm: 0, cjs: 1, json: 2 };
|
|
1591
|
+
const edgeKind = { any: 0, import: 1, require: 2 };
|
|
1592
|
+
embedded.modules.forEach((m, i) => {
|
|
1593
|
+
const stored = npmStored[i];
|
|
1594
|
+
const key = Buffer.from(m.key, "utf8");
|
|
1595
|
+
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)}"`);
|
|
1596
|
+
if (stored.esm !== null) {
|
|
1597
|
+
out.push(`@sc_npm_esm_${i} = internal constant [${stored.esm.bytes.length + 1} x i8] c"${llBytes(stored.esm.bytes)}"`);
|
|
1598
|
+
}
|
|
1599
|
+
});
|
|
1600
|
+
const moduleRows = embedded.modules.map((m, i) => {
|
|
1601
|
+
const stored = npmStored[i];
|
|
1602
|
+
const esm = stored.esm === null
|
|
1603
|
+
? `ptr null, ${this.sizeType} 0, ${this.sizeType} 0`
|
|
1604
|
+
: `ptr @sc_npm_esm_${i}, ${this.sizeType} ${stored.esm.bytes.length}, ${this.sizeType} ${stored.esm.raw}`;
|
|
1605
|
+
return `%ScrIslandModule { ptr @sc_npm_key_${i}, ptr @sc_npm_src_${i}, ` +
|
|
1606
|
+
`${this.sizeType} ${stored.src.bytes.length}, ${this.sizeType} ${stored.src.raw}, ` +
|
|
1607
|
+
`i32 ${fmt[m.format]}, ${esm} }`;
|
|
1608
|
+
});
|
|
1609
|
+
out.push(`@sc_npm_modules = internal constant [${moduleRows.length} x %ScrIslandModule] [ ${moduleRows.join(", ")} ]`);
|
|
1610
|
+
embedded.edges.forEach((edge, i) => {
|
|
1611
|
+
for (const [part, text] of [["from", edge.from], ["spec", edge.specifier], ["to", edge.to]]) {
|
|
1612
|
+
const bytes = Buffer.from(text, "utf8");
|
|
1613
|
+
out.push(`@sc_npm_edge_${i}_${part} = internal constant [${bytes.length + 1} x i8] c"${llBytes(bytes)}"`);
|
|
1614
|
+
}
|
|
1615
|
+
});
|
|
1616
|
+
if (embedded.edges.length > 0) {
|
|
1617
|
+
const edgeRows = embedded.edges.map((edge, i) => `%ScrIslandEdge { ptr @sc_npm_edge_${i}_from, ptr @sc_npm_edge_${i}_spec, ` +
|
|
1618
|
+
`ptr @sc_npm_edge_${i}_to, i32 ${edgeKind[edge.kind]} }`);
|
|
1619
|
+
out.push(`@sc_npm_edges = internal constant [${edgeRows.length} x %ScrIslandEdge] [ ${edgeRows.join(", ")} ]`);
|
|
1620
|
+
}
|
|
1621
|
+
out.push(``);
|
|
1622
|
+
}
|
|
1623
|
+
out.push(...ffiCallbacks.globals);
|
|
1624
|
+
if (ffiCallbacks.globals.length > 0)
|
|
1625
|
+
out.push(``);
|
|
1305
1626
|
for (const g of globals) {
|
|
1306
1627
|
const ty = this.llType(g.type);
|
|
1307
1628
|
const zero = ty === "double" ? f64Lit(0) : ty === "ptr" ? "null" : "false";
|
|
@@ -1310,6 +1631,7 @@ class LlEmitter {
|
|
|
1310
1631
|
if (globals.length > 0)
|
|
1311
1632
|
out.push(``);
|
|
1312
1633
|
out.push(...helpers);
|
|
1634
|
+
out.push(...ffiCallbacks.defs);
|
|
1313
1635
|
out.push(...shapes.defs);
|
|
1314
1636
|
out.push(...classShapes.defs);
|
|
1315
1637
|
out.push(...classObjDefs);
|
|
@@ -1327,7 +1649,7 @@ class LlEmitter {
|
|
|
1327
1649
|
const stamps = [];
|
|
1328
1650
|
for (const iv of this.errorIntervals) {
|
|
1329
1651
|
for (const [field, value] of [[0, iv.pre], [1, iv.post]]) {
|
|
1330
|
-
stamps.push(` store
|
|
1652
|
+
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
1653
|
}
|
|
1332
1654
|
}
|
|
1333
1655
|
if (this.emitterInterval !== null) {
|
|
@@ -1335,14 +1657,14 @@ class LlEmitter {
|
|
|
1335
1657
|
// EventEmitter instances answer instanceof and dispatch dynamic
|
|
1336
1658
|
// teardown under THIS module's preorder numbering.
|
|
1337
1659
|
out.push(`@scr_emitter_vt = external global %ScrVt`, ``);
|
|
1338
|
-
stamps.push(` store
|
|
1660
|
+
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
1661
|
}
|
|
1340
1662
|
for (const iv of this.streamIntervals) {
|
|
1341
1663
|
// The runtime stream vtables' intervals (streamVtStampLines) — the
|
|
1342
1664
|
// emitter story: instanceof and dynamic teardown dispatch through
|
|
1343
1665
|
// them.
|
|
1344
1666
|
out.push(`@${iv.vt} = external global %ScrVt`);
|
|
1345
|
-
stamps.push(` store
|
|
1667
|
+
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
1668
|
}
|
|
1347
1669
|
if (this.streamIntervals.length > 0)
|
|
1348
1670
|
out.push(``);
|
|
@@ -1366,17 +1688,28 @@ class LlEmitter {
|
|
|
1366
1688
|
// LIBRARY mode: no @main — the profile-declared external
|
|
1367
1689
|
// symbols instead, from the same IR facts the C emission consumes.
|
|
1368
1690
|
out.push(...this.emitLibDefs(globals, globalReleaseLines, stamps));
|
|
1369
|
-
out.push(`attributes #0 = { sanitize_address }
|
|
1691
|
+
out.push(`attributes #0 = { sanitize_address }`);
|
|
1692
|
+
if (this.wasi)
|
|
1693
|
+
out.push(`attributes #1 = { sanitize_address presplitcoroutine }`);
|
|
1694
|
+
out.push(``);
|
|
1370
1695
|
return out.join("\n");
|
|
1371
1696
|
}
|
|
1372
|
-
out.push(`define i32
|
|
1697
|
+
out.push(`define i32 @${this.wasi ? "__main_argc_argv" : "main"}(i32 %argc, ptr %argv) ${FN_ATTRS} {`, `entry:`, ` call void @scr_init()`, ...stamps,
|
|
1373
1698
|
// Event-surface programs (signal/exit listeners) fill the loop's
|
|
1374
1699
|
// nullable event hooks before %main — scr_events.c links only when
|
|
1375
1700
|
// this line is emitted (cc.ts gates on the same predicate).
|
|
1376
1701
|
...(usesEvents ? [` call void @scr_events_install()`] : []),
|
|
1377
1702
|
// fs.watch programs fill the loop's watch hooks the same way —
|
|
1378
1703
|
// 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)`, ...(
|
|
1704
|
+
...(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
|
|
1705
|
+
? [
|
|
1706
|
+
...(moduleEmbedsCompressedNpm(this.mod)
|
|
1707
|
+
? [` call void @scr_island_set_inflate(ptr @scr_zlib_inflate_exact)`]
|
|
1708
|
+
: []),
|
|
1709
|
+
` call void @scr_island_modules(ptr @sc_npm_modules, ${this.sizeType} ${embedded.modules.length}, ` +
|
|
1710
|
+
`ptr ${embedded.edges.length > 0 ? "@sc_npm_edges" : "null"}, ${this.sizeType} ${embedded.edges.length})`,
|
|
1711
|
+
]
|
|
1712
|
+
: []), ...(asyncEntry
|
|
1380
1713
|
? [` %top = call ptr @${mangleAsyncSpawn(this.mod.entry)}()`]
|
|
1381
1714
|
: [` call void @${mangleFunction(this.mod.entry)}()`]),
|
|
1382
1715
|
// Uncaught exception from top-level code: Node exits 1.
|
|
@@ -1447,18 +1780,20 @@ class LlEmitter {
|
|
|
1447
1780
|
` %tla_pending = icmp eq i32 %tla_status, 13`,
|
|
1448
1781
|
` br i1 %tla_pending, label %tla_stuck, label %tla_ok`,
|
|
1449
1782
|
`tla_stuck:`,
|
|
1450
|
-
...
|
|
1451
|
-
...topPendingReleases,
|
|
1452
|
-
` ret i32 13`,
|
|
1783
|
+
...topPendingExitLines(),
|
|
1453
1784
|
`tla_ok:`,
|
|
1454
1785
|
]
|
|
1455
1786
|
: []),
|
|
1456
1787
|
]
|
|
1457
|
-
: []), ...exitListenerLines("xn"), ...globalReleases,
|
|
1788
|
+
: []), ...exitListenerLines("xn"), ...globalReleases, ...(usesNodeTest
|
|
1789
|
+
? [` %test_exit = call i32 @scr_test_exit_code()`, ` ret i32 %test_exit`]
|
|
1790
|
+
: usesIsland
|
|
1791
|
+
? [` %island_exit = call i32 @scr_island_exit_code()`, ` ret i32 %island_exit`]
|
|
1792
|
+
: [` ret i32 0`]), `}`, ``,
|
|
1458
1793
|
// sanitize_address is inert under the plain pipeline; the sanitized
|
|
1459
1794
|
// lane's -fsanitize=address link activates instrumentation over the
|
|
1460
1795
|
// emitted functions too (the runtime TUs get theirs from clang).
|
|
1461
|
-
`attributes #0 = { sanitize_address }`, ``);
|
|
1796
|
+
`attributes #0 = { sanitize_address }`, ...(this.wasi ? [`attributes #1 = { sanitize_address presplitcoroutine }`] : []), ``);
|
|
1462
1797
|
return out.join("\n");
|
|
1463
1798
|
}
|
|
1464
1799
|
/** LIBRARY mode: the profile-declared external definitions — the
|
|
@@ -1510,7 +1845,7 @@ class LlEmitter {
|
|
|
1510
1845
|
});
|
|
1511
1846
|
out.push(ovlCells.length === 0
|
|
1512
1847
|
? `@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
|
|
1848
|
+
: `@scr_library_trap_overlays = constant [${ovlCells.length} x ptr] [${ovlCells.join(", ")}]`, `@scr_library_trap_overlays_len = constant ${this.sizeType} ${lib.trapOverlays.length}`, ``);
|
|
1514
1849
|
// The init entry: full deterministic reset-and-reevaluate. Program
|
|
1515
1850
|
// globals release and zero first (run-once guards included), then the
|
|
1516
1851
|
// runtime session reset, the error-vt interval stamps verbatim from
|
|
@@ -1596,13 +1931,13 @@ class LlEmitter {
|
|
|
1596
1931
|
args.push(`double %c${i}`);
|
|
1597
1932
|
break;
|
|
1598
1933
|
case "string":
|
|
1599
|
-
params.push(`ptr %a${i}_ptr`,
|
|
1600
|
-
body.push(` %c${i} = call ptr @scr_library_str_in(ptr %a${i}_ptr,
|
|
1934
|
+
params.push(`ptr %a${i}_ptr`, `${this.sizeType} %a${i}_len`);
|
|
1935
|
+
body.push(` %c${i} = call ptr @scr_library_str_in(ptr %a${i}_ptr, ${this.sizeType} %a${i}_len)`);
|
|
1601
1936
|
args.push(`ptr %c${i}`);
|
|
1602
1937
|
break;
|
|
1603
1938
|
case "bytes":
|
|
1604
|
-
params.push(`ptr %a${i}_ptr`,
|
|
1605
|
-
body.push(` %c${i} = call ptr @scr_library_bytes_in(ptr %a${i}_ptr,
|
|
1939
|
+
params.push(`ptr %a${i}_ptr`, `${this.sizeType} %a${i}_len`);
|
|
1940
|
+
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
1941
|
args.push(`ptr %c${i}`);
|
|
1607
1942
|
break;
|
|
1608
1943
|
}
|
|
@@ -1676,7 +2011,7 @@ class LlEmitter {
|
|
|
1676
2011
|
// scr_box_retain is a static inline (increment-unless-immortal, then
|
|
1677
2012
|
// mark the cycle header live — every box is collector-headered);
|
|
1678
2013
|
// 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
|
|
2014
|
+
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
2015
|
}
|
|
1681
2016
|
// The declarations these helpers added must land in the extern block,
|
|
1682
2017
|
// which already flushed — append here instead (LLVM is order-free).
|
|
@@ -1696,7 +2031,7 @@ class LlEmitter {
|
|
|
1696
2031
|
// never the inner return type.
|
|
1697
2032
|
const ret = fn.async === true || fn.generator !== undefined ? "ptr" : this.llType(fn.returnType);
|
|
1698
2033
|
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 {
|
|
2034
|
+
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
2035
|
}
|
|
1701
2036
|
return out;
|
|
1702
2037
|
}
|
|
@@ -1709,6 +2044,11 @@ class LlEmitter {
|
|
|
1709
2044
|
* fiber eagerly to its first suspension and returns the promise). */
|
|
1710
2045
|
emitAsyncScaffolding() {
|
|
1711
2046
|
const out = [];
|
|
2047
|
+
if (this.wasi) {
|
|
2048
|
+
this.declare(`declare void @llvm.coro.resume(ptr)`);
|
|
2049
|
+
this.declare(`declare void @llvm.coro.destroy(ptr)`);
|
|
2050
|
+
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`, `}`, ``);
|
|
2051
|
+
}
|
|
1712
2052
|
for (const fn of this.mod.functions) {
|
|
1713
2053
|
if (fn.async !== true)
|
|
1714
2054
|
continue;
|
|
@@ -1716,9 +2056,9 @@ class LlEmitter {
|
|
|
1716
2056
|
const lifted = fn.captures !== undefined;
|
|
1717
2057
|
const fieldTys = [...(lifted ? ["ptr"] : []), ...fn.params.map((p) => this.llType(p.type))];
|
|
1718
2058
|
out.push(`%${pack} = type { ${fieldTys.join(", ") || "i8"} } ; ${fn.name} args`);
|
|
1719
|
-
const sizeOf = `ptrtoint (ptr getelementptr (%${pack}, ptr null, i32 1) to
|
|
2059
|
+
const sizeOf = `ptrtoint (ptr getelementptr (%${pack}, ptr null, i32 1) to ${this.sizeType})`;
|
|
1720
2060
|
this.declare(`declare void @free(ptr)`);
|
|
1721
|
-
this.declare(`declare ptr @malloc(
|
|
2061
|
+
this.declare(`declare ptr @malloc(${this.sizeType})`);
|
|
1722
2062
|
this.declare(`declare zeroext i1 @scr_exc_pending()`);
|
|
1723
2063
|
this.declare(`declare ptr @scr_fiber_promise(ptr)`);
|
|
1724
2064
|
this.declare(`declare ptr @scr_async_spawn(ptr, ptr)`);
|
|
@@ -1738,41 +2078,49 @@ class LlEmitter {
|
|
|
1738
2078
|
const retTy = this.llType(ret);
|
|
1739
2079
|
const bodyCall = `call ${retTy} @${mangleFunction(fn.name)}(${loads.join(", ")})`;
|
|
1740
2080
|
tr.push(retTy === "void" ? ` ${bodyCall}` : ` %r = ${bodyCall}`);
|
|
1741
|
-
if (
|
|
1742
|
-
|
|
1743
|
-
|
|
2081
|
+
if (this.wasi) {
|
|
2082
|
+
// The coroutine body settles its own promise and owns the retained
|
|
2083
|
+
// lifted environment until final suspension. Its initial call
|
|
2084
|
+
// returns here at the first suspend (or final suspend).
|
|
2085
|
+
tr.push(` ret void`, `}`, ``);
|
|
1744
2086
|
}
|
|
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)})`);
|
|
2087
|
+
else {
|
|
2088
|
+
if (lifted) {
|
|
2089
|
+
this.declare(`declare void @scr_closure_release(ptr)`);
|
|
2090
|
+
tr.push(` call void @scr_closure_release(ptr %a0)`);
|
|
1768
2091
|
}
|
|
2092
|
+
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)`);
|
|
2093
|
+
switch (ret.kind) {
|
|
2094
|
+
case "void":
|
|
2095
|
+
this.declare(`declare void @scr_promise_fulfill_void(ptr)`);
|
|
2096
|
+
tr.push(` call void @scr_promise_fulfill_void(ptr %pr)`);
|
|
2097
|
+
break;
|
|
2098
|
+
case "f64":
|
|
2099
|
+
case "date":
|
|
2100
|
+
this.declare(`declare void @scr_promise_fulfill_f64(ptr, double)`);
|
|
2101
|
+
tr.push(` call void @scr_promise_fulfill_f64(ptr %pr, double %r)`);
|
|
2102
|
+
break;
|
|
2103
|
+
case "bool":
|
|
2104
|
+
this.declare(`declare void @scr_promise_fulfill_bool(ptr, i1 zeroext)`);
|
|
2105
|
+
tr.push(` call void @scr_promise_fulfill_bool(ptr %pr, i1 %r)`);
|
|
2106
|
+
break;
|
|
2107
|
+
case "string":
|
|
2108
|
+
this.declare(`declare void @scr_promise_fulfill_str(ptr, ptr)`);
|
|
2109
|
+
tr.push(` call void @scr_promise_fulfill_str(ptr %pr, ptr %r) ; moves in`);
|
|
2110
|
+
break;
|
|
2111
|
+
default: {
|
|
2112
|
+
const v = vAdapters(this, ret);
|
|
2113
|
+
this.declare(`declare void @scr_promise_fulfill_ref(ptr, ptr, ptr, ptr, ptr)`);
|
|
2114
|
+
tr.push(` call void @scr_promise_fulfill_ref(ptr %pr, ptr %r, ptr ${v.retain}, ptr ${v.release}, ptr ${traceArg(this, ret)})`);
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
tr.push(` ret void`, `thrown:`);
|
|
2118
|
+
if (ret.kind !== "void" && isRefCounted(ret)) {
|
|
2119
|
+
// An escaping throw means %r is the never-read dummy (NULL).
|
|
2120
|
+
tr.push(` call void ${releaseSym(this, ret)}(ptr %r)`);
|
|
2121
|
+
}
|
|
2122
|
+
tr.push(` ret void`, `}`, ``);
|
|
1769
2123
|
}
|
|
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
2124
|
out.push(...tr);
|
|
1777
2125
|
// Spawn wrapper: pack the args (+1 moves in), spawn the fiber.
|
|
1778
2126
|
const params = fieldTys.map((ty, i) => `${ty} %a${i}`);
|
|
@@ -1799,7 +2147,7 @@ class LlEmitter {
|
|
|
1799
2147
|
`cache_miss:`,
|
|
1800
2148
|
]
|
|
1801
2149
|
: []),
|
|
1802
|
-
` %ap = call ptr @malloc(
|
|
2150
|
+
` %ap = call ptr @malloc(${this.sizeType} ${sizeOf})`,
|
|
1803
2151
|
` %isnull = icmp eq ptr %ap, null`,
|
|
1804
2152
|
` br i1 %isnull, label %oom, label %ok`,
|
|
1805
2153
|
`oom:`,
|
|
@@ -1867,9 +2215,9 @@ class LlEmitter {
|
|
|
1867
2215
|
const lifted = fn.captures !== undefined;
|
|
1868
2216
|
const fieldTys = [...(lifted ? ["ptr"] : []), ...fn.params.map((p) => this.llType(p.type))];
|
|
1869
2217
|
out.push(`%${pack} = type { ${fieldTys.join(", ") || "i8"} } ; ${fn.name} args`);
|
|
1870
|
-
const sizeOf = `ptrtoint (ptr getelementptr (%${pack}, ptr null, i32 1) to
|
|
2218
|
+
const sizeOf = `ptrtoint (ptr getelementptr (%${pack}, ptr null, i32 1) to ${this.sizeType})`;
|
|
1871
2219
|
this.declare(`declare void @free(ptr)`);
|
|
1872
|
-
this.declare(`declare ptr @malloc(
|
|
2220
|
+
this.declare(`declare ptr @malloc(${this.sizeType})`);
|
|
1873
2221
|
this.declare(`declare zeroext i1 @scr_exc_pending()`);
|
|
1874
2222
|
this.declare(`declare zeroext i1 @scr_exc_genret_pending()`);
|
|
1875
2223
|
this.declare(`declare void @scr_exc_clear()`);
|
|
@@ -1891,7 +2239,7 @@ class LlEmitter {
|
|
|
1891
2239
|
const retTy = this.llType(ret);
|
|
1892
2240
|
const bodyCall = `call ${retTy} @${mangleFunction(fn.name)}(${loads.join(", ")})`;
|
|
1893
2241
|
tr.push(retTy === "void" ? ` ${bodyCall}` : ` %r = ${bodyCall}`);
|
|
1894
|
-
if (lifted) {
|
|
2242
|
+
if (lifted && !this.wasi) {
|
|
1895
2243
|
this.declare(`declare void @scr_closure_release(ptr)`);
|
|
1896
2244
|
tr.push(` call void @scr_closure_release(ptr %a0)`);
|
|
1897
2245
|
}
|
|
@@ -1899,31 +2247,36 @@ class LlEmitter {
|
|
|
1899
2247
|
// with the NONE slot — JS's undefined done-value. A GENRET unwind
|
|
1900
2248
|
// consumes the sentinel and promotes the parked .return value; a
|
|
1901
2249
|
// 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
|
-
}
|
|
2250
|
+
if (this.wasi) {
|
|
2251
|
+
tr.push(` ret void`, `}`, ``);
|
|
1921
2252
|
}
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2253
|
+
else {
|
|
2254
|
+
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:`);
|
|
2255
|
+
switch (ret.kind) {
|
|
2256
|
+
case "void":
|
|
2257
|
+
tr.push(` br label %done ; void body: the done value is undefined (NONE)`);
|
|
2258
|
+
break;
|
|
2259
|
+
case "f64":
|
|
2260
|
+
case "date":
|
|
2261
|
+
this.declare(`declare void @scr_gen_out_f64(ptr, double)`);
|
|
2262
|
+
tr.push(` call void @scr_gen_out_f64(ptr %g, double %r)`, ` br label %done`);
|
|
2263
|
+
break;
|
|
2264
|
+
case "bool":
|
|
2265
|
+
this.declare(`declare void @scr_gen_out_bool(ptr, i1 zeroext)`);
|
|
2266
|
+
tr.push(` call void @scr_gen_out_bool(ptr %g, i1 %r)`, ` br label %done`);
|
|
2267
|
+
break;
|
|
2268
|
+
default: {
|
|
2269
|
+
const v = vAdapters(this, ret);
|
|
2270
|
+
this.declare(`declare void @scr_gen_out_ref(ptr, ptr, ptr)`);
|
|
2271
|
+
tr.push(` call void @scr_gen_out_ref(ptr %g, ptr %r, ptr ${v.release})`, ` br label %done`);
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
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:`);
|
|
2275
|
+
if (ret.kind !== "void" && isRefCounted(ret)) {
|
|
2276
|
+
tr.push(` call void ${releaseSym(this, ret)}(ptr %r) ; unwound: the never-read dummy`);
|
|
2277
|
+
}
|
|
2278
|
+
tr.push(` br label %done`, `done:`, ` ret void`, `}`, ``);
|
|
1925
2279
|
}
|
|
1926
|
-
tr.push(` br label %done`, `done:`, ` ret void`, `}`, ``);
|
|
1927
2280
|
out.push(...tr);
|
|
1928
2281
|
// The never-started teardown: drop the packed (+1) arguments.
|
|
1929
2282
|
const dr = [
|
|
@@ -1952,7 +2305,7 @@ class LlEmitter {
|
|
|
1952
2305
|
const sp = [
|
|
1953
2306
|
`define internal ptr @${mangleGenSpawn(fn.name)}(${params.join(", ")}) ${FN_ATTRS} { ; gen spawn ${fn.name}`,
|
|
1954
2307
|
`entry:`,
|
|
1955
|
-
` %ap = call ptr @malloc(
|
|
2308
|
+
` %ap = call ptr @malloc(${this.sizeType} ${sizeOf})`,
|
|
1956
2309
|
` %isnull = icmp eq ptr %ap, null`,
|
|
1957
2310
|
` br i1 %isnull, label %oom, label %ok`,
|
|
1958
2311
|
`oom:`,
|
|
@@ -2124,6 +2477,10 @@ class LlEmitter {
|
|
|
2124
2477
|
return;
|
|
2125
2478
|
}
|
|
2126
2479
|
this.releaseForJump(0, 0);
|
|
2480
|
+
if (this.currentWasiCoro !== null) {
|
|
2481
|
+
this.B.terminate(`br label %${this.currentWasiCoro.finalLabel}`);
|
|
2482
|
+
return;
|
|
2483
|
+
}
|
|
2127
2484
|
const t = this.currentReturnType;
|
|
2128
2485
|
if (t.kind === "void")
|
|
2129
2486
|
this.B.terminate("ret void");
|
|
@@ -2207,8 +2564,8 @@ class LlEmitter {
|
|
|
2207
2564
|
const len = B.tmp();
|
|
2208
2565
|
const t = B.tmp();
|
|
2209
2566
|
B.line(`${lenp} = getelementptr inbounds %ScrStr, ptr ${v.name}, i64 0, i32 1`);
|
|
2210
|
-
B.line(`${len} = load
|
|
2211
|
-
B.line(`${t} = icmp ne
|
|
2567
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenp}`);
|
|
2568
|
+
B.line(`${t} = icmp ne ${this.sizeType} ${len}, 0`);
|
|
2212
2569
|
return t;
|
|
2213
2570
|
}
|
|
2214
2571
|
case "date":
|
|
@@ -2303,8 +2660,8 @@ class LlEmitter {
|
|
|
2303
2660
|
const len = B.tmp();
|
|
2304
2661
|
const t = B.tmp();
|
|
2305
2662
|
B.line(`${lenp} = getelementptr inbounds %ScrStr, ptr ${p}, i64 0, i32 1`);
|
|
2306
|
-
B.line(`${len} = load
|
|
2307
|
-
B.line(`${t} = icmp ne
|
|
2663
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenp}`);
|
|
2664
|
+
B.line(`${t} = icmp ne ${this.sizeType} ${len}, 0`);
|
|
2308
2665
|
B.line(`store i1 ${t}, ptr ${slot}`);
|
|
2309
2666
|
break;
|
|
2310
2667
|
}
|
|
@@ -2459,7 +2816,7 @@ class LlEmitter {
|
|
|
2459
2816
|
B.line(`${vtp} = getelementptr inbounds %${classStructSym(staticClassName)}, ptr ${objName}, i64 0, i32 1`);
|
|
2460
2817
|
B.line(`${vt} = load ptr, ptr ${vtp}`);
|
|
2461
2818
|
B.line(`${prep} = getelementptr inbounds %ScrVt, ptr ${vt}, i64 0, i32 0`);
|
|
2462
|
-
B.line(`${pre} = load
|
|
2819
|
+
B.line(`${pre} = load ${this.sizeType}, ptr ${prep}`);
|
|
2463
2820
|
return pre;
|
|
2464
2821
|
}
|
|
2465
2822
|
/** The class object's static symbol (classes as values), registering it
|
|
@@ -2652,6 +3009,93 @@ class LlEmitter {
|
|
|
2652
3009
|
return mangleGenSpawn(fnName);
|
|
2653
3010
|
return mangleFunction(fnName);
|
|
2654
3011
|
}
|
|
3012
|
+
/** Queue the current wasm coroutine and suspend it. The runtime decides
|
|
3013
|
+
* whether the promise waiter list or the ready FIFO owns the continuation;
|
|
3014
|
+
* LLVM keeps all live locals in the coroutine frame. */
|
|
3015
|
+
emitWasiSuspend(promise) {
|
|
3016
|
+
const coro = this.currentWasiCoro;
|
|
3017
|
+
if (coro === null)
|
|
3018
|
+
throw new Error("llvm emitter bug: wasm suspension outside async body");
|
|
3019
|
+
if (promise === null) {
|
|
3020
|
+
this.declare(`declare void @scr_wasi_await_hop_prepare(ptr)`);
|
|
3021
|
+
this.B.line(`call void @scr_wasi_await_hop_prepare(ptr ${coro.self})`);
|
|
3022
|
+
}
|
|
3023
|
+
else {
|
|
3024
|
+
this.declare(`declare void @scr_wasi_await_prepare(ptr, ptr)`);
|
|
3025
|
+
this.B.line(`call void @scr_wasi_await_prepare(ptr ${coro.self}, ptr ${promise})`);
|
|
3026
|
+
}
|
|
3027
|
+
this.emitWasiSuspendPrepared();
|
|
3028
|
+
}
|
|
3029
|
+
/** Suspend after a target-specific runtime helper already queued the
|
|
3030
|
+
* continuation (used by module awaits, which skip the hop when settled). */
|
|
3031
|
+
emitWasiSuspendPrepared() {
|
|
3032
|
+
const coro = this.currentWasiCoro;
|
|
3033
|
+
if (coro === null)
|
|
3034
|
+
throw new Error("llvm emitter bug: wasm suspension outside async body");
|
|
3035
|
+
const save = this.B.tmp();
|
|
3036
|
+
const state = this.B.tmp();
|
|
3037
|
+
const resume = this.B.newLabel("coro.resume");
|
|
3038
|
+
this.B.line(`${save} = call token @llvm.coro.save(ptr ${coro.handle})`);
|
|
3039
|
+
this.B.line(`${state} = call i8 @llvm.coro.suspend(token ${save}, i1 false)`);
|
|
3040
|
+
this.B.terminate(`switch i8 ${state}, label %${coro.suspendLabel} [ i8 0, label %${resume} i8 1, label %${coro.cleanupLabel} ]`);
|
|
3041
|
+
this.B.startBlock(resume);
|
|
3042
|
+
}
|
|
3043
|
+
/** Move a clean async return value into the current fiber's promise. */
|
|
3044
|
+
emitWasiFulfill(v) {
|
|
3045
|
+
const coro = this.currentWasiCoro;
|
|
3046
|
+
if (coro === null)
|
|
3047
|
+
throw new Error("llvm emitter bug: wasm fulfillment outside async body");
|
|
3048
|
+
const ret = this.currentReturnType;
|
|
3049
|
+
if (coro.kind === "generator") {
|
|
3050
|
+
this.declare(`declare ptr @scr_gen_of_fiber(ptr)`);
|
|
3051
|
+
const gen = this.B.tmp();
|
|
3052
|
+
this.B.line(`${gen} = call ptr @scr_gen_of_fiber(ptr ${coro.self})`);
|
|
3053
|
+
switch (ret.kind) {
|
|
3054
|
+
case "void":
|
|
3055
|
+
return;
|
|
3056
|
+
case "f64":
|
|
3057
|
+
case "date":
|
|
3058
|
+
this.declare(`declare void @scr_gen_out_f64(ptr, double)`);
|
|
3059
|
+
this.B.line(`call void @scr_gen_out_f64(ptr ${gen}, double ${v.name})`);
|
|
3060
|
+
return;
|
|
3061
|
+
case "bool":
|
|
3062
|
+
this.declare(`declare void @scr_gen_out_bool(ptr, i1 zeroext)`);
|
|
3063
|
+
this.B.line(`call void @scr_gen_out_bool(ptr ${gen}, i1 ${v.name})`);
|
|
3064
|
+
return;
|
|
3065
|
+
default:
|
|
3066
|
+
this.declare(`declare void @scr_gen_out_ref(ptr, ptr, ptr)`);
|
|
3067
|
+
this.B.line(`call void @scr_gen_out_ref(ptr ${gen}, ptr ${v.name}, ptr ${vAdapters(this, ret).release})`);
|
|
3068
|
+
return;
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
this.declare(`declare ptr @scr_fiber_promise(ptr)`);
|
|
3072
|
+
const pr = this.B.tmp();
|
|
3073
|
+
this.B.line(`${pr} = call ptr @scr_fiber_promise(ptr ${coro.self})`);
|
|
3074
|
+
switch (ret.kind) {
|
|
3075
|
+
case "void":
|
|
3076
|
+
this.declare(`declare void @scr_promise_fulfill_void(ptr)`);
|
|
3077
|
+
this.B.line(`call void @scr_promise_fulfill_void(ptr ${pr})`);
|
|
3078
|
+
break;
|
|
3079
|
+
case "f64":
|
|
3080
|
+
case "date":
|
|
3081
|
+
this.declare(`declare void @scr_promise_fulfill_f64(ptr, double)`);
|
|
3082
|
+
this.B.line(`call void @scr_promise_fulfill_f64(ptr ${pr}, double ${v.name})`);
|
|
3083
|
+
break;
|
|
3084
|
+
case "bool":
|
|
3085
|
+
this.declare(`declare void @scr_promise_fulfill_bool(ptr, i1 zeroext)`);
|
|
3086
|
+
this.B.line(`call void @scr_promise_fulfill_bool(ptr ${pr}, i1 ${v.name})`);
|
|
3087
|
+
break;
|
|
3088
|
+
case "string":
|
|
3089
|
+
this.declare(`declare void @scr_promise_fulfill_str(ptr, ptr)`);
|
|
3090
|
+
this.B.line(`call void @scr_promise_fulfill_str(ptr ${pr}, ptr ${v.name}) ; moves in`);
|
|
3091
|
+
break;
|
|
3092
|
+
default: {
|
|
3093
|
+
const rc = vAdapters(this, ret);
|
|
3094
|
+
this.declare(`declare void @scr_promise_fulfill_ref(ptr, ptr, ptr, ptr, ptr)`);
|
|
3095
|
+
this.B.line(`call void @scr_promise_fulfill_ref(ptr ${pr}, ptr ${v.name}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${traceArg(this, ret)})`);
|
|
3096
|
+
}
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
2655
3099
|
emitFunction(fn) {
|
|
2656
3100
|
const B = new BlockBuilder();
|
|
2657
3101
|
this.B = B;
|
|
@@ -2666,7 +3110,41 @@ class LlEmitter {
|
|
|
2666
3110
|
this.tryStack = [];
|
|
2667
3111
|
this.currentReturnType = fn.returnType;
|
|
2668
3112
|
this.currentGenerator = fn.generator ?? null;
|
|
3113
|
+
this.currentWasiCoro = null;
|
|
2669
3114
|
this.logArgSlots = 0;
|
|
3115
|
+
if (this.wasi && (fn.async === true || fn.generator !== undefined)) {
|
|
3116
|
+
this.declare(`declare token @llvm.coro.id(i32, ptr, ptr, ptr)`);
|
|
3117
|
+
this.declare(`declare ${this.sizeType} @llvm.coro.size.${this.sizeType}()`);
|
|
3118
|
+
this.declare(`declare ptr @llvm.coro.begin(token, ptr)`);
|
|
3119
|
+
this.declare(`declare token @llvm.coro.save(ptr)`);
|
|
3120
|
+
this.declare(`declare i8 @llvm.coro.suspend(token, i1)`);
|
|
3121
|
+
this.declare(`declare ptr @llvm.coro.free(token, ptr)`);
|
|
3122
|
+
this.declare(`declare i1 @llvm.coro.end(ptr, i1, token)`);
|
|
3123
|
+
this.declare(`declare ptr @malloc(${this.sizeType})`);
|
|
3124
|
+
this.declare(`declare void @free(ptr)`);
|
|
3125
|
+
this.declare(`declare void @scr_wasi_coro_started(ptr)`);
|
|
3126
|
+
this.declare(`declare ptr @scr_fiber_self()`);
|
|
3127
|
+
const id = B.tmp();
|
|
3128
|
+
const size = B.tmp();
|
|
3129
|
+
const mem = B.tmp();
|
|
3130
|
+
const handle = B.tmp();
|
|
3131
|
+
const self = B.tmp();
|
|
3132
|
+
B.line(`${id} = call token @llvm.coro.id(i32 0, ptr null, ptr null, ptr null)`);
|
|
3133
|
+
B.line(`${size} = call ${this.sizeType} @llvm.coro.size.${this.sizeType}()`);
|
|
3134
|
+
B.line(`${mem} = call ptr @malloc(${this.sizeType} ${size})`);
|
|
3135
|
+
B.line(`${handle} = call ptr @llvm.coro.begin(token ${id}, ptr ${mem})`);
|
|
3136
|
+
B.line(`call void @scr_wasi_coro_started(ptr ${handle})`);
|
|
3137
|
+
B.line(`${self} = call ptr @scr_fiber_self()`);
|
|
3138
|
+
this.currentWasiCoro = {
|
|
3139
|
+
kind: fn.async === true ? "async" : "generator",
|
|
3140
|
+
id,
|
|
3141
|
+
handle,
|
|
3142
|
+
self,
|
|
3143
|
+
finalLabel: B.newLabel("coro.final"),
|
|
3144
|
+
cleanupLabel: B.newLabel("coro.cleanup"),
|
|
3145
|
+
suspendLabel: B.newLabel("coro.suspend"),
|
|
3146
|
+
};
|
|
3147
|
+
}
|
|
2670
3148
|
const paramIds = new Set(fn.params.map((p) => p.localId));
|
|
2671
3149
|
for (const local of fn.locals) {
|
|
2672
3150
|
// Boxed locals' slots hold their capture BOX (a ptr); captured
|
|
@@ -2688,9 +3166,11 @@ class LlEmitter {
|
|
|
2688
3166
|
// Captured bindings come in through the environment — borrowed for the
|
|
2689
3167
|
// whole call (the closure owns them): bound here, never released here.
|
|
2690
3168
|
(fn.captures ?? []).forEach((c, i) => {
|
|
3169
|
+
const caps = B.tmp();
|
|
2691
3170
|
const p = B.tmp();
|
|
2692
3171
|
const box = B.tmp();
|
|
2693
|
-
B.line(`${
|
|
3172
|
+
B.line(`${caps} = getelementptr inbounds %ScrClosure, ptr %sc_env, i64 1 ; caps`);
|
|
3173
|
+
B.line(`${p} = getelementptr inbounds ptr, ptr ${caps}, ${this.sizeType} ${i} ; caps[${i}]`);
|
|
2694
3174
|
B.line(`${box} = load ptr, ptr ${p}`);
|
|
2695
3175
|
B.line(`store ptr ${box}, ptr %${mangleLocal(c.localId)} ; captured ${c.name}`);
|
|
2696
3176
|
});
|
|
@@ -2720,9 +3200,51 @@ class LlEmitter {
|
|
|
2720
3200
|
// whose unwind released everything down to depth 0).
|
|
2721
3201
|
if (fn.returnType.kind === "void" && !B.isTerminated()) {
|
|
2722
3202
|
this.releaseScope(this.scopes[0]);
|
|
2723
|
-
|
|
3203
|
+
if (this.currentWasiCoro !== null) {
|
|
3204
|
+
this.emitWasiFulfill(null);
|
|
3205
|
+
B.terminate(`br label %${this.currentWasiCoro.finalLabel}`);
|
|
3206
|
+
}
|
|
3207
|
+
else {
|
|
3208
|
+
B.terminate("ret void");
|
|
3209
|
+
}
|
|
2724
3210
|
}
|
|
2725
3211
|
this.scopes.pop();
|
|
3212
|
+
const coro = this.currentWasiCoro;
|
|
3213
|
+
if (coro !== null) {
|
|
3214
|
+
B.startBlock(coro.finalLabel);
|
|
3215
|
+
if (fn.captures !== undefined) {
|
|
3216
|
+
this.declare(`declare void @scr_closure_release(ptr)`);
|
|
3217
|
+
B.line(`call void @scr_closure_release(ptr %sc_env)`);
|
|
3218
|
+
}
|
|
3219
|
+
if (coro.kind === "generator") {
|
|
3220
|
+
this.declare(`declare void @scr_wasi_gen_finish(ptr)`);
|
|
3221
|
+
B.line(`call void @scr_wasi_gen_finish(ptr ${coro.self})`);
|
|
3222
|
+
}
|
|
3223
|
+
else {
|
|
3224
|
+
this.declare(`declare void @scr_wasi_async_finish(ptr)`);
|
|
3225
|
+
B.line(`call void @scr_wasi_async_finish(ptr ${coro.self})`);
|
|
3226
|
+
}
|
|
3227
|
+
const finalState = B.tmp();
|
|
3228
|
+
B.line(`${finalState} = call i8 @llvm.coro.suspend(token none, i1 true)`);
|
|
3229
|
+
B.terminate(`switch i8 ${finalState}, label %${coro.suspendLabel} [ i8 1, label %${coro.cleanupLabel} ]`);
|
|
3230
|
+
B.startBlock(coro.cleanupLabel);
|
|
3231
|
+
const frame = B.tmp();
|
|
3232
|
+
B.line(`${frame} = call ptr @llvm.coro.free(token ${coro.id}, ptr ${coro.handle})`);
|
|
3233
|
+
B.line(`call void @free(ptr ${frame})`);
|
|
3234
|
+
B.br(coro.suspendLabel);
|
|
3235
|
+
B.startBlock(coro.suspendLabel);
|
|
3236
|
+
const ended = B.tmp();
|
|
3237
|
+
B.line(`${ended} = call i1 @llvm.coro.end(ptr ${coro.handle}, i1 false, token none)`);
|
|
3238
|
+
const ret = this.llType(fn.returnType);
|
|
3239
|
+
if (ret === "void")
|
|
3240
|
+
B.terminate(`ret void`);
|
|
3241
|
+
else if (ret === "double")
|
|
3242
|
+
B.terminate(`ret double ${f64Lit(0)}`);
|
|
3243
|
+
else if (ret === "i1")
|
|
3244
|
+
B.terminate(`ret i1 false`);
|
|
3245
|
+
else
|
|
3246
|
+
B.terminate(`ret ptr null`);
|
|
3247
|
+
}
|
|
2726
3248
|
if (this.logArgSlots > 0) {
|
|
2727
3249
|
B.entryAllocas.push(`%logargs = alloca [${this.logArgSlots} x %ScrLogArg]`);
|
|
2728
3250
|
}
|
|
@@ -2731,7 +3253,8 @@ class LlEmitter {
|
|
|
2731
3253
|
if (fn.captures !== undefined)
|
|
2732
3254
|
params.unshift("ptr %sc_env");
|
|
2733
3255
|
const ret = this.llType(fn.returnType);
|
|
2734
|
-
|
|
3256
|
+
const attrs = coro !== null ? "#1" : FN_ATTRS;
|
|
3257
|
+
return `define internal ${ret} @${mangleFunction(fn.name)}(${params.join(", ")}) ${attrs} { ; ${fn.name}\n${B.render()}\n}`;
|
|
2735
3258
|
}
|
|
2736
3259
|
// ── statements ──────────────────────────────────────────────────────────
|
|
2737
3260
|
emitStmts(stmts) {
|
|
@@ -2960,7 +3483,7 @@ class LlEmitter {
|
|
|
2960
3483
|
B.line(`${kp} = getelementptr inbounds %ScrDynPath, ptr ${pathSlot}, i64 0, i32 1`);
|
|
2961
3484
|
B.line(`store ptr ${this.cstr(f.name)}, ptr ${kp}`);
|
|
2962
3485
|
B.line(`${ip} = getelementptr inbounds %ScrDynPath, ptr ${pathSlot}, i64 0, i32 2`);
|
|
2963
|
-
B.line(`store
|
|
3486
|
+
B.line(`store ${this.sizeType} 0, ptr ${ip}`);
|
|
2964
3487
|
const helper = this.dyn.dynCheckHelper(f.type);
|
|
2965
3488
|
const fty = this.llType(f.type);
|
|
2966
3489
|
const nv = B.tmp();
|
|
@@ -3129,8 +3652,8 @@ class LlEmitter {
|
|
|
3129
3652
|
let integerSlot = null;
|
|
3130
3653
|
if (integerLoop) {
|
|
3131
3654
|
integerSlot = B.slot();
|
|
3132
|
-
B.entryAllocas.push(`${integerSlot} = alloca
|
|
3133
|
-
B.line(`store
|
|
3655
|
+
B.entryAllocas.push(`${integerSlot} = alloca ${this.sizeType} ; integer induction ${this.currentLocals.get(integerLoop.localId).name}`);
|
|
3656
|
+
B.line(`store ${this.sizeType} 0, ptr ${integerSlot}`);
|
|
3134
3657
|
this.integerLoopBindings.set(integerLoop.localId, integerSlot);
|
|
3135
3658
|
}
|
|
3136
3659
|
else if (s.init) {
|
|
@@ -3156,9 +3679,9 @@ class LlEmitter {
|
|
|
3156
3679
|
const index = B.tmp();
|
|
3157
3680
|
const inBounds = B.tmp();
|
|
3158
3681
|
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
|
|
3682
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}`);
|
|
3683
|
+
B.line(`${index} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
3684
|
+
B.line(`${inBounds} = icmp ult ${this.sizeType} ${index}, ${len}`);
|
|
3162
3685
|
B.condBr(inBounds, lb, le);
|
|
3163
3686
|
}
|
|
3164
3687
|
else if (s.cond)
|
|
@@ -3196,9 +3719,9 @@ class LlEmitter {
|
|
|
3196
3719
|
if (integerLoop && integerSlot) {
|
|
3197
3720
|
const old = B.tmp();
|
|
3198
3721
|
const next = B.tmp();
|
|
3199
|
-
B.line(`${old} = load
|
|
3200
|
-
B.line(`${next} = add nuw
|
|
3201
|
-
B.line(`store
|
|
3722
|
+
B.line(`${old} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
3723
|
+
B.line(`${next} = add nuw ${this.sizeType} ${old}, 1`);
|
|
3724
|
+
B.line(`store ${this.sizeType} ${next}, ptr ${integerSlot}`);
|
|
3202
3725
|
}
|
|
3203
3726
|
else if (s.update)
|
|
3204
3727
|
this.emitStmt(s.update);
|
|
@@ -3376,10 +3899,16 @@ class LlEmitter {
|
|
|
3376
3899
|
else {
|
|
3377
3900
|
this.releaseForJump(0, 0);
|
|
3378
3901
|
}
|
|
3379
|
-
if (
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3902
|
+
if (!B.isTerminated()) {
|
|
3903
|
+
if (this.currentWasiCoro !== null) {
|
|
3904
|
+
this.emitWasiFulfill(v);
|
|
3905
|
+
B.terminate(`br label %${this.currentWasiCoro.finalLabel}`);
|
|
3906
|
+
}
|
|
3907
|
+
else if (v === null)
|
|
3908
|
+
B.terminate("ret void");
|
|
3909
|
+
else
|
|
3910
|
+
B.terminate(`ret ${this.llType(s.value.type)} ${v.name}`);
|
|
3911
|
+
}
|
|
3383
3912
|
break;
|
|
3384
3913
|
}
|
|
3385
3914
|
case "throw": {
|
|
@@ -3408,8 +3937,8 @@ class LlEmitter {
|
|
|
3408
3937
|
// the construct (message) with the SC code stamped on `code`,
|
|
3409
3938
|
// then unwind exactly like `throw`. SCR_ERR_ERROR = 0.
|
|
3410
3939
|
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)},
|
|
3940
|
+
this.declare(`declare void @scr_throw_error_msg_code(i32, ptr, ${this.sizeType}, ptr)`);
|
|
3941
|
+
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
3942
|
this.emitUnwind();
|
|
3414
3943
|
break;
|
|
3415
3944
|
}
|
|
@@ -3689,8 +4218,8 @@ class LlEmitter {
|
|
|
3689
4218
|
if (integerSlot !== undefined) {
|
|
3690
4219
|
const integer = B.tmp();
|
|
3691
4220
|
const number = B.tmp();
|
|
3692
|
-
B.line(`${integer} = load
|
|
3693
|
-
B.line(`${number} = uitofp
|
|
4221
|
+
B.line(`${integer} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
4222
|
+
B.line(`${number} = uitofp ${this.sizeType} ${integer} to double`);
|
|
3694
4223
|
return { name: number, type: e.type };
|
|
3695
4224
|
}
|
|
3696
4225
|
const b = this.binding(e.localId);
|
|
@@ -4817,15 +5346,17 @@ class LlEmitter {
|
|
|
4817
5346
|
}
|
|
4818
5347
|
// Lifted async lambdas enter through their spawn wrapper (which
|
|
4819
5348
|
// takes sc_env first, like every lifted function).
|
|
4820
|
-
this.declare(`declare ptr @scr_closure_new(ptr,
|
|
5349
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
4821
5350
|
const c = B.tmp();
|
|
4822
|
-
B.line(`${c} = call ptr @scr_closure_new(ptr @${this.callTarget(e.fnName)},
|
|
5351
|
+
B.line(`${c} = call ptr @scr_closure_new(ptr @${this.callTarget(e.fnName)}, ${this.sizeType} ${e.captures.length})`);
|
|
4823
5352
|
const out = this.own({ name: c, type: e.type });
|
|
4824
5353
|
e.captures.forEach((localId, i) => {
|
|
4825
5354
|
const box = this.loadBox(`%${mangleLocal(localId)}`);
|
|
4826
5355
|
const retained = this.retainBox(box);
|
|
5356
|
+
const caps = B.tmp();
|
|
4827
5357
|
const capp = B.tmp();
|
|
4828
|
-
B.line(`${
|
|
5358
|
+
B.line(`${caps} = getelementptr inbounds %ScrClosure, ptr ${c}, i64 1 ; caps`);
|
|
5359
|
+
B.line(`${capp} = getelementptr inbounds ptr, ptr ${caps}, ${this.sizeType} ${i} ; caps[${i}]`);
|
|
4829
5360
|
B.line(`store ptr ${retained}, ptr ${capp}`);
|
|
4830
5361
|
});
|
|
4831
5362
|
return out;
|
|
@@ -4904,11 +5435,49 @@ class LlEmitter {
|
|
|
4904
5435
|
if (!entry)
|
|
4905
5436
|
throw new Error(`llvm emitter bug: unknown FFI import ${e.import}`);
|
|
4906
5437
|
const args = e.args.map((arg) => this.emitExpr(arg));
|
|
5438
|
+
const sourceArgs = new Map();
|
|
5439
|
+
const callbackArgs = new Map();
|
|
5440
|
+
let sourceIndex = 0;
|
|
5441
|
+
entry.params.forEach((param, abiIndex) => {
|
|
5442
|
+
if (isFfiContextParam(param))
|
|
5443
|
+
return;
|
|
5444
|
+
const arg = args[sourceIndex++];
|
|
5445
|
+
sourceArgs.set(abiIndex, arg);
|
|
5446
|
+
if (isFfiCallbackParam(param))
|
|
5447
|
+
callbackArgs.set(param.callback.id, arg);
|
|
5448
|
+
});
|
|
5449
|
+
const rawContexts = [];
|
|
5450
|
+
for (const param of entry.params) {
|
|
5451
|
+
if (!isFfiCallbackParam(param))
|
|
5452
|
+
continue;
|
|
5453
|
+
const adapter = this.ffiCallbackAdapter(entry.name, param.callback.id);
|
|
5454
|
+
if (adapter.tls === null)
|
|
5455
|
+
continue;
|
|
5456
|
+
const callback = callbackArgs.get(param.callback.id);
|
|
5457
|
+
const previous = B.tmp();
|
|
5458
|
+
B.line(`${previous} = load ptr, ptr @${adapter.tls}`);
|
|
5459
|
+
B.line(`store ptr ${callback.name}, ptr @${adapter.tls}`);
|
|
5460
|
+
rawContexts.push({ tls: adapter.tls, previous });
|
|
5461
|
+
}
|
|
4907
5462
|
const nativeArgs = [];
|
|
4908
5463
|
const nativeParamTypes = [];
|
|
4909
|
-
entry.params.forEach((
|
|
4910
|
-
|
|
4911
|
-
|
|
5464
|
+
entry.params.forEach((param, i) => {
|
|
5465
|
+
if (isFfiCallbackParam(param)) {
|
|
5466
|
+
const adapter = this.ffiCallbackAdapter(entry.name, param.callback.id);
|
|
5467
|
+
nativeParamTypes.push("ptr");
|
|
5468
|
+
nativeArgs.push(`ptr @${adapter.symbol}`);
|
|
5469
|
+
return;
|
|
5470
|
+
}
|
|
5471
|
+
if (isFfiContextParam(param)) {
|
|
5472
|
+
const callback = callbackArgs.get(param.context);
|
|
5473
|
+
if (!callback)
|
|
5474
|
+
throw new Error(`llvm emitter bug: FFI context '${param.context}' has no callback arg`);
|
|
5475
|
+
nativeParamTypes.push("ptr");
|
|
5476
|
+
nativeArgs.push(`ptr ${callback.name}`);
|
|
5477
|
+
return;
|
|
5478
|
+
}
|
|
5479
|
+
const arg = sourceArgs.get(i);
|
|
5480
|
+
switch (param) {
|
|
4912
5481
|
case "f64":
|
|
4913
5482
|
nativeParamTypes.push("double");
|
|
4914
5483
|
nativeArgs.push(`double ${arg.name}`);
|
|
@@ -4927,7 +5496,7 @@ class LlEmitter {
|
|
|
4927
5496
|
const asU32 = B.tmp();
|
|
4928
5497
|
B.line(`${asDouble} = call double @scr_bit_ushr(double ${arg.name}, double ${f64Lit(0)})`);
|
|
4929
5498
|
B.line(`${asU32} = fptoui double ${asDouble} to i32`);
|
|
4930
|
-
if (
|
|
5499
|
+
if (param === "u8") {
|
|
4931
5500
|
const asU8 = B.tmp();
|
|
4932
5501
|
B.line(`${asU8} = trunc i32 ${asU32} to i8`);
|
|
4933
5502
|
nativeParamTypes.push("i8");
|
|
@@ -4975,29 +5544,47 @@ class LlEmitter {
|
|
|
4975
5544
|
}
|
|
4976
5545
|
}
|
|
4977
5546
|
});
|
|
4978
|
-
const retTy = entry.returns
|
|
4979
|
-
: entry.returns === "bool" || entry.returns === "u8" ? "i8"
|
|
4980
|
-
: entry.returns === "u32" || entry.returns === "i32" ? "i32"
|
|
4981
|
-
: "void";
|
|
5547
|
+
const retTy = ffiNativeTypeLl(entry.returns);
|
|
4982
5548
|
this.declare(`declare ${retTy} @${entry.symbol}(${nativeParamTypes.join(", ")})`);
|
|
4983
5549
|
const call = `call ${retTy} @${entry.symbol}(${nativeArgs.join(", ")})`;
|
|
5550
|
+
const restoreRawContexts = () => {
|
|
5551
|
+
for (let i = rawContexts.length - 1; i >= 0; i--) {
|
|
5552
|
+
const saved = rawContexts[i];
|
|
5553
|
+
B.line(`store ptr ${saved.previous}, ptr @${saved.tls}`);
|
|
5554
|
+
}
|
|
5555
|
+
};
|
|
5556
|
+
const callbacksMayThrow = callbackArgs.size > 0;
|
|
4984
5557
|
if (entry.returns === "void") {
|
|
4985
5558
|
B.line(call);
|
|
5559
|
+
restoreRawContexts();
|
|
5560
|
+
if (callbacksMayThrow)
|
|
5561
|
+
this.emitPendingCheck();
|
|
4986
5562
|
return { name: "", type: e.type };
|
|
4987
5563
|
}
|
|
4988
5564
|
const raw = B.tmp();
|
|
4989
5565
|
B.line(`${raw} = ${call}`);
|
|
4990
|
-
|
|
4991
|
-
|
|
5566
|
+
restoreRawContexts();
|
|
5567
|
+
if (entry.returns === "f64") {
|
|
5568
|
+
const result = { name: raw, type: e.type };
|
|
5569
|
+
if (callbacksMayThrow)
|
|
5570
|
+
this.emitPendingCheck();
|
|
5571
|
+
return result;
|
|
5572
|
+
}
|
|
4992
5573
|
if (entry.returns === "bool") {
|
|
4993
5574
|
const value = B.tmp();
|
|
4994
5575
|
B.line(`${value} = icmp ne i8 ${raw}, 0`);
|
|
4995
|
-
|
|
5576
|
+
const result = { name: value, type: e.type };
|
|
5577
|
+
if (callbacksMayThrow)
|
|
5578
|
+
this.emitPendingCheck();
|
|
5579
|
+
return result;
|
|
4996
5580
|
}
|
|
4997
5581
|
const value = B.tmp();
|
|
4998
5582
|
const op = entry.returns === "i32" ? "sitofp" : "uitofp";
|
|
4999
5583
|
B.line(`${value} = ${op} ${retTy} ${raw} to double`);
|
|
5000
|
-
|
|
5584
|
+
const result = { name: value, type: e.type };
|
|
5585
|
+
if (callbacksMayThrow)
|
|
5586
|
+
this.emitPendingCheck();
|
|
5587
|
+
return result;
|
|
5001
5588
|
}
|
|
5002
5589
|
case "new": {
|
|
5003
5590
|
// Allocate (fields zeroed, vt stamped), then run the ctor. The
|
|
@@ -5116,8 +5703,8 @@ class LlEmitter {
|
|
|
5116
5703
|
const ge = B.tmp();
|
|
5117
5704
|
const le = B.tmp();
|
|
5118
5705
|
const t = B.tmp();
|
|
5119
|
-
B.line(`${ge} = icmp sge
|
|
5120
|
-
B.line(`${le} = icmp sle
|
|
5706
|
+
B.line(`${ge} = icmp sge ${this.sizeType} ${pre}, ${target.pre}`);
|
|
5707
|
+
B.line(`${le} = icmp sle ${this.sizeType} ${pre}, ${target.post}`);
|
|
5121
5708
|
B.line(`${t} = and i1 ${ge}, ${le} ; instanceof ${e.className}`);
|
|
5122
5709
|
return { name: t, type: e.type };
|
|
5123
5710
|
}
|
|
@@ -5135,14 +5722,14 @@ class LlEmitter {
|
|
|
5135
5722
|
const tpostp = B.tmp();
|
|
5136
5723
|
const tpost = B.tmp();
|
|
5137
5724
|
B.line(`${tprep} = getelementptr inbounds %ScrClassObj, ptr ${target.name}, i64 0, i32 1`);
|
|
5138
|
-
B.line(`${tpre} = load
|
|
5725
|
+
B.line(`${tpre} = load ${this.sizeType}, ptr ${tprep}`);
|
|
5139
5726
|
B.line(`${tpostp} = getelementptr inbounds %ScrClassObj, ptr ${target.name}, i64 0, i32 2`);
|
|
5140
|
-
B.line(`${tpost} = load
|
|
5727
|
+
B.line(`${tpost} = load ${this.sizeType}, ptr ${tpostp}`);
|
|
5141
5728
|
const ge = B.tmp();
|
|
5142
5729
|
const le = B.tmp();
|
|
5143
5730
|
const t = B.tmp();
|
|
5144
|
-
B.line(`${ge} = icmp sge
|
|
5145
|
-
B.line(`${le} = icmp sle
|
|
5731
|
+
B.line(`${ge} = icmp sge ${this.sizeType} ${pre}, ${tpre}`);
|
|
5732
|
+
B.line(`${le} = icmp sle ${this.sizeType} ${pre}, ${tpost}`);
|
|
5146
5733
|
B.line(`${t} = and i1 ${ge}, ${le}`);
|
|
5147
5734
|
return { name: t, type: e.type };
|
|
5148
5735
|
}
|
|
@@ -5154,9 +5741,9 @@ class LlEmitter {
|
|
|
5154
5741
|
const c = this.emitExpr(e.value);
|
|
5155
5742
|
if (e.test === "instanceof") {
|
|
5156
5743
|
const target = this.classMetaOf(e.className);
|
|
5157
|
-
this.declare(`declare zeroext i1 @scr_caught_instanceof(ptr,
|
|
5744
|
+
this.declare(`declare zeroext i1 @scr_caught_instanceof(ptr, ${this.sizeType}, ${this.sizeType})`);
|
|
5158
5745
|
const t = B.tmp();
|
|
5159
|
-
B.line(`${t} = call zeroext i1 @scr_caught_instanceof(ptr ${c.name},
|
|
5746
|
+
B.line(`${t} = call zeroext i1 @scr_caught_instanceof(ptr ${c.name}, ${this.sizeType} ${target.pre}, ${this.sizeType} ${target.post})`);
|
|
5160
5747
|
if (e.negated !== true)
|
|
5161
5748
|
return { name: t, type: e.type };
|
|
5162
5749
|
const n = B.tmp();
|
|
@@ -5221,9 +5808,9 @@ class LlEmitter {
|
|
|
5221
5808
|
const c = this.emitExpr(e.value);
|
|
5222
5809
|
const target = this.classMetaOf(e.className);
|
|
5223
5810
|
const display = e.className.startsWith("%") ? e.className.slice(1) : e.className;
|
|
5224
|
-
this.declare(`declare ptr @scr_caught_check_obj(ptr,
|
|
5811
|
+
this.declare(`declare ptr @scr_caught_check_obj(ptr, ${this.sizeType}, ${this.sizeType}, ptr)`);
|
|
5225
5812
|
const t = B.tmp();
|
|
5226
|
-
B.line(`${t} = call ptr @scr_caught_check_obj(ptr ${c.name},
|
|
5813
|
+
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
5814
|
const out = this.own({ name: t, type: e.type });
|
|
5228
5815
|
this.emitPendingCheck();
|
|
5229
5816
|
return out;
|
|
@@ -5334,7 +5921,7 @@ class LlEmitter {
|
|
|
5334
5921
|
return compact;
|
|
5335
5922
|
const rewriter = this.walkers.jsonIndentHelper();
|
|
5336
5923
|
const t2 = B.tmp();
|
|
5337
|
-
B.line(`${t2} = call ptr @${rewriter}(ptr ${compact.name}, ptr ${this.cstr(indent)},
|
|
5924
|
+
B.line(`${t2} = call ptr @${rewriter}(ptr ${compact.name}, ptr ${this.cstr(indent)}, ${this.sizeType} ${Buffer.byteLength(indent, "utf8")})`);
|
|
5338
5925
|
return this.own({ name: t2, type: e.type });
|
|
5339
5926
|
}
|
|
5340
5927
|
case "bytesNew": {
|
|
@@ -5389,18 +5976,50 @@ class LlEmitter {
|
|
|
5389
5976
|
const v = this.emitExpr(e.value);
|
|
5390
5977
|
const yt = e.value.type;
|
|
5391
5978
|
if (yt.kind === "f64" || yt.kind === "date") {
|
|
5392
|
-
this.
|
|
5393
|
-
|
|
5979
|
+
if (this.wasi) {
|
|
5980
|
+
const coro = this.currentWasiCoro;
|
|
5981
|
+
this.declare(`declare ptr @scr_gen_of_fiber(ptr)`);
|
|
5982
|
+
this.declare(`declare void @scr_gen_out_f64(ptr, double)`);
|
|
5983
|
+
const g = B.tmp();
|
|
5984
|
+
B.line(`${g} = call ptr @scr_gen_of_fiber(ptr ${coro.self})`);
|
|
5985
|
+
B.line(`call void @scr_gen_out_f64(ptr ${g}, double ${v.name})`);
|
|
5986
|
+
}
|
|
5987
|
+
else {
|
|
5988
|
+
this.declare(`declare void @scr_gen_yield_f64(double)`);
|
|
5989
|
+
B.line(`call void @scr_gen_yield_f64(double ${v.name})`);
|
|
5990
|
+
}
|
|
5394
5991
|
}
|
|
5395
5992
|
else if (yt.kind === "bool") {
|
|
5396
|
-
this.
|
|
5397
|
-
|
|
5993
|
+
if (this.wasi) {
|
|
5994
|
+
const coro = this.currentWasiCoro;
|
|
5995
|
+
this.declare(`declare ptr @scr_gen_of_fiber(ptr)`);
|
|
5996
|
+
this.declare(`declare void @scr_gen_out_bool(ptr, i1 zeroext)`);
|
|
5997
|
+
const g = B.tmp();
|
|
5998
|
+
B.line(`${g} = call ptr @scr_gen_of_fiber(ptr ${coro.self})`);
|
|
5999
|
+
B.line(`call void @scr_gen_out_bool(ptr ${g}, i1 ${v.name})`);
|
|
6000
|
+
}
|
|
6001
|
+
else {
|
|
6002
|
+
this.declare(`declare void @scr_gen_yield_bool(i1 zeroext)`);
|
|
6003
|
+
B.line(`call void @scr_gen_yield_bool(i1 ${v.name})`);
|
|
6004
|
+
}
|
|
5398
6005
|
}
|
|
5399
6006
|
else {
|
|
5400
6007
|
this.moveTemp(v); // the OUT slot takes ownership
|
|
5401
|
-
this.
|
|
5402
|
-
|
|
6008
|
+
if (this.wasi) {
|
|
6009
|
+
const coro = this.currentWasiCoro;
|
|
6010
|
+
this.declare(`declare ptr @scr_gen_of_fiber(ptr)`);
|
|
6011
|
+
this.declare(`declare void @scr_gen_out_ref(ptr, ptr, ptr)`);
|
|
6012
|
+
const g = B.tmp();
|
|
6013
|
+
B.line(`${g} = call ptr @scr_gen_of_fiber(ptr ${coro.self})`);
|
|
6014
|
+
B.line(`call void @scr_gen_out_ref(ptr ${g}, ptr ${v.name}, ptr ${vAdapters(this, yt).release})`);
|
|
6015
|
+
}
|
|
6016
|
+
else {
|
|
6017
|
+
this.declare(`declare void @scr_gen_yield_ref(ptr, ptr)`);
|
|
6018
|
+
B.line(`call void @scr_gen_yield_ref(ptr ${v.name}, ptr ${vAdapters(this, yt).release})`);
|
|
6019
|
+
}
|
|
5403
6020
|
}
|
|
6021
|
+
if (this.wasi)
|
|
6022
|
+
this.emitWasiSuspendPrepared();
|
|
5404
6023
|
this.emitPendingCheck();
|
|
5405
6024
|
if (e.type.kind === "void") {
|
|
5406
6025
|
// An undefined next-channel: nothing to read (the frontend
|
|
@@ -5532,6 +6151,8 @@ class LlEmitter {
|
|
|
5532
6151
|
// refcounted results arrive +1 and join the frame pre-check so an
|
|
5533
6152
|
// unwind releases the dummy (NULL) harmlessly.
|
|
5534
6153
|
const pr = this.emitExpr(e.value);
|
|
6154
|
+
if (this.wasi)
|
|
6155
|
+
this.emitWasiSuspend(pr.name);
|
|
5535
6156
|
if (e.type.kind === "void") {
|
|
5536
6157
|
this.declare(`declare void @scr_await_void(ptr)`);
|
|
5537
6158
|
B.line(`call void @scr_await_void(ptr ${pr.name})`);
|
|
@@ -5586,10 +6207,18 @@ class LlEmitter {
|
|
|
5586
6207
|
B.condBr(isP, lp, lh);
|
|
5587
6208
|
B.startBlock(lp);
|
|
5588
6209
|
this.declare(`declare void @scr_await_void(ptr)`);
|
|
5589
|
-
|
|
6210
|
+
{
|
|
6211
|
+
const promise = this.unionPeek(u.name);
|
|
6212
|
+
if (this.wasi)
|
|
6213
|
+
this.emitWasiSuspend(promise);
|
|
6214
|
+
B.line(`call void @scr_await_void(ptr ${promise})`);
|
|
6215
|
+
}
|
|
5590
6216
|
B.br(lj);
|
|
5591
6217
|
B.startBlock(lh);
|
|
5592
|
-
|
|
6218
|
+
if (this.wasi)
|
|
6219
|
+
this.emitWasiSuspend(null);
|
|
6220
|
+
else
|
|
6221
|
+
B.line(`call void @scr_await_hop()`);
|
|
5593
6222
|
B.br(lj);
|
|
5594
6223
|
B.startBlock(lj);
|
|
5595
6224
|
this.emitPendingCheck();
|
|
@@ -5618,6 +6247,8 @@ class LlEmitter {
|
|
|
5618
6247
|
B.condBr(isP, lp, lh);
|
|
5619
6248
|
B.startBlock(lp);
|
|
5620
6249
|
const peek = this.unionPeek(u.name);
|
|
6250
|
+
if (this.wasi)
|
|
6251
|
+
this.emitWasiSuspend(peek);
|
|
5621
6252
|
let awaited;
|
|
5622
6253
|
if (inner.kind === "f64" || inner.kind === "date") {
|
|
5623
6254
|
this.declare(`declare double @scr_await_f64(ptr)`);
|
|
@@ -5646,7 +6277,10 @@ class LlEmitter {
|
|
|
5646
6277
|
B.line(`store ptr ${this.unionNewOwned(innerTag, awaited)}, ptr ${slot}`);
|
|
5647
6278
|
B.br(lj);
|
|
5648
6279
|
B.startBlock(lh);
|
|
5649
|
-
|
|
6280
|
+
if (this.wasi)
|
|
6281
|
+
this.emitWasiSuspend(null);
|
|
6282
|
+
else
|
|
6283
|
+
B.line(`call void @scr_await_hop()`);
|
|
5650
6284
|
const unitTags = def.arms.flatMap((a, i) => (isUnitType(a) ? [i] : []));
|
|
5651
6285
|
if (unitTags.length === 1) {
|
|
5652
6286
|
B.line(`store ptr ${this.unitInstanceRef(resUnionId, resTagOf(def.arms[unitTags[0]]))}, ptr ${slot}`);
|
|
@@ -5772,8 +6406,27 @@ class LlEmitter {
|
|
|
5772
6406
|
// Internal ESM dependency wait: pending promises park the module
|
|
5773
6407
|
// fiber, while settled ones continue synchronously.
|
|
5774
6408
|
const p = this.emitExpr(e.args[0]);
|
|
5775
|
-
this.
|
|
5776
|
-
|
|
6409
|
+
if (this.wasi) {
|
|
6410
|
+
const coro = this.currentWasiCoro;
|
|
6411
|
+
if (coro === null)
|
|
6412
|
+
throw new Error("llvm emitter bug: module await outside wasm coroutine");
|
|
6413
|
+
this.declare(`declare zeroext i1 @scr_wasi_module_await_prepare(ptr, ptr)`);
|
|
6414
|
+
const needsSuspend = B.tmp();
|
|
6415
|
+
const suspend = B.newLabel("ma.suspend");
|
|
6416
|
+
const ready = B.newLabel("ma.ready");
|
|
6417
|
+
B.line(`${needsSuspend} = call zeroext i1 @scr_wasi_module_await_prepare(ptr ${coro.self}, ptr ${p.name})`);
|
|
6418
|
+
B.condBr(needsSuspend, suspend, ready);
|
|
6419
|
+
B.startBlock(suspend);
|
|
6420
|
+
this.emitWasiSuspendPrepared();
|
|
6421
|
+
B.br(ready);
|
|
6422
|
+
B.startBlock(ready);
|
|
6423
|
+
this.declare(`declare void @scr_module_await(ptr)`);
|
|
6424
|
+
B.line(`call void @scr_module_await(ptr ${p.name})`);
|
|
6425
|
+
}
|
|
6426
|
+
else {
|
|
6427
|
+
this.declare(`declare void @scr_module_await(ptr)`);
|
|
6428
|
+
B.line(`call void @scr_module_await(ptr ${p.name})`);
|
|
6429
|
+
}
|
|
5777
6430
|
this.emitPendingCheck();
|
|
5778
6431
|
return { name: "", type: e.type };
|
|
5779
6432
|
}
|
|
@@ -5807,7 +6460,7 @@ class LlEmitter {
|
|
|
5807
6460
|
const len = B.tmp();
|
|
5808
6461
|
const cap = B.tmp();
|
|
5809
6462
|
B.line(`${len} = call double @scr_arr_len(ptr ${ps.name})`);
|
|
5810
|
-
B.line(`${cap} = fptoui double ${len} to
|
|
6463
|
+
B.line(`${cap} = fptoui double ${len} to ${this.sizeType}`);
|
|
5811
6464
|
const vals = B.tmp();
|
|
5812
6465
|
B.line(`${vals} = ${arrNewCall(this, elem, cap)}`);
|
|
5813
6466
|
this.own({ name: vals, type: e.type.inner });
|
|
@@ -5929,8 +6582,8 @@ class LlEmitter {
|
|
|
5929
6582
|
}
|
|
5930
6583
|
});
|
|
5931
6584
|
const fn = e.name === "console.error" ? "scr_console_error" : "scr_console_log";
|
|
5932
|
-
this.declare(`declare void @${fn}(
|
|
5933
|
-
B.line(`call void @${fn}(
|
|
6585
|
+
this.declare(`declare void @${fn}(${this.sizeType}, ptr)`);
|
|
6586
|
+
B.line(`call void @${fn}(${this.sizeType} ${args.length}, ptr %logargs)`);
|
|
5934
6587
|
return { name: "", type: e.type };
|
|
5935
6588
|
}
|
|
5936
6589
|
case "dynFrom": {
|
|
@@ -5972,9 +6625,9 @@ class LlEmitter {
|
|
|
5972
6625
|
this.liveDynRefAdapters.set(key, adapter);
|
|
5973
6626
|
}
|
|
5974
6627
|
const rc = vAdapters(this, v.type);
|
|
5975
|
-
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr,
|
|
6628
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
5976
6629
|
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)},
|
|
6630
|
+
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
6631
|
return this.own({ name: boxed, type: e.type });
|
|
5979
6632
|
}
|
|
5980
6633
|
if (v.type.kind === "func") {
|
|
@@ -6075,14 +6728,14 @@ class LlEmitter {
|
|
|
6075
6728
|
B.entryAllocas.push(`${arr} = alloca [${args.length} x ptr]`);
|
|
6076
6729
|
args.forEach((a, i) => {
|
|
6077
6730
|
const p = B.tmp();
|
|
6078
|
-
B.line(`${p} = getelementptr inbounds [${args.length} x ptr], ptr ${arr}, i64 0,
|
|
6731
|
+
B.line(`${p} = getelementptr inbounds [${args.length} x ptr], ptr ${arr}, i64 0, ${this.sizeType} ${i}`);
|
|
6079
6732
|
B.line(`store ptr ${a.name}, ptr ${p}`);
|
|
6080
6733
|
});
|
|
6081
6734
|
argsPtr = arr;
|
|
6082
6735
|
}
|
|
6083
|
-
this.declare(`declare ptr @scr_dyn_call(ptr, ptr,
|
|
6736
|
+
this.declare(`declare ptr @scr_dyn_call(ptr, ptr, ${this.sizeType}, ptr)`);
|
|
6084
6737
|
const t = B.tmp();
|
|
6085
|
-
B.line(`${t} = call ptr @scr_dyn_call(ptr ${callee.name}, ptr ${argsPtr},
|
|
6738
|
+
B.line(`${t} = call ptr @scr_dyn_call(ptr ${callee.name}, ptr ${argsPtr}, ${this.sizeType} ${args.length}, ptr ${this.cstr(e.calleeName)})`);
|
|
6086
6739
|
const out = this.own({ name: t, type: e.type });
|
|
6087
6740
|
this.emitPendingCheck();
|
|
6088
6741
|
return out;
|
|
@@ -6099,14 +6752,14 @@ class LlEmitter {
|
|
|
6099
6752
|
B.entryAllocas.push(`${arr} = alloca [${args.length} x ptr]`);
|
|
6100
6753
|
args.forEach((a, i) => {
|
|
6101
6754
|
const p = B.tmp();
|
|
6102
|
-
B.line(`${p} = getelementptr inbounds [${args.length} x ptr], ptr ${arr}, i64 0,
|
|
6755
|
+
B.line(`${p} = getelementptr inbounds [${args.length} x ptr], ptr ${arr}, i64 0, ${this.sizeType} ${i}`);
|
|
6103
6756
|
B.line(`store ptr ${a.name}, ptr ${p}`);
|
|
6104
6757
|
});
|
|
6105
6758
|
argsPtr = arr;
|
|
6106
6759
|
}
|
|
6107
|
-
this.declare(`declare ptr @scr_dyn_invoke(ptr, ptr, ptr,
|
|
6760
|
+
this.declare(`declare ptr @scr_dyn_invoke(ptr, ptr, ptr, ${this.sizeType}, ptr)`);
|
|
6108
6761
|
const t = B.tmp();
|
|
6109
|
-
B.line(`${t} = call ptr @scr_dyn_invoke(ptr ${recv.name}, ptr ${this.cstr(e.method)}, ptr ${argsPtr},
|
|
6762
|
+
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
6763
|
const out = this.own({ name: t, type: e.type });
|
|
6111
6764
|
this.emitPendingCheck();
|
|
6112
6765
|
return out;
|
|
@@ -6173,11 +6826,11 @@ class LlEmitter {
|
|
|
6173
6826
|
B.line(`${isObj} = icmp eq i32 ${kd}, ${DK.OBJ}`);
|
|
6174
6827
|
B.condBr(isObj, lObj, lNotObj);
|
|
6175
6828
|
B.startBlock(lObj);
|
|
6176
|
-
this.declare(`declare ptr @scr_dyn_obj_get(ptr, ptr,
|
|
6829
|
+
this.declare(`declare ptr @scr_dyn_obj_get(ptr, ptr, ${this.sizeType})`);
|
|
6177
6830
|
const keyBytes = Buffer.byteLength(e.key, "utf8");
|
|
6178
6831
|
const m = B.tmp();
|
|
6179
6832
|
const has = B.tmp();
|
|
6180
|
-
B.line(`${m} = call ptr @scr_dyn_obj_get(ptr ${d.name}, ptr ${this.cstr(e.key)},
|
|
6833
|
+
B.line(`${m} = call ptr @scr_dyn_obj_get(ptr ${d.name}, ptr ${this.cstr(e.key)}, ${this.sizeType} ${keyBytes})`);
|
|
6181
6834
|
B.line(`${has} = icmp ne ptr ${m}, null`);
|
|
6182
6835
|
B.line(`store i1 ${has}, ptr ${slot}`);
|
|
6183
6836
|
B.br(lj);
|
|
@@ -6195,8 +6848,8 @@ class LlEmitter {
|
|
|
6195
6848
|
const len = B.tmp();
|
|
6196
6849
|
const inR = B.tmp();
|
|
6197
6850
|
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
|
|
6851
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenp}`);
|
|
6852
|
+
B.line(`${inR} = icmp ugt ${this.sizeType} ${len}, ${e.key}`);
|
|
6200
6853
|
B.line(`store i1 ${inR}, ptr ${slot}`);
|
|
6201
6854
|
}
|
|
6202
6855
|
B.br(lj);
|
|
@@ -6309,10 +6962,10 @@ class LlEmitter {
|
|
|
6309
6962
|
const lj = B.newLabel("dts.j");
|
|
6310
6963
|
B.condBr(isObj, lObj, lj);
|
|
6311
6964
|
B.startBlock(lObj);
|
|
6312
|
-
this.declare(`declare ptr @scr_dyn_obj_get(ptr, ptr,
|
|
6965
|
+
this.declare(`declare ptr @scr_dyn_obj_get(ptr, ptr, ${this.sizeType})`);
|
|
6313
6966
|
const m = B.tmp();
|
|
6314
6967
|
const has = B.tmp();
|
|
6315
|
-
B.line(`${m} = call ptr @scr_dyn_obj_get(ptr ${d.name}, ptr ${this.cstr("%error")},
|
|
6968
|
+
B.line(`${m} = call ptr @scr_dyn_obj_get(ptr ${d.name}, ptr ${this.cstr("%error")}, ${this.sizeType} 6)`);
|
|
6316
6969
|
B.line(`${has} = icmp ne ptr ${m}, null`);
|
|
6317
6970
|
B.line(`store i1 ${has}, ptr ${slot}`);
|
|
6318
6971
|
B.br(lj);
|
|
@@ -6420,7 +7073,7 @@ class LlEmitter {
|
|
|
6420
7073
|
}
|
|
6421
7074
|
const helper = this.dyn.dynIterNHelper();
|
|
6422
7075
|
const t = B.tmp();
|
|
6423
|
-
B.line(`${t} = call ptr @${helper}(ptr ${v.name},
|
|
7076
|
+
B.line(`${t} = call ptr @${helper}(ptr ${v.name}, ${this.sizeType} ${e.count})`);
|
|
6424
7077
|
const out = this.own({ name: t, type: e.type });
|
|
6425
7078
|
this.emitPendingCheck();
|
|
6426
7079
|
return out;
|
|
@@ -7174,13 +7827,13 @@ class LlEmitter {
|
|
|
7174
7827
|
this.resolveThunkDefs.push(...d);
|
|
7175
7828
|
return sym;
|
|
7176
7829
|
}
|
|
7177
|
-
/** Loads a dyn node's kind tag
|
|
7830
|
+
/** Loads a dyn node's kind tag after its size_t RC word — the dyn expression tests'
|
|
7178
7831
|
* shared read. */
|
|
7179
7832
|
dynKind(d) {
|
|
7180
7833
|
const B = this.B;
|
|
7181
7834
|
const p = B.tmp();
|
|
7182
7835
|
const k = B.tmp();
|
|
7183
|
-
B.line(`${p} = getelementptr inbounds i8, ptr ${d}, i64 8 ; ->kind`);
|
|
7836
|
+
B.line(`${p} = getelementptr inbounds i8, ptr ${d}, i64 ${this.sizeType === "i32" ? 4 : 8} ; ->kind`);
|
|
7184
7837
|
B.line(`${k} = load i32, ptr ${p}`);
|
|
7185
7838
|
return k;
|
|
7186
7839
|
}
|
|
@@ -7486,11 +8139,11 @@ class LlEmitter {
|
|
|
7486
8139
|
}
|
|
7487
8140
|
this.declare(`declare ptr @scr_union_new_f64(i32, double)`);
|
|
7488
8141
|
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
|
|
8142
|
+
this.declare(`declare ptr @scr_str_new(ptr, ${this.sizeType})`);
|
|
8143
|
+
this.declare(`declare ${this.sizeType} @strlen(ptr)`);
|
|
7491
8144
|
this.declare(`declare ptr @scr_str_retain_v(ptr)`);
|
|
7492
8145
|
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
|
|
8146
|
+
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
8147
|
return sym;
|
|
7495
8148
|
}
|
|
7496
8149
|
/** Interned per-union child-stream data adapter — emit-async.ts's
|
|
@@ -7521,8 +8174,8 @@ class LlEmitter {
|
|
|
7521
8174
|
* POINTER-SIZE slots off the emit tuple's va_list (textual LLVM IR
|
|
7522
8175
|
* cannot va_arg portably) and calls this function behind the wrapper
|
|
7523
8176
|
* closure's fn. It re-types each slot to the listener's declared
|
|
7524
|
-
* parameter (f64
|
|
7525
|
-
*
|
|
8177
|
+
* parameter (f64/bool scalars load from the emit site's stack slot,
|
|
8178
|
+
* refcounted values retain the direct pointer — the callee owns +1 per the
|
|
7526
8179
|
* universal convention) and calls the ORIGINAL listener held by the
|
|
7527
8180
|
* wrapper's one capture box. A non-void result is discarded (refcounted
|
|
7528
8181
|
* ones released) — Node ignores listener return values. Interned per
|
|
@@ -7556,11 +8209,11 @@ class LlEmitter {
|
|
|
7556
8209
|
cbT.params.forEach((p, i) => {
|
|
7557
8210
|
const ty = this.llType(p);
|
|
7558
8211
|
if (ty === "double") {
|
|
7559
|
-
d.push(` %
|
|
8212
|
+
d.push(` %d${i} = load double, ptr %a${i}`);
|
|
7560
8213
|
passed.push(`double %d${i}`);
|
|
7561
8214
|
}
|
|
7562
8215
|
else if (ty === "i1") {
|
|
7563
|
-
d.push(` %
|
|
8216
|
+
d.push(` %b${i} = load i1, ptr %a${i}`);
|
|
7564
8217
|
passed.push(`i1 %b${i}`);
|
|
7565
8218
|
}
|
|
7566
8219
|
else if (isRefCounted(p)) {
|
|
@@ -7592,11 +8245,11 @@ class LlEmitter {
|
|
|
7592
8245
|
* registration call it feeds always moves it into the registry. */
|
|
7593
8246
|
wrapEmitterListener(target, adapterFn) {
|
|
7594
8247
|
const B = this.B;
|
|
7595
|
-
this.declare(`declare ptr @scr_closure_new(ptr,
|
|
8248
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
7596
8249
|
this.declare(`declare ptr @scr_box_new(i32)`);
|
|
7597
8250
|
this.declare(`declare void @scr_box_set_ref(ptr, ptr)`);
|
|
7598
8251
|
const ad = B.tmp();
|
|
7599
|
-
B.line(`${ad} = call ptr @scr_closure_new(ptr @${adapterFn},
|
|
8252
|
+
B.line(`${ad} = call ptr @scr_closure_new(ptr @${adapterFn}, ${this.sizeType} 1)`);
|
|
7600
8253
|
const bx = B.tmp();
|
|
7601
8254
|
B.line(`${bx} = call ptr @scr_box_new(i32 4) ; SCR_BOX_FUNC`);
|
|
7602
8255
|
const capsp = B.tmp();
|
|
@@ -7672,7 +8325,7 @@ class LlEmitter {
|
|
|
7672
8325
|
throw new Error("llvm emitter bug: bound-close err union lacks its undefined arm");
|
|
7673
8326
|
trampoline = `${sym}_cb`;
|
|
7674
8327
|
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,
|
|
8328
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
7676
8329
|
this.declare(`declare ptr @scr_box_new(i32)`);
|
|
7677
8330
|
this.declare(`declare void @scr_box_set_ref(ptr, ptr)`);
|
|
7678
8331
|
}
|
|
@@ -7695,7 +8348,7 @@ class LlEmitter {
|
|
|
7695
8348
|
` %pv = load ptr, ptr %pp`,
|
|
7696
8349
|
];
|
|
7697
8350
|
if (oneParam) {
|
|
7698
|
-
d.push(` %reg = call ptr @scr_closure_new(ptr @${trampoline},
|
|
8351
|
+
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
8352
|
}
|
|
7700
8353
|
else {
|
|
7701
8354
|
d.push(` %reg = call ptr @scr_closure_retain_v(ptr %pv)`, ` store ptr %reg, ptr %regslot`);
|
|
@@ -7791,8 +8444,8 @@ class LlEmitter {
|
|
|
7791
8444
|
? "a 'data' listener declaring a Buffer chunk received a string (the stream has an encoding set)"
|
|
7792
8445
|
: "a 'data' listener declaring a string chunk received a Buffer (call setEncoding, or declare the chunk as a Buffer)";
|
|
7793
8446
|
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)},
|
|
8447
|
+
this.declare(`declare void @scr_throw_error_msg(i32, ptr, ${this.sizeType})`);
|
|
8448
|
+
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
8449
|
finish("%r0");
|
|
7797
8450
|
d.push(`}`, ``);
|
|
7798
8451
|
}
|
|
@@ -7988,13 +8641,13 @@ class LlEmitter {
|
|
|
7988
8641
|
// The stream-owning completion closure (a 1-cap closure boxing the
|
|
7989
8642
|
// retained stream) — shared by the typed and dyn done shapes.
|
|
7990
8643
|
const doneClosure = (fnRef, tag) => {
|
|
7991
|
-
this.declare(`declare ptr @scr_closure_new(ptr,
|
|
8644
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
7992
8645
|
this.declare(`declare ptr @scr_box_new_obj(ptr, ptr, ptr)`);
|
|
7993
8646
|
this.declare(`declare void @scr_box_set_ref(ptr, ptr)`);
|
|
7994
8647
|
this.declare(`declare ptr @scr_stream_retain_v(ptr)`);
|
|
7995
8648
|
this.declare(`declare void @scr_stream_release_v(ptr)`);
|
|
7996
8649
|
this.declare(`declare void @scr_stream_trace(ptr, ptr, ptr)`);
|
|
7997
|
-
d.push(` %${tag}clo = call ptr @scr_closure_new(ptr ${fnRef},
|
|
8650
|
+
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
8651
|
return `%${tag}clo`;
|
|
7999
8652
|
};
|
|
8000
8653
|
for (let i = off; i < declared.length; i++) {
|
|
@@ -8023,10 +8676,10 @@ class LlEmitter {
|
|
|
8023
8676
|
passed.push(`ptr %dc${i}`);
|
|
8024
8677
|
}
|
|
8025
8678
|
else if (isEncPos) {
|
|
8026
|
-
this.declare(`declare ptr @scr_str_new(ptr,
|
|
8679
|
+
this.declare(`declare ptr @scr_str_new(ptr, ${this.sizeType})`);
|
|
8027
8680
|
this.declare(`declare ptr @scr_dyn_new_str(ptr)`);
|
|
8028
8681
|
this.declare(`declare void @scr_str_release(ptr)`);
|
|
8029
|
-
d.push(` %es${i} = call ptr @scr_str_new(ptr ${this.cstr("buffer")},
|
|
8682
|
+
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
8683
|
passed.push(`ptr %ed${i}`);
|
|
8031
8684
|
}
|
|
8032
8685
|
else if (isErrPos) {
|
|
@@ -8048,7 +8701,7 @@ class LlEmitter {
|
|
|
8048
8701
|
}
|
|
8049
8702
|
else if (isDonePos) {
|
|
8050
8703
|
const glue = `scr_stream_done_dyn_${kind}`;
|
|
8051
|
-
this.declare(`declare ptr @${glue}(ptr, ptr,
|
|
8704
|
+
this.declare(`declare ptr @${glue}(ptr, ptr, ${this.sizeType})`);
|
|
8052
8705
|
this.declare(`declare ptr @scr_dyn_new_func(ptr, ptr, i32, ptr, ptr)`);
|
|
8053
8706
|
const clo = doneClosure(`@${glue}`, `dd${i}`);
|
|
8054
8707
|
const arity = kind === "t" || kind === "l" ? 2 : 1;
|
|
@@ -8068,8 +8721,8 @@ class LlEmitter {
|
|
|
8068
8721
|
}
|
|
8069
8722
|
else if (isEncPos) {
|
|
8070
8723
|
// 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")},
|
|
8724
|
+
this.declare(`declare ptr @scr_str_new(ptr, ${this.sizeType})`);
|
|
8725
|
+
d.push(` %en${i} = call ptr @scr_str_new(ptr ${this.cstr("buffer")}, ${this.sizeType} 6)`);
|
|
8073
8726
|
passed.push(`ptr %en${i}`);
|
|
8074
8727
|
}
|
|
8075
8728
|
else if (isErrPos) {
|
|
@@ -8872,7 +9525,7 @@ class LlEmitter {
|
|
|
8872
9525
|
if (slot === undefined)
|
|
8873
9526
|
return null;
|
|
8874
9527
|
const index = this.B.tmp();
|
|
8875
|
-
this.B.line(`${index} = load
|
|
9528
|
+
this.B.line(`${index} = load ${this.sizeType}, ptr ${slot}`);
|
|
8876
9529
|
return index;
|
|
8877
9530
|
}
|
|
8878
9531
|
/** Bounds-check a typed-array element index without an out-of-line call
|
|
@@ -8884,16 +9537,16 @@ class LlEmitter {
|
|
|
8884
9537
|
const lenPtr = B.tmp();
|
|
8885
9538
|
const len = B.tmp();
|
|
8886
9539
|
B.line(`${lenPtr} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 1`);
|
|
8887
|
-
B.line(`${len} = load
|
|
9540
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}`);
|
|
8888
9541
|
if (integerIndex) {
|
|
8889
9542
|
const inRange = B.tmp();
|
|
8890
|
-
B.line(`${inRange} = icmp ult
|
|
9543
|
+
B.line(`${inRange} = icmp ult ${this.sizeType} ${index}, ${len}`);
|
|
8891
9544
|
const invalid = B.newLabel("bytes.index.invalid");
|
|
8892
9545
|
const valid = B.newLabel("bytes.index.valid");
|
|
8893
9546
|
B.condBr(inRange, valid, invalid);
|
|
8894
9547
|
B.startBlock(invalid);
|
|
8895
9548
|
const indexF64 = B.tmp();
|
|
8896
|
-
B.line(`${indexF64} = uitofp
|
|
9549
|
+
B.line(`${indexF64} = uitofp ${this.sizeType} ${index} to double`);
|
|
8897
9550
|
this.declare(`declare double @scr_bytes_get(ptr, double)`);
|
|
8898
9551
|
B.line(`call double @scr_bytes_get(ptr ${receiver}, double ${indexF64})`);
|
|
8899
9552
|
B.terminate("unreachable");
|
|
@@ -8904,7 +9557,7 @@ class LlEmitter {
|
|
|
8904
9557
|
const nonnegative = B.tmp();
|
|
8905
9558
|
const belowLen = B.tmp();
|
|
8906
9559
|
const inRange = B.tmp();
|
|
8907
|
-
B.line(`${lenF64} = uitofp
|
|
9560
|
+
B.line(`${lenF64} = uitofp ${this.sizeType} ${len} to double`);
|
|
8908
9561
|
B.line(`${nonnegative} = fcmp oge double ${index}, ${f64Lit(0)}`);
|
|
8909
9562
|
B.line(`${belowLen} = fcmp olt double ${index}, ${lenF64}`);
|
|
8910
9563
|
B.line(`${inRange} = and i1 ${nonnegative}, ${belowLen}`);
|
|
@@ -8916,8 +9569,8 @@ class LlEmitter {
|
|
|
8916
9569
|
const idx = B.tmp();
|
|
8917
9570
|
const roundTrip = B.tmp();
|
|
8918
9571
|
const integral = B.tmp();
|
|
8919
|
-
B.line(`${idx} = fptoui double ${index} to
|
|
8920
|
-
B.line(`${roundTrip} = uitofp
|
|
9572
|
+
B.line(`${idx} = fptoui double ${index} to ${this.sizeType}`);
|
|
9573
|
+
B.line(`${roundTrip} = uitofp ${this.sizeType} ${idx} to double`);
|
|
8921
9574
|
B.line(`${integral} = fcmp oeq double ${roundTrip}, ${index}`);
|
|
8922
9575
|
B.condBr(integral, valid, invalid);
|
|
8923
9576
|
B.startBlock(invalid);
|
|
@@ -8941,12 +9594,12 @@ class LlEmitter {
|
|
|
8941
9594
|
const p = B.tmp();
|
|
8942
9595
|
const len = B.tmp();
|
|
8943
9596
|
B.line(`${p} = getelementptr inbounds %ScrBytes, ptr ${receiver}, i64 0, i32 1`);
|
|
8944
|
-
B.line(`${len} = load
|
|
9597
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${p}`);
|
|
8945
9598
|
const count = bytes && elem !== "u8" ? B.tmp() : len;
|
|
8946
9599
|
if (count !== len)
|
|
8947
|
-
B.line(`${count} = shl
|
|
9600
|
+
B.line(`${count} = shl ${this.sizeType} ${len}, 2`);
|
|
8948
9601
|
const out = B.tmp();
|
|
8949
|
-
B.line(`${out} = uitofp
|
|
9602
|
+
B.line(`${out} = uitofp ${this.sizeType} ${count} to double`);
|
|
8950
9603
|
return { name: out, type: F64 };
|
|
8951
9604
|
}
|
|
8952
9605
|
/** Kind-specialized typed-array load. */
|
|
@@ -8959,7 +9612,7 @@ class LlEmitter {
|
|
|
8959
9612
|
const raw = B.tmp();
|
|
8960
9613
|
const wide = B.tmp();
|
|
8961
9614
|
const out = B.tmp();
|
|
8962
|
-
B.line(`${p} = getelementptr inbounds i8, ptr ${data},
|
|
9615
|
+
B.line(`${p} = getelementptr inbounds i8, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
8963
9616
|
B.line(`${raw} = load i8, ptr ${p}, align 1`);
|
|
8964
9617
|
B.line(`${wide} = zext i8 ${raw} to i32`);
|
|
8965
9618
|
B.line(`${out} = uitofp i32 ${wide} to double`);
|
|
@@ -8968,14 +9621,14 @@ class LlEmitter {
|
|
|
8968
9621
|
if (elem === "f32") {
|
|
8969
9622
|
const raw = B.tmp();
|
|
8970
9623
|
const out = B.tmp();
|
|
8971
|
-
B.line(`${p} = getelementptr inbounds float, ptr ${data},
|
|
9624
|
+
B.line(`${p} = getelementptr inbounds float, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
8972
9625
|
B.line(`${raw} = load float, ptr ${p}, align 1`);
|
|
8973
9626
|
B.line(`${out} = fpext float ${raw} to double`);
|
|
8974
9627
|
return { name: out, type: F64 };
|
|
8975
9628
|
}
|
|
8976
9629
|
const raw = B.tmp();
|
|
8977
9630
|
const out = B.tmp();
|
|
8978
|
-
B.line(`${p} = getelementptr inbounds i32, ptr ${data},
|
|
9631
|
+
B.line(`${p} = getelementptr inbounds i32, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
8979
9632
|
B.line(`${raw} = load i32, ptr ${p}, align 1`);
|
|
8980
9633
|
B.line(`${out} = ${elem === "i32" ? "sitofp" : "uitofp"} i32 ${raw} to double`);
|
|
8981
9634
|
return { name: out, type: F64 };
|
|
@@ -9053,18 +9706,18 @@ class LlEmitter {
|
|
|
9053
9706
|
if (elem === "u8") {
|
|
9054
9707
|
const byte = B.tmp();
|
|
9055
9708
|
B.line(`${byte} = trunc i32 ${stored} to i8`);
|
|
9056
|
-
B.line(`${p} = getelementptr inbounds i8, ptr ${data},
|
|
9709
|
+
B.line(`${p} = getelementptr inbounds i8, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
9057
9710
|
B.line(`store i8 ${byte}, ptr ${p}, align 1`);
|
|
9058
9711
|
return;
|
|
9059
9712
|
}
|
|
9060
9713
|
if (elem === "f32") {
|
|
9061
9714
|
const narrowed = B.tmp();
|
|
9062
9715
|
B.line(`${narrowed} = fptrunc double ${value} to float`);
|
|
9063
|
-
B.line(`${p} = getelementptr inbounds float, ptr ${data},
|
|
9716
|
+
B.line(`${p} = getelementptr inbounds float, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
9064
9717
|
B.line(`store float ${narrowed}, ptr ${p}, align 1`);
|
|
9065
9718
|
return;
|
|
9066
9719
|
}
|
|
9067
|
-
B.line(`${p} = getelementptr inbounds i32, ptr ${data},
|
|
9720
|
+
B.line(`${p} = getelementptr inbounds i32, ptr ${data}, ${this.sizeType} ${idx}`);
|
|
9068
9721
|
B.line(`store i32 ${stored}, ptr ${p}, align 1`);
|
|
9069
9722
|
}
|
|
9070
9723
|
/** The bytesIntrinsic surface (emit-exprs.ts's switch, .ll flavored).
|
|
@@ -9698,7 +10351,7 @@ class LlEmitter {
|
|
|
9698
10351
|
const commit = `${snapshot}_commit`;
|
|
9699
10352
|
const check = this.dyn.dynCheckHelper(t);
|
|
9700
10353
|
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
|
|
10354
|
+
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
10355
|
return `@${commit}`;
|
|
9703
10356
|
}
|
|
9704
10357
|
if (t.kind !== "record")
|
|
@@ -9758,7 +10411,7 @@ class LlEmitter {
|
|
|
9758
10411
|
}
|
|
9759
10412
|
const sym = `sc_ldu_${this.liveDynUnionRefAdapters.size}`;
|
|
9760
10413
|
this.liveDynUnionRefAdapters.set(key, sym);
|
|
9761
|
-
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr,
|
|
10414
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
9762
10415
|
const adapters = new Map();
|
|
9763
10416
|
for (const { arm, tag } of mutableArms) {
|
|
9764
10417
|
const prefix = `${sym}_${tag}`;
|
|
@@ -9782,7 +10435,7 @@ class LlEmitter {
|
|
|
9782
10435
|
const boxed = B.tmp();
|
|
9783
10436
|
B.line(`${payloadPtr} = getelementptr inbounds %ScrUnion, ptr %u, i64 0, i32 5`);
|
|
9784
10437
|
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)},
|
|
10438
|
+
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
10439
|
B.terminate(`ret ptr ${boxed}`);
|
|
9787
10440
|
});
|
|
9788
10441
|
B.startBlock(fallback);
|
|
@@ -9809,8 +10462,8 @@ class LlEmitter {
|
|
|
9809
10462
|
const nested = this.streamTypedRefMaterializeAdapter(t, ctx);
|
|
9810
10463
|
const rc = vAdapters(this, t);
|
|
9811
10464
|
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)},
|
|
10465
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
10466
|
+
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
10467
|
return boxed;
|
|
9815
10468
|
}
|
|
9816
10469
|
/** LLVM twin of the C stream materializer: mutable reference children
|
|
@@ -9865,7 +10518,7 @@ class LlEmitter {
|
|
|
9865
10518
|
}
|
|
9866
10519
|
else {
|
|
9867
10520
|
this.declare(`declare ptr @scr_dyn_new_obj()`);
|
|
9868
|
-
this.declare(`declare void @scr_dyn_obj_set(ptr, ptr,
|
|
10521
|
+
this.declare(`declare void @scr_dyn_obj_set(ptr, ptr, ${this.sizeType}, ptr)`);
|
|
9869
10522
|
const out = B.tmp();
|
|
9870
10523
|
B.line(`${out} = call ptr @scr_dyn_new_obj()`);
|
|
9871
10524
|
const byName = new Map(shape.fields.map((field) => [field.name, field]));
|
|
@@ -9887,7 +10540,7 @@ class LlEmitter {
|
|
|
9887
10540
|
fieldValue = boolValue;
|
|
9888
10541
|
}
|
|
9889
10542
|
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)},
|
|
10543
|
+
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
10544
|
}
|
|
9892
10545
|
B.terminate(`ret ptr ${out}`);
|
|
9893
10546
|
}
|
|
@@ -9994,7 +10647,7 @@ class LlEmitter {
|
|
|
9994
10647
|
B.line(`${boxed} = call ptr @${this.dyn.toDynHelper(elem)}(ptr ${value})`);
|
|
9995
10648
|
}
|
|
9996
10649
|
else {
|
|
9997
|
-
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr,
|
|
10650
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
9998
10651
|
const boxedSlot = B.slot();
|
|
9999
10652
|
B.entryAllocas.push(`${boxedSlot} = alloca ptr`);
|
|
10000
10653
|
const tagPtr = B.tmp();
|
|
@@ -10016,7 +10669,7 @@ class LlEmitter {
|
|
|
10016
10669
|
const armBoxed = B.tmp();
|
|
10017
10670
|
B.line(`${payloadPtr} = getelementptr inbounds %ScrUnion, ptr ${value}, i64 0, i32 5`);
|
|
10018
10671
|
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)},
|
|
10672
|
+
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
10673
|
B.line(`store ptr ${armBoxed}, ptr ${boxedSlot}`);
|
|
10021
10674
|
B.br(join);
|
|
10022
10675
|
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 +10696,8 @@ class LlEmitter {
|
|
|
10043
10696
|
commit = this.streamTypedRefCommitAdapter(elem, snapshot);
|
|
10044
10697
|
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
10698
|
}
|
|
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},
|
|
10699
|
+
this.declare(`declare ptr @scr_dyn_new_typed_ref(ptr, ptr, ptr, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
10700
|
+
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
10701
|
}
|
|
10049
10702
|
else {
|
|
10050
10703
|
boxed = B.tmp();
|
|
@@ -10785,16 +11438,16 @@ class LlEmitter {
|
|
|
10785
11438
|
const tag6 = infoDef.arms.findIndex((a) => a.kind === "record" && this.recordsById.get(a.shapeId)?.fields.find((f) => f.name === "scopeid")?.type.kind === "f64");
|
|
10786
11439
|
const tag4 = 1 - tag6;
|
|
10787
11440
|
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,
|
|
11441
|
+
this.declare(`declare ${this.sizeType} @scr_os_ifaddrs_count(ptr)`);
|
|
11442
|
+
this.declare(`declare ptr @scr_os_ifaddrs_name(ptr, ${this.sizeType})`);
|
|
11443
|
+
this.declare(`declare ptr @scr_os_ifaddrs_address(ptr, ${this.sizeType})`);
|
|
11444
|
+
this.declare(`declare ptr @scr_os_ifaddrs_netmask(ptr, ${this.sizeType})`);
|
|
11445
|
+
this.declare(`declare ptr @scr_os_ifaddrs_family(ptr, ${this.sizeType})`);
|
|
11446
|
+
this.declare(`declare ptr @scr_os_ifaddrs_mac(ptr, ${this.sizeType})`);
|
|
11447
|
+
this.declare(`declare zeroext i1 @scr_os_ifaddrs_internal(ptr, ${this.sizeType})`);
|
|
11448
|
+
this.declare(`declare zeroext i1 @scr_os_ifaddrs_ipv6(ptr, ${this.sizeType})`);
|
|
11449
|
+
this.declare(`declare ptr @scr_os_ifaddrs_cidr(ptr, ${this.sizeType})`);
|
|
11450
|
+
this.declare(`declare double @scr_os_ifaddrs_scopeid(ptr, ${this.sizeType})`);
|
|
10798
11451
|
this.declare(`declare void @scr_os_ifaddrs_free(ptr)`);
|
|
10799
11452
|
this.declare(`declare ptr @scr_union_new_ref(i32, ptr, ptr, ptr, ptr)`);
|
|
10800
11453
|
this.declare(`declare ptr @scr_union_retain_v(ptr)`);
|
|
@@ -10813,11 +11466,11 @@ class LlEmitter {
|
|
|
10813
11466
|
const snap = B.tmp();
|
|
10814
11467
|
const cnt = B.tmp();
|
|
10815
11468
|
B.line(`${snap} = call ptr @scr_os_ifaddrs()`);
|
|
10816
|
-
B.line(`${cnt} = call
|
|
11469
|
+
B.line(`${cnt} = call ${this.sizeType} @scr_os_ifaddrs_count(ptr ${snap})`);
|
|
10817
11470
|
const iSlot = B.slot();
|
|
10818
11471
|
const rowSlot = B.slot();
|
|
10819
|
-
B.entryAllocas.push(`${iSlot} = alloca
|
|
10820
|
-
B.line(`store
|
|
11472
|
+
B.entryAllocas.push(`${iSlot} = alloca ${this.sizeType}`, `${rowSlot} = alloca ptr`);
|
|
11473
|
+
B.line(`store ${this.sizeType} 0, ptr ${iSlot}`);
|
|
10821
11474
|
const lc = B.newLabel("ni.c");
|
|
10822
11475
|
const lb = B.newLabel("ni.b");
|
|
10823
11476
|
const le = B.newLabel("ni.e");
|
|
@@ -10825,12 +11478,12 @@ class LlEmitter {
|
|
|
10825
11478
|
B.startBlock(lc);
|
|
10826
11479
|
const i = B.tmp();
|
|
10827
11480
|
const cont = B.tmp();
|
|
10828
|
-
B.line(`${i} = load
|
|
10829
|
-
B.line(`${cont} = icmp ult
|
|
11481
|
+
B.line(`${i} = load ${this.sizeType}, ptr ${iSlot}`);
|
|
11482
|
+
B.line(`${cont} = icmp ult ${this.sizeType} ${i}, ${cnt}`);
|
|
10830
11483
|
B.condBr(cont, lb, le);
|
|
10831
11484
|
B.startBlock(lb);
|
|
10832
11485
|
const isV6 = B.tmp();
|
|
10833
|
-
B.line(`${isV6} = call zeroext i1 @scr_os_ifaddrs_ipv6(ptr ${snap},
|
|
11486
|
+
B.line(`${isV6} = call zeroext i1 @scr_os_ifaddrs_ipv6(ptr ${snap}, ${this.sizeType} ${i})`);
|
|
10834
11487
|
const l6 = B.newLabel("ni.v6");
|
|
10835
11488
|
const l4 = B.newLabel("ni.v4");
|
|
10836
11489
|
const lRow = B.newLabel("ni.r");
|
|
@@ -10857,14 +11510,14 @@ class LlEmitter {
|
|
|
10857
11510
|
["mac", "scr_os_ifaddrs_mac"],
|
|
10858
11511
|
]) {
|
|
10859
11512
|
const v = B.tmp();
|
|
10860
|
-
B.line(`${v} = call ptr @${sym}(ptr ${snap},
|
|
11513
|
+
B.line(`${v} = call ptr @${sym}(ptr ${snap}, ${this.sizeType} ${i}) ; +1`);
|
|
10861
11514
|
B.line(`store ptr ${v}, ptr ${this.recordFieldPtr(r, t.shapeId, field).ptr}`);
|
|
10862
11515
|
}
|
|
10863
11516
|
const internal = B.tmp();
|
|
10864
|
-
B.line(`${internal} = call zeroext i1 @scr_os_ifaddrs_internal(ptr ${snap},
|
|
11517
|
+
B.line(`${internal} = call zeroext i1 @scr_os_ifaddrs_internal(ptr ${snap}, ${this.sizeType} ${i})`);
|
|
10865
11518
|
this.storeField(this.recordFieldPtr(r, t.shapeId, "internal").ptr, { kind: "bool" }, internal);
|
|
10866
11519
|
const cs = B.tmp();
|
|
10867
|
-
B.line(`${cs} = call ptr @scr_os_ifaddrs_cidr(ptr ${snap},
|
|
11520
|
+
B.line(`${cs} = call ptr @scr_os_ifaddrs_cidr(ptr ${snap}, ${this.sizeType} ${i}) ; +1 or null`);
|
|
10868
11521
|
const hasCidr = B.tmp();
|
|
10869
11522
|
B.line(`${hasCidr} = icmp ne ptr ${cs}, null`);
|
|
10870
11523
|
const lcs = B.newLabel("ni.cs");
|
|
@@ -10889,7 +11542,7 @@ class LlEmitter {
|
|
|
10889
11542
|
B.line(`store ptr ${cv}, ptr ${this.recordFieldPtr(r, t.shapeId, "cidr").ptr}`);
|
|
10890
11543
|
if (v6) {
|
|
10891
11544
|
const sc = B.tmp();
|
|
10892
|
-
B.line(`${sc} = call double @scr_os_ifaddrs_scopeid(ptr ${snap},
|
|
11545
|
+
B.line(`${sc} = call double @scr_os_ifaddrs_scopeid(ptr ${snap}, ${this.sizeType} ${i})`);
|
|
10893
11546
|
this.storeField(this.recordFieldPtr(r, t.shapeId, "scopeid").ptr, F64, sc);
|
|
10894
11547
|
}
|
|
10895
11548
|
else {
|
|
@@ -10915,7 +11568,7 @@ class LlEmitter {
|
|
|
10915
11568
|
const row = B.tmp();
|
|
10916
11569
|
B.line(`${row} = load ptr, ptr ${rowSlot}`);
|
|
10917
11570
|
const nm = B.tmp();
|
|
10918
|
-
B.line(`${nm} = call ptr @scr_os_ifaddrs_name(ptr ${snap},
|
|
11571
|
+
B.line(`${nm} = call ptr @scr_os_ifaddrs_name(ptr ${snap}, ${this.sizeType} ${i}) ; +1`);
|
|
10919
11572
|
const cell = B.tmp();
|
|
10920
11573
|
B.line(`${cell} = call ptr @scr_map_get_str_ref(ptr ${ovf}, ptr ${nm})`);
|
|
10921
11574
|
const hasCell = B.tmp();
|
|
@@ -10951,8 +11604,8 @@ class LlEmitter {
|
|
|
10951
11604
|
B.line(`call void @scr_arr_release(ptr ${rows})`);
|
|
10952
11605
|
B.line(`call void @scr_str_release(ptr ${nm})`);
|
|
10953
11606
|
const i2 = B.tmp();
|
|
10954
|
-
B.line(`${i2} = add
|
|
10955
|
-
B.line(`store
|
|
11607
|
+
B.line(`${i2} = add ${this.sizeType} ${i}, 1`);
|
|
11608
|
+
B.line(`store ${this.sizeType} ${i2}, ptr ${iSlot}`);
|
|
10956
11609
|
B.br(lc);
|
|
10957
11610
|
B.startBlock(le);
|
|
10958
11611
|
B.line(`call void @scr_os_ifaddrs_free(ptr ${snap})`);
|
|
@@ -10969,21 +11622,21 @@ class LlEmitter {
|
|
|
10969
11622
|
const recT = e.type.elem;
|
|
10970
11623
|
const path = this.emitExpr(e.args[0]);
|
|
10971
11624
|
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,
|
|
11625
|
+
this.declare(`declare ${this.sizeType} @scr_fs_scandir_count(ptr)`);
|
|
11626
|
+
this.declare(`declare ptr @scr_fs_scandir_name(ptr, ${this.sizeType})`);
|
|
11627
|
+
this.declare(`declare double @scr_fs_scandir_type(ptr, ${this.sizeType})`);
|
|
10975
11628
|
this.declare(`declare void @scr_fs_scandir_free(ptr)`);
|
|
10976
11629
|
const snap = B.tmp();
|
|
10977
11630
|
B.line(`${snap} = call ptr @scr_fs_scandir(ptr ${path.name})`);
|
|
10978
11631
|
this.emitPendingCheck();
|
|
10979
11632
|
const cnt = B.tmp();
|
|
10980
|
-
B.line(`${cnt} = call
|
|
11633
|
+
B.line(`${cnt} = call ${this.sizeType} @scr_fs_scandir_count(ptr ${snap})`);
|
|
10981
11634
|
const arr = B.tmp();
|
|
10982
11635
|
B.line(`${arr} = ${arrNewCall(this, recT, cnt)}`);
|
|
10983
11636
|
const out = this.own({ name: arr, type: e.type });
|
|
10984
11637
|
const iSlot = B.slot();
|
|
10985
|
-
B.entryAllocas.push(`${iSlot} = alloca
|
|
10986
|
-
B.line(`store
|
|
11638
|
+
B.entryAllocas.push(`${iSlot} = alloca ${this.sizeType}`);
|
|
11639
|
+
B.line(`store ${this.sizeType} 0, ptr ${iSlot}`);
|
|
10987
11640
|
const lc = B.newLabel("sd.c");
|
|
10988
11641
|
const lb = B.newLabel("sd.b");
|
|
10989
11642
|
const le = B.newLabel("sd.e");
|
|
@@ -10991,23 +11644,23 @@ class LlEmitter {
|
|
|
10991
11644
|
B.startBlock(lc);
|
|
10992
11645
|
const i = B.tmp();
|
|
10993
11646
|
const cont = B.tmp();
|
|
10994
|
-
B.line(`${i} = load
|
|
10995
|
-
B.line(`${cont} = icmp ult
|
|
11647
|
+
B.line(`${i} = load ${this.sizeType}, ptr ${iSlot}`);
|
|
11648
|
+
B.line(`${cont} = icmp ult ${this.sizeType} ${i}, ${cnt}`);
|
|
10996
11649
|
B.condBr(cont, lb, le);
|
|
10997
11650
|
B.startBlock(lb);
|
|
10998
11651
|
const row = B.tmp();
|
|
10999
11652
|
B.line(`${row} = call ptr @${mangleRecordNew(recT.shapeId)}()`);
|
|
11000
11653
|
const dt = B.tmp();
|
|
11001
|
-
B.line(`${dt} = call double @scr_fs_scandir_type(ptr ${snap},
|
|
11654
|
+
B.line(`${dt} = call double @scr_fs_scandir_type(ptr ${snap}, ${this.sizeType} ${i})`);
|
|
11002
11655
|
this.storeField(this.recordFieldPtr(row, recT.shapeId, "%dtype").ptr, F64, dt);
|
|
11003
11656
|
const nm = B.tmp();
|
|
11004
|
-
B.line(`${nm} = call ptr @scr_fs_scandir_name(ptr ${snap},
|
|
11657
|
+
B.line(`${nm} = call ptr @scr_fs_scandir_name(ptr ${snap}, ${this.sizeType} ${i}) ; +1`);
|
|
11005
11658
|
B.line(`store ptr ${nm}, ptr ${this.recordFieldPtr(row, recT.shapeId, "name").ptr}`);
|
|
11006
11659
|
B.line(`store ptr ${this.retainValue(path.name, STRING)}, ptr ${this.recordFieldPtr(row, recT.shapeId, "parentPath").ptr}`);
|
|
11007
11660
|
this.arrPush(arr, "ref", row); // push takes ownership of the row
|
|
11008
11661
|
const i2 = B.tmp();
|
|
11009
|
-
B.line(`${i2} = add
|
|
11010
|
-
B.line(`store
|
|
11662
|
+
B.line(`${i2} = add ${this.sizeType} ${i}, 1`);
|
|
11663
|
+
B.line(`store ${this.sizeType} ${i2}, ptr ${iSlot}`);
|
|
11011
11664
|
B.br(lc);
|
|
11012
11665
|
B.startBlock(le);
|
|
11013
11666
|
B.line(`call void @scr_fs_scandir_free(ptr ${snap})`);
|
|
@@ -11077,22 +11730,19 @@ class LlEmitter {
|
|
|
11077
11730
|
}
|
|
11078
11731
|
if (e.fn === "emitter.emit") {
|
|
11079
11732
|
// The variadic dispatch: the event's unified tuple rides the C
|
|
11080
|
-
// variadic tail POINTER-CLASSED
|
|
11081
|
-
//
|
|
11082
|
-
//
|
|
11733
|
+
// variadic tail POINTER-CLASSED. Scalar values ride pointers to
|
|
11734
|
+
// call-lived stack slots, while reference values ride directly; the
|
|
11735
|
+
// fixed shim can therefore read one pointer-width slot per argument
|
|
11736
|
+
// on both wasm32 and native targets. Every argument is borrowed. May
|
|
11083
11737
|
// throw (listeners run inside).
|
|
11084
11738
|
const args = e.args.map((a) => this.emitExpr(a));
|
|
11085
11739
|
const tuple = args.slice(2).map((a) => {
|
|
11086
11740
|
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}`;
|
|
11741
|
+
if (ty === "double" || ty === "i1") {
|
|
11742
|
+
const slot = B.slot();
|
|
11743
|
+
B.entryAllocas.push(`${slot} = alloca ${ty} ; EventEmitter scalar argument`);
|
|
11744
|
+
B.line(`store ${ty} ${a.name}, ptr ${slot}`);
|
|
11745
|
+
return `ptr ${slot}`;
|
|
11096
11746
|
}
|
|
11097
11747
|
return `ptr ${a.name}`;
|
|
11098
11748
|
});
|
|
@@ -11681,13 +12331,13 @@ class LlEmitter {
|
|
|
11681
12331
|
throw new Error("llvm emitter bug: net.serverCloseBind result not a func");
|
|
11682
12332
|
const args = e.args.map((a) => this.emitExpr(a));
|
|
11683
12333
|
const fnSym = this.closeBindThunkFor(e.type.params[0], e.type.ret.kind === "netServer");
|
|
11684
|
-
this.declare(`declare ptr @scr_closure_new(ptr,
|
|
12334
|
+
this.declare(`declare ptr @scr_closure_new(ptr, ${this.sizeType})`);
|
|
11685
12335
|
this.declare(`declare ptr @scr_box_new_obj(ptr, ptr, ptr)`);
|
|
11686
12336
|
this.declare(`declare void @scr_box_set_ref(ptr, ptr)`);
|
|
11687
12337
|
this.declare(`declare ptr @scr_net_server_retain_v(ptr)`);
|
|
11688
12338
|
this.declare(`declare void @scr_net_server_release_v(ptr)`);
|
|
11689
12339
|
const bound = B.tmp();
|
|
11690
|
-
B.line(`${bound} = call ptr @scr_closure_new(ptr @${fnSym},
|
|
12340
|
+
B.line(`${bound} = call ptr @scr_closure_new(ptr @${fnSym}, ${this.sizeType} 1)`);
|
|
11691
12341
|
const bx = B.tmp();
|
|
11692
12342
|
B.line(`${bx} = call ptr @scr_box_new_obj(ptr @scr_net_server_retain_v, ptr @scr_net_server_release_v, ptr null)`);
|
|
11693
12343
|
const capp = B.tmp();
|
|
@@ -11988,22 +12638,22 @@ class LlEmitter {
|
|
|
11988
12638
|
if (ca.type.kind === "string") {
|
|
11989
12639
|
caData = B.tmp();
|
|
11990
12640
|
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`);
|
|
12641
|
+
B.line(`${caLen} = load ${this.sizeType}, ptr ${caLenPtr}`);
|
|
12642
|
+
B.line(`${caData} = getelementptr inbounds i8, ptr ${ca.name}, i64 ${this.abiOffset(24, 12)}`);
|
|
11993
12643
|
}
|
|
11994
12644
|
else if (ca.type.kind === "bytes" && ca.type.elem === "u8") {
|
|
11995
12645
|
const caDataPtr = B.tmp();
|
|
11996
12646
|
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`);
|
|
12647
|
+
B.line(`${caLenPtr} = getelementptr inbounds i8, ptr ${ca.name}, i64 ${this.abiOffset(8, 4)}`);
|
|
12648
|
+
B.line(`${caLen} = load ${this.sizeType}, ptr ${caLenPtr}`);
|
|
12649
|
+
B.line(`${caDataPtr} = getelementptr inbounds i8, ptr ${ca.name}, i64 ${this.abiOffset(24, 12)}`);
|
|
12000
12650
|
B.line(`${caData} = load ptr, ptr ${caDataPtr}`);
|
|
12001
12651
|
}
|
|
12002
12652
|
else {
|
|
12003
12653
|
throw new Error(`llvm emitter bug: ${e.fn} CA is not a string or Buffer`);
|
|
12004
12654
|
}
|
|
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,
|
|
12655
|
+
callArgs = [...callArgs.slice(0, 8), `ptr ${caData}`, `${this.sizeType} ${caLen}`];
|
|
12656
|
+
this.declare(`declare ptr @scr_https_request(ptr, double, ptr, ptr, double, ptr, i1 zeroext, i1 zeroext, ptr, ${this.sizeType}, ptr, ptr)`);
|
|
12007
12657
|
}
|
|
12008
12658
|
else {
|
|
12009
12659
|
const decls = head.map((a) => (this.llType(a.type) === "i1" ? "i1 zeroext" : this.llType(a.type)));
|