@scriptc/compiler 0.2.5 → 0.2.6
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 +57 -30
- package/dist/backend/cycle-analysis.test.js +1 -1
- package/dist/backend/executable-features.js +1 -0
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/link-plan-core.d.ts +2 -0
- package/dist/backend/link-plan-core.js +1 -0
- package/dist/backend/link-plan-core.js.map +1 -1
- package/dist/backend/link-plan.d.ts +1 -0
- package/dist/backend/link-plan.js +3 -0
- package/dist/backend/link-plan.js.map +1 -1
- package/dist/backend/llvm/byte-numbers.js +32 -4
- package/dist/backend/llvm/byte-numbers.js.map +1 -1
- package/dist/backend/llvm/byte-windows.d.ts +31 -0
- package/dist/backend/llvm/byte-windows.js +334 -0
- package/dist/backend/llvm/byte-windows.js.map +1 -0
- package/dist/backend/llvm/byte-windows.test.d.ts +1 -0
- package/dist/backend/llvm/byte-windows.test.js +244 -0
- package/dist/backend/llvm/byte-windows.test.js.map +1 -0
- package/dist/backend/llvm/call-lifetimes.d.ts +2 -2
- package/dist/backend/llvm/call-lifetimes.js +17 -7
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/classes.d.ts +14 -1
- package/dist/backend/llvm/classes.js +80 -9
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.d.ts +1 -0
- package/dist/backend/llvm/classes.test.js +99 -0
- package/dist/backend/llvm/classes.test.js.map +1 -0
- package/dist/backend/llvm/constant-callbacks.d.ts +11 -0
- package/dist/backend/llvm/constant-callbacks.js +213 -0
- package/dist/backend/llvm/constant-callbacks.js.map +1 -0
- package/dist/backend/llvm/constant-callbacks.test.d.ts +1 -0
- package/dist/backend/llvm/constant-callbacks.test.js +124 -0
- package/dist/backend/llvm/constant-callbacks.test.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +1 -1
- package/dist/backend/llvm/dyn.js +7 -34
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +19 -0
- package/dist/backend/llvm/emitter.js +274 -46
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +17 -11
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.js +11 -0
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-calls.js +91 -23
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +21 -9
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +36 -3
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +7 -0
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.test.js +1 -1
- package/dist/backend/llvm/expr-stream-bridges.test.js +1 -1
- package/dist/backend/llvm/integer-remainder.d.ts +7 -0
- package/dist/backend/llvm/integer-remainder.js +26 -0
- package/dist/backend/llvm/integer-remainder.js.map +1 -0
- package/dist/backend/llvm/layouts.js +1 -1
- package/dist/backend/llvm/layouts.js.map +1 -1
- package/dist/backend/llvm/lib-abi.js +7 -0
- package/dist/backend/llvm/lib-abi.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +7 -22
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +15 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.d.ts +8 -2
- package/dist/backend/llvm/local-array-reads.js +89 -68
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.test.js +28 -4
- package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.test.js +1 -1
- package/dist/backend/llvm/loop-array-borrows.d.ts +11 -0
- package/dist/backend/llvm/loop-array-borrows.js +70 -0
- package/dist/backend/llvm/loop-array-borrows.js.map +1 -0
- package/dist/backend/llvm/loop-array-borrows.test.d.ts +1 -0
- package/dist/backend/llvm/loop-array-borrows.test.js +145 -0
- package/dist/backend/llvm/loop-array-borrows.test.js.map +1 -0
- package/dist/backend/llvm/map-read-lifetimes.d.ts +5 -0
- package/dist/backend/llvm/map-read-lifetimes.js +20 -5
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +1 -1
- package/dist/backend/llvm/reference-effects.d.ts +2 -1
- package/dist/backend/llvm/reference-effects.js +7 -0
- package/dist/backend/llvm/reference-effects.js.map +1 -1
- package/dist/backend/llvm/shapes.d.ts +4 -1
- package/dist/backend/llvm/shapes.js +22 -7
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/split-loops.d.ts +48 -0
- package/dist/backend/llvm/split-loops.js +183 -0
- package/dist/backend/llvm/split-loops.js.map +1 -0
- package/dist/backend/llvm/split.js +0 -7
- package/dist/backend/llvm/split.js.map +1 -1
- package/dist/backend/llvm/split.test.js +66 -2
- package/dist/backend/llvm/split.test.js.map +1 -1
- package/dist/backend/llvm/stack-callbacks.d.ts +14 -0
- package/dist/backend/llvm/stack-callbacks.js +73 -0
- package/dist/backend/llvm/stack-callbacks.js.map +1 -0
- package/dist/backend/llvm/stack-captures.d.ts +25 -0
- package/dist/backend/llvm/stack-captures.js +150 -0
- package/dist/backend/llvm/stack-captures.js.map +1 -0
- package/dist/backend/llvm/stack-unions.test.js +1 -1
- package/dist/backend/llvm/string-construction.test.js +1 -1
- package/dist/backend/llvm/string-lifetimes.test.js +8 -4
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/string-slices.d.ts +20 -0
- package/dist/backend/llvm/string-slices.js +87 -0
- package/dist/backend/llvm/string-slices.js.map +1 -0
- package/dist/backend/llvm/string-slices.test.d.ts +1 -0
- package/dist/backend/llvm/string-slices.test.js +98 -0
- package/dist/backend/llvm/string-slices.test.js.map +1 -0
- package/dist/backend/llvm/switch-dispatch.test.js +1 -1
- package/dist/backend/llvm/walkers.d.ts +4 -14
- package/dist/backend/llvm/walkers.js +53 -311
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/may-throw.js +1 -1
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +1 -1
- package/dist/backend/native/contracts.d.ts +2 -0
- package/dist/backend/native/executable.js +12 -4
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +2 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native-codegen-core.d.ts +6 -0
- package/dist/backend/native-codegen-core.js +21 -0
- package/dist/backend/native-codegen-core.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +4 -0
- package/dist/backend/native-codegen.js +34 -18
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +47 -2
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +1 -0
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/native-tools.d.ts +3 -1
- package/dist/backend/native-tools.js +6 -4
- package/dist/backend/native-tools.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-core.d.ts +1 -0
- package/dist/backend/runtime-pack-core.js +8 -1
- package/dist/backend/runtime-pack-core.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +41 -4
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +11 -1
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/target-diagnostics.test.js +1 -1
- package/dist/executable/executable-cache.d.ts +1 -0
- package/dist/executable/executable-cache.js +2 -1
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +15 -0
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/frontend/fork-target.d.ts +5 -0
- package/dist/frontend/fork-target.js +40 -8
- package/dist/frontend/fork-target.js.map +1 -1
- package/dist/frontend/fork-target.test.d.ts +1 -0
- package/dist/frontend/fork-target.test.js +59 -0
- package/dist/frontend/fork-target.test.js.map +1 -0
- package/dist/frontend/lowering/binding-analysis.js +2 -2
- package/dist/frontend/lowering/binding-analysis.js.map +1 -1
- package/dist/frontend/lowering/builtins/atomics.d.ts +2 -11
- package/dist/frontend/lowering/builtins/atomics.js +64 -28
- package/dist/frontend/lowering/builtins/atomics.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +3 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js +51 -4
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-calls.js +6 -1
- package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/workers.d.ts +5 -0
- package/dist/frontend/lowering/builtins/workers.js +65 -0
- package/dist/frontend/lowering/builtins/workers.js.map +1 -0
- package/dist/frontend/lowering/class-assertions.d.ts +7 -0
- package/dist/frontend/lowering/class-assertions.js +96 -0
- package/dist/frontend/lowering/class-assertions.js.map +1 -0
- package/dist/frontend/lowering/class-protocols.d.ts +17 -0
- package/dist/frontend/lowering/class-protocols.js +126 -0
- package/dist/frontend/lowering/class-protocols.js.map +1 -0
- package/dist/frontend/lowering/containers/array-callbacks.d.ts +7 -11
- package/dist/frontend/lowering/containers/array-callbacks.js +52 -87
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +12 -34
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +22 -3
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +2 -6
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/generic-functions.d.ts +2 -5
- package/dist/frontend/lowering/generic-functions.js +13 -10
- package/dist/frontend/lowering/generic-functions.js.map +1 -1
- package/dist/frontend/lowering/instantiation-path.d.ts +8 -0
- package/dist/frontend/lowering/instantiation-path.js +10 -0
- package/dist/frontend/lowering/instantiation-path.js.map +1 -0
- package/dist/frontend/lowering/instantiation-path.test.d.ts +1 -0
- package/dist/frontend/lowering/instantiation-path.test.js +23 -0
- package/dist/frontend/lowering/instantiation-path.test.js.map +1 -0
- package/dist/frontend/lowering/lower-builtin-values.js +11 -7
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +36 -3
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +5 -0
- package/dist/frontend/lowering/lower-classes.js +121 -53
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.js +1 -1
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +31 -10
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-functions.d.ts +1 -1
- package/dist/frontend/lowering/lower-functions.js +2 -2
- package/dist/frontend/lowering/lower-functions.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +1 -1
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +1 -0
- package/dist/frontend/lowering/lower-modules.js +44 -9
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +13 -11
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +1 -1
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +13 -1
- package/dist/frontend/lowering/lowerer.js +51 -9
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/sanitize-class-types.test.js +2 -2
- package/dist/frontend/lowering/split-consumers.d.ts +7 -0
- package/dist/frontend/lowering/split-consumers.js +64 -0
- package/dist/frontend/lowering/split-consumers.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +3 -4
- package/dist/frontend/lowering/surfaces.js +35 -7
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/module-source-candidates.d.ts +10 -0
- package/dist/frontend/module-source-candidates.js +40 -0
- package/dist/frontend/module-source-candidates.js.map +1 -0
- package/dist/frontend/module-source-candidates.test.d.ts +1 -0
- package/dist/frontend/module-source-candidates.test.js +53 -0
- package/dist/frontend/module-source-candidates.test.js.map +1 -0
- package/dist/frontend/pipeline.js +2 -2
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/program-analysis.d.ts +2 -0
- package/dist/frontend/program-analysis.js +2 -0
- package/dist/frontend/program-analysis.js.map +1 -1
- package/dist/frontend/program.js +17 -29
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/ts7/ast-node.js +6 -8
- package/dist/frontend/ts7/ast-node.js.map +1 -1
- package/dist/frontend/ts7/ast-node.test.js +42 -1
- package/dist/frontend/ts7/ast-node.test.js.map +1 -1
- package/dist/frontend/ts7/ast-wire.d.ts +4 -0
- package/dist/frontend/ts7/ast-wire.js +28 -0
- package/dist/frontend/ts7/ast-wire.js.map +1 -1
- package/dist/frontend/ts7/ast.d.ts +2 -1
- package/dist/frontend/ts7/ast.js +8 -4
- package/dist/frontend/ts7/ast.js.map +1 -1
- package/dist/frontend/ts7/checker.d.ts +8 -2
- package/dist/frontend/ts7/checker.js +41 -5
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/checker.test.js +42 -0
- package/dist/frontend/ts7/checker.test.js.map +1 -1
- package/dist/frontend/ts7/program-host.d.ts +7 -0
- package/dist/frontend/ts7/program-host.js +26 -2
- package/dist/frontend/ts7/program-host.js.map +1 -1
- package/dist/frontend/ts7/program-host.test.js +29 -0
- package/dist/frontend/ts7/program-host.test.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +3 -0
- package/dist/frontend/type-mapper.js +44 -2
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/worker-target.d.ts +6 -0
- package/dist/frontend/worker-target.js +108 -0
- package/dist/frontend/worker-target.js.map +1 -0
- package/dist/frontend/worker-target.test.d.ts +1 -0
- package/dist/frontend/worker-target.test.js +71 -0
- package/dist/frontend/worker-target.test.js.map +1 -0
- package/dist/index.js +24 -7
- package/dist/index.js.map +1 -1
- package/dist/ir/builtin-effects.js +12 -0
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +13 -12
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/constant-tables.test.js +1 -1
- package/dist/ir/initializer-bindings.test.js +1 -1
- package/dist/ir/ir.d.ts +9 -10
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/numeric-call-specialization.d.ts +8 -0
- package/dist/ir/numeric-call-specialization.js +198 -0
- package/dist/ir/numeric-call-specialization.js.map +1 -0
- package/dist/ir/runtime-features.js +4 -3
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/scalar-records.test.js +1 -1
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +3 -3
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/validate.js +89 -23
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +91 -4
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/fence-eval.test.js +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/ir-policy.js +2 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/dist/library/library-cache.test.js +5 -5
- package/dist/native/compiler.js +24 -11
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/compiler.test.js +7 -3
- package/dist/native/compiler.test.js.map +1 -1
- package/dist/native/prepare.js +2 -0
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/sanitizer.test.js +1 -0
- package/dist/native/sanitizer.test.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +30 -2
|
@@ -21,13 +21,16 @@ import { InternalCompilerError } from "../../errors.js";
|
|
|
21
21
|
import { deflateRawSync } from "node:zlib";
|
|
22
22
|
import { endsWithJump, matchStringSelfConcat, streamTypedRefEligible } from "../../ir/analysis.js";
|
|
23
23
|
import { emitLibraryIdentityLines } from "../library-identity-markers.js";
|
|
24
|
-
import { CAUGHT, ffiCallbackType, isDynTypedRefType, isFfiContextParam, isRefCounted, isUnitType, POINTER_KINDS, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, typeKey, VOID, } from "../../ir/ir.js";
|
|
24
|
+
import { CAUGHT, ffiCallbackType, isDynTypedRefType, isFfiContextParam, isRefCounted, isUnitType, POINTER_KINDS, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, typeKey, STRING, VOID, } from "../../ir/ir.js";
|
|
25
25
|
import { moduleRuntimeFeatures, moduleEmbedsBuiltin, moduleEmbedsCompressedNpm, NPM_COMPRESS_MIN, } from "../../ir/runtime-features.js";
|
|
26
26
|
import { matchIntegerArrayForLoop, matchIntegerBytesForLoop, matchIntegerCountedForLoop, } from "../../ir/integer-loops.js";
|
|
27
27
|
import { emitCountedLoopLimit } from "./counted-loops.js";
|
|
28
28
|
import { emitLiteralSwitch } from "./switch-dispatch.js";
|
|
29
29
|
import { findBytesBounds } from "./bytes-bounds.js";
|
|
30
|
+
import { emitByteWindowGuard, findInitializedByteLoopBindings, matchByteWindow, } from "./byte-windows.js";
|
|
31
|
+
import { canDeferSplitPiece, emitSplitSpanNext, materializeSplitPiece, emitSplitCursor, emitSplitNext, emitSplitScratch, emitSplitSnapshot, findPrivateSplitLocals, loadSplitSnapshot, storeSplitSnapshot, stringSplit, } from "./split-loops.js";
|
|
30
32
|
import { scalarizeNumericRecords } from "../../ir/scalar-records.js";
|
|
33
|
+
import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js";
|
|
31
34
|
import { everyStmtList } from "../../ir/traverse.js";
|
|
32
35
|
import { analyzeIntegerRanges } from "../../ir/integer-ranges.js";
|
|
33
36
|
import { findIntegerViews } from "./integer-views.js";
|
|
@@ -41,12 +44,17 @@ import { analyzeCallLifetimes } from "./call-lifetimes.js";
|
|
|
41
44
|
import { canStackUnion, emitStackUnion, findLocalStackUnions } from "./stack-unions.js";
|
|
42
45
|
import { allocateLocalUnion, findLocalUnionStorage, storeLocalUnion, } from "./local-union-storage.js";
|
|
43
46
|
import { BlockBuilder } from "./blocks.js";
|
|
44
|
-
import { emitLocalArrayRead, findLocalArrayReads, findCallArrayReads, OptionalArrayReads, } from "./local-array-reads.js";
|
|
47
|
+
import { emitLocalArrayRead, emitBorrowedArrayRead, findLocalArrayReads, findCallArrayReads, OptionalArrayReads, } from "./local-array-reads.js";
|
|
45
48
|
import { emitStackMapRead, findMapReadLifetimes, matchMapRead, } from "./map-read-lifetimes.js";
|
|
46
49
|
import { emitBorrowedFieldSequence } from "./borrowed-receivers.js";
|
|
47
50
|
import { emitBorrowedInput } from "./borrowed-inputs.js";
|
|
48
51
|
import { ReferenceEffects } from "./reference-effects.js";
|
|
49
52
|
import { LlvmDebugInfo } from "./debug-info.js";
|
|
53
|
+
import { StackCallbacks } from "./stack-callbacks.js";
|
|
54
|
+
import { findLoopArrayBorrows } from "./loop-array-borrows.js";
|
|
55
|
+
import { findConstantCallbacks } from "./constant-callbacks.js";
|
|
56
|
+
import { findScalarStringSlices, emitStringSliceSnapshot, } from "./string-slices.js";
|
|
57
|
+
import { StackCaptures } from "./stack-captures.js";
|
|
50
58
|
import { f64Lit, ffiNativeTypeLl, ffiNativeParamLl, ffiNativeReturnLl, llvmCommentText, } from "./common.js";
|
|
51
59
|
import { ffiExtendsNarrowIntegers } from "../targets.js";
|
|
52
60
|
import { emitLiteralExpr, emitOperatorExpr, emitStringExpr, emitContainerExpr, emitRecordExpr, } from "./expr-primitives.js";
|
|
@@ -67,7 +75,7 @@ import { emitChildProcessLibCall, emitAsyncContextLibCall, emitProcessLibCall, e
|
|
|
67
75
|
import { emitStreamLibCall } from "./lib-stream.js";
|
|
68
76
|
import { emitNetworkHttpLibCall } from "./lib-network.js";
|
|
69
77
|
import { emitAssertInspectLibCall, emitIoLibCall, emitGenericLibCall, emitLibCall, } from "./lib-dispatch.js";
|
|
70
|
-
import { buildClassGraph, classEnvironmentIndex, classFieldIndex, classStructSym, } from "./classes.js";
|
|
78
|
+
import { buildClassGraph, classMembershipIntervals, emitClassMembershipHelper, classEnvironmentIndex, classFieldIndex, classStructSym, } from "./classes.js";
|
|
71
79
|
import { LlDyn } from "./dyn.js";
|
|
72
80
|
import { LlvmUnsupportedError } from "./unsupported.js";
|
|
73
81
|
import { LlWalkers } from "./walkers.js";
|
|
@@ -100,11 +108,15 @@ function ffiCallbackDummyLl(callback) {
|
|
|
100
108
|
}
|
|
101
109
|
export function emitLlvmModule(mod, options = {}) {
|
|
102
110
|
// Keep source storage intact for debugger inspection in dev builds.
|
|
103
|
-
return new LlEmitter(options.debugSources === undefined
|
|
111
|
+
return new LlEmitter(options.debugSources === undefined
|
|
112
|
+
? scalarizeNumericRecords(specializeNumericCalls(mod, mangleFunction))
|
|
113
|
+
: mod, options).emit();
|
|
104
114
|
}
|
|
105
115
|
/** Keep large translation units below the host's single-string limit. */
|
|
106
116
|
export function emitLlvmModuleSource(mod, options = {}) {
|
|
107
|
-
const parts = new LlEmitter(options.debugSources === undefined
|
|
117
|
+
const parts = new LlEmitter(options.debugSources === undefined
|
|
118
|
+
? scalarizeNumericRecords(specializeNumericCalls(mod, mangleFunction))
|
|
119
|
+
: mod, options).emitParts();
|
|
108
120
|
const length = parts.reduce((total, part) => total + part.length, Math.max(0, parts.length - 1));
|
|
109
121
|
if (length <= 256 * 1024 * 1024)
|
|
110
122
|
return parts.join("\n");
|
|
@@ -116,6 +128,9 @@ function llStrBytes(text) {
|
|
|
116
128
|
export class LlEmitter {
|
|
117
129
|
mod;
|
|
118
130
|
localArrayReads = new Map();
|
|
131
|
+
loopArrayBorrows = new Set();
|
|
132
|
+
scalarStringSlices = new Map();
|
|
133
|
+
stringSlices = new Map();
|
|
119
134
|
localStackUnions = new Map();
|
|
120
135
|
localUnionStorageProofs = new Map();
|
|
121
136
|
localUnionStorage = new Map();
|
|
@@ -206,6 +221,10 @@ export class LlEmitter {
|
|
|
206
221
|
callArrayReads = new Map();
|
|
207
222
|
mapReadLifetimes = { locals: new Map(), arguments: new Map() };
|
|
208
223
|
callLifetimes;
|
|
224
|
+
constantCallbacks;
|
|
225
|
+
currentConstantCallbacks = new Map();
|
|
226
|
+
stackCallbacks;
|
|
227
|
+
stackCaptures;
|
|
209
228
|
borrowedParameters = new Set();
|
|
210
229
|
stableCallBindings = new Set();
|
|
211
230
|
/** Manifest-bound native imports, used by ffiCall emission. */
|
|
@@ -288,6 +307,10 @@ export class LlEmitter {
|
|
|
288
307
|
* for blocks and switches. */
|
|
289
308
|
jumpTargets = [];
|
|
290
309
|
currentLocals = new Map();
|
|
310
|
+
privateSplitLocals = new Map();
|
|
311
|
+
splitSpans = new Map();
|
|
312
|
+
storedSplits = new Map();
|
|
313
|
+
streamingSplitsEnabled = false;
|
|
291
314
|
initializerBindings;
|
|
292
315
|
numericLocals = new Map();
|
|
293
316
|
captureIds = new Set();
|
|
@@ -295,6 +318,8 @@ export class LlEmitter {
|
|
|
295
318
|
integerLoopBindings = new Map();
|
|
296
319
|
countedLoopsEnabled = false;
|
|
297
320
|
integerRanges = new Map();
|
|
321
|
+
byteWindowsEnabled = true;
|
|
322
|
+
byteWindowEntries = new Map();
|
|
298
323
|
bytesBounds = new Set();
|
|
299
324
|
integerViews = new Map();
|
|
300
325
|
/** Enclosing try-with-FINALLY regions, innermost last: a `return`
|
|
@@ -359,7 +384,10 @@ export class LlEmitter {
|
|
|
359
384
|
}
|
|
360
385
|
const mt = computeMayThrow(mod);
|
|
361
386
|
this.mayThrow = mt.fns;
|
|
362
|
-
|
|
387
|
+
if (mod.workers)
|
|
388
|
+
for (const fn of mod.functions)
|
|
389
|
+
this.mayThrow.add(fn.name);
|
|
390
|
+
this.indirectMayThrow = mt.indirect || mod.workers === true;
|
|
363
391
|
for (const cls of mod.classes ?? []) {
|
|
364
392
|
for (const m of cls.methods ?? []) {
|
|
365
393
|
if (this.mayThrow.has(`%${cls.name}.${m}`))
|
|
@@ -371,6 +399,9 @@ export class LlEmitter {
|
|
|
371
399
|
this.optionalArrayReads = new OptionalArrayReads(this.fnByName, this.unionsById);
|
|
372
400
|
this.referenceEffects = new ReferenceEffects(this.fnByName, (call) => this.optionalArrayReads.get(call) !== null);
|
|
373
401
|
this.callLifetimes = analyzeCallLifetimes(this.fnByName);
|
|
402
|
+
this.constantCallbacks = findConstantCallbacks(mod, this.callLifetimes);
|
|
403
|
+
this.stackCallbacks = new StackCallbacks(this.fnByName);
|
|
404
|
+
this.stackCaptures = new StackCaptures(this.fnByName, this.callLifetimes, this.stackCallbacks);
|
|
374
405
|
for (const r of mod.records ?? [])
|
|
375
406
|
this.recordsById.set(r.id, r);
|
|
376
407
|
const traced = computeTraced(mod);
|
|
@@ -396,8 +427,9 @@ export class LlEmitter {
|
|
|
396
427
|
isErrorClass: (name) => this.classMeta.get(name)?.root.def.name === "%Error",
|
|
397
428
|
classSubtypes: (name) => {
|
|
398
429
|
const target = this.classMetaOf(name);
|
|
430
|
+
const intervals = classMembershipIntervals(this.classMeta, target.def.name);
|
|
399
431
|
return [...this.classMeta.values()]
|
|
400
|
-
.filter((meta) =>
|
|
432
|
+
.filter((meta) => intervals.some((range) => range.pre <= meta.pre && meta.pre <= range.post))
|
|
401
433
|
.map((meta) => meta.def.name);
|
|
402
434
|
},
|
|
403
435
|
};
|
|
@@ -507,7 +539,7 @@ export class LlEmitter {
|
|
|
507
539
|
if (adapter.global !== null)
|
|
508
540
|
globals.push(`@${adapter.global} = internal thread_local global ptr null`);
|
|
509
541
|
if (adapter.table !== null) {
|
|
510
|
-
globals.push(`@${adapter.table} = internal global %ScrFfiTable zeroinitializer`);
|
|
542
|
+
globals.push(`@${adapter.table} = internal ${this.mod.workers ? "thread_local " : ""}global %ScrFfiTable zeroinitializer`);
|
|
511
543
|
}
|
|
512
544
|
const params = cb.params.flatMap((param, i) => {
|
|
513
545
|
if (isFfiContextParam(param))
|
|
@@ -953,7 +985,7 @@ export class LlEmitter {
|
|
|
953
985
|
// with neither keep the atexit path, so their listener timing is
|
|
954
986
|
// unchanged.
|
|
955
987
|
const hasRefGlobals = globals.some((g) => isRefCounted(g.type)) || fnValueProps.length > 0;
|
|
956
|
-
const inlineExitListeners = usesEvents && (hasRefGlobals || this.ffiHasRetainedCallback);
|
|
988
|
+
const inlineExitListeners = usesEvents && (this.mod.workers || hasRefGlobals || this.ffiHasRetainedCallback);
|
|
957
989
|
this.declare(`declare i32 @scr_exit_code_hint_get()`);
|
|
958
990
|
if (inlineExitListeners) {
|
|
959
991
|
this.declare(`declare void @scr_run_exit_listeners(double)`);
|
|
@@ -1081,7 +1113,10 @@ export class LlEmitter {
|
|
|
1081
1113
|
}
|
|
1082
1114
|
// Helpers assemble BEFORE the declaration table flushes (they add
|
|
1083
1115
|
// write/abort declarations).
|
|
1084
|
-
const helpers =
|
|
1116
|
+
const helpers = [
|
|
1117
|
+
...this.helperDefs(),
|
|
1118
|
+
...emitClassMembershipHelper(this.classMeta, this.sizeType),
|
|
1119
|
+
];
|
|
1085
1120
|
if (this.constantNumericTables.size > 0)
|
|
1086
1121
|
this.declare(`declare double @scr_arr_get_number(ptr, double)`);
|
|
1087
1122
|
const out = [
|
|
@@ -1121,11 +1156,11 @@ export class LlEmitter {
|
|
|
1121
1156
|
// scr_runtime.h's natural alignment: kind at 8, f64 at 16, b at 24,
|
|
1122
1157
|
// payload at 32).
|
|
1123
1158
|
`%ScrCaught = type { ${this.sizeType}, i32, double, i8, ptr, ptr, ptr, ptr }`,
|
|
1124
|
-
// ScrBytes { rc, len, elem(i32+pad), data, backing }. Indexed
|
|
1159
|
+
// ScrBytes { rc, len, elem(i32+pad), data, backing, brands, shared }. Indexed
|
|
1125
1160
|
// typed-array access GEPs through this directly: the IR type already
|
|
1126
1161
|
// fixes elem, so the hot path needs neither a runtime kind load nor
|
|
1127
1162
|
// the generic scr_bytes_get/set call.
|
|
1128
|
-
`%ScrBytes = type { ${this.sizeType}, ${this.sizeType}, i32, ptr, ptr, i8 }`,
|
|
1163
|
+
`%ScrBytes = type { ${this.sizeType}, ${this.sizeType}, i32, ptr, ptr, i8, i8, i8, ptr }`,
|
|
1129
1164
|
// The capture box { rc, kind, obj_retain, obj_release, obj_trace,
|
|
1130
1165
|
// slot } — TDZ reads peek the payload slot (offset 40) directly.
|
|
1131
1166
|
`%ScrBox = type { ${this.sizeType}, i32, ptr, ptr, ptr, i64 }`,
|
|
@@ -1148,8 +1183,8 @@ export class LlEmitter {
|
|
|
1148
1183
|
// objects compiled with -DSCR_THREAD_INSTANCES. Immutable interned
|
|
1149
1184
|
// data (string literals, unit arms, template arrays, vtables) stays
|
|
1150
1185
|
// shared.
|
|
1151
|
-
const tl = this.mod.lib?.threadInstances === true ? "thread_local " : "";
|
|
1152
|
-
out.push(``, `@scr_error_vts = external ${tl}global [${RUNTIME_ERROR_CLASSES.size} x %ScrVt]`, `declare void @scr_init()`, `declare void @scr_lib_init(i32, ptr)`, ...(this.runtimeAbiMarker && this.mod.lib === undefined
|
|
1186
|
+
const tl = this.mod.workers === true || this.mod.lib?.threadInstances === true ? "thread_local " : "";
|
|
1187
|
+
out.push(``, `@scr_error_vts = external ${tl}global [${RUNTIME_ERROR_CLASSES.size} x %ScrVt]`, `declare void @scr_init()`, `declare void @scr_lib_init(i32, ptr)`, ...(this.mod.workers ? [`declare void @scr_runtime_workers_v7()`] : []), ...(this.runtimeAbiMarker && this.mod.lib === undefined
|
|
1153
1188
|
? [`declare void @${RUNTIME_ABI_MARKER}()`]
|
|
1154
1189
|
: []));
|
|
1155
1190
|
for (const d of this.decls)
|
|
@@ -1306,7 +1341,7 @@ export class LlEmitter {
|
|
|
1306
1341
|
// The runtime stream vtables' intervals (streamVtStampLines) — the
|
|
1307
1342
|
// emitter story: instanceof and dynamic teardown dispatch through
|
|
1308
1343
|
// them.
|
|
1309
|
-
out.push(`@${iv.vt} = external global %ScrVt`);
|
|
1344
|
+
out.push(`@${iv.vt} = external ${tl}global %ScrVt`);
|
|
1310
1345
|
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}`);
|
|
1311
1346
|
}
|
|
1312
1347
|
if (this.streamIntervals.length > 0)
|
|
@@ -1343,7 +1378,7 @@ export class LlEmitter {
|
|
|
1343
1378
|
out.push(this.debug.render());
|
|
1344
1379
|
return out;
|
|
1345
1380
|
}
|
|
1346
|
-
out.push(`define i32 @${this.wasi ? "__main_argc_argv" : "main"}(i32 %argc, ptr %argv) ${FN_ATTRS} {`, `entry:`, ...(this.runtimeAbiMarker ? [` call void @${RUNTIME_ABI_MARKER}()`] : []), ` call void @scr_init()`, ...stamps,
|
|
1381
|
+
out.push(`define i32 @${this.mod.workers ? "sc_context_entry" : this.wasi ? "__main_argc_argv" : "main"}(i32 %argc, ptr %argv) ${FN_ATTRS} {`, `entry:`, ...(this.runtimeAbiMarker ? [` call void @${RUNTIME_ABI_MARKER}()`] : []), ...(this.mod.workers ? [` call void @scr_runtime_workers_v7()`] : []), ` call void @scr_init()`, ...stamps,
|
|
1347
1382
|
// Event-surface programs (signal/exit listeners) fill the loop's
|
|
1348
1383
|
// nullable event hooks before %main — scr_events.c links only when
|
|
1349
1384
|
// this line is emitted (native/executable.ts gates on the same predicate).
|
|
@@ -1456,6 +1491,9 @@ export class LlEmitter {
|
|
|
1456
1491
|
// lane's -fsanitize=address link activates instrumentation over the
|
|
1457
1492
|
// emitted functions too (the runtime TUs get theirs from clang).
|
|
1458
1493
|
`attributes #0 = { sanitize_address }`, ...(this.wasi ? [`attributes #1 = { sanitize_address presplitcoroutine }`] : []), ...(hasNoInlineRecordClone ? [`attributes #2 = { noinline sanitize_address }`] : []), ``);
|
|
1494
|
+
if (this.mod.workers) {
|
|
1495
|
+
out.push(`declare void @scr_context_cleanup()`, `declare i32 @scr_worker_argc()`, `declare ptr @scr_worker_argv()`, `define i32 @sc_worker_entry(i32 %root) ${FN_ATTRS} {`, `entry:`, ` %argc = call i32 @scr_worker_argc()`, ` %argv = call ptr @scr_worker_argv()`, ` %result = call i32 @sc_context_entry(i32 %argc, ptr %argv)`, ` ret i32 %result`, `}`, `define i32 @main(i32 %argc, ptr %argv) ${FN_ATTRS} {`, `entry:`, ` %result = call i32 @sc_context_entry(i32 %argc, ptr %argv)`, ` call void @scr_context_cleanup()`, ` ret i32 %result`, `}`);
|
|
1496
|
+
}
|
|
1459
1497
|
out.push(...this.fieldAliasMetadata());
|
|
1460
1498
|
if (this.debug !== null)
|
|
1461
1499
|
out.push(this.debug.render());
|
|
@@ -1723,7 +1761,7 @@ export class LlEmitter {
|
|
|
1723
1761
|
// never the inner return type.
|
|
1724
1762
|
const ret = fn.async === true || fn.generator !== undefined ? "ptr" : this.llType(fn.returnType);
|
|
1725
1763
|
const call = `call ${ret} @${this.callTarget(name)}(${args})`;
|
|
1726
|
-
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, i32 ${(fn.generator ? 1 : 0) + (fn.async ? 2 : 0) + (fn.ownsPrototype ? 4 : 0)} }`, ``);
|
|
1764
|
+
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 ${this.mod.workers === true || this.mod.lib?.threadInstances === true ? "thread_local " : ""}global %ScrClosure { ${this.sizeType} -1, ptr @${mangleWrapper(name)}, ${this.sizeType} 0, ptr null, i32 ${(fn.generator ? 1 : 0) + (fn.async ? 2 : 0) + (fn.ownsPrototype ? 4 : 0)} }`, ``);
|
|
1727
1765
|
}
|
|
1728
1766
|
return out;
|
|
1729
1767
|
}
|
|
@@ -2206,6 +2244,20 @@ export class LlEmitter {
|
|
|
2206
2244
|
* using the result). Callers own the surrounding pending branch; a
|
|
2207
2245
|
* `throw` unwinds unconditionally. */
|
|
2208
2246
|
emitUnwind() {
|
|
2247
|
+
if (this.mod.workers && this.tryStack.length > 0) {
|
|
2248
|
+
this.declare(`declare zeroext i1 @scr_context_stopping()`);
|
|
2249
|
+
const stopped = this.B.tmp();
|
|
2250
|
+
this.B.line(`${stopped} = call zeroext i1 @scr_context_stopping()`);
|
|
2251
|
+
const stop = this.B.newLabel("context.stop");
|
|
2252
|
+
const ordinary = this.B.newLabel("context.throw");
|
|
2253
|
+
this.B.condBr(stopped, stop, ordinary);
|
|
2254
|
+
this.B.startBlock(stop);
|
|
2255
|
+
const handlers = this.tryStack;
|
|
2256
|
+
this.tryStack = [];
|
|
2257
|
+
this.emitUnwind();
|
|
2258
|
+
this.tryStack = handlers;
|
|
2259
|
+
this.B.startBlock(ordinary);
|
|
2260
|
+
}
|
|
2209
2261
|
const target = this.tryStack[this.tryStack.length - 1];
|
|
2210
2262
|
const frameDepth = target?.frameDepth ?? 0;
|
|
2211
2263
|
const scopeDepth = target?.scopeDepth ?? 0;
|
|
@@ -2269,6 +2321,34 @@ export class LlEmitter {
|
|
|
2269
2321
|
this.emitUnwind();
|
|
2270
2322
|
B.startBlock(lk);
|
|
2271
2323
|
}
|
|
2324
|
+
workerLoopBudget() {
|
|
2325
|
+
if (!this.mod.workers)
|
|
2326
|
+
return null;
|
|
2327
|
+
const slot = this.B.slot();
|
|
2328
|
+
this.B.entryAllocas.push(`${slot} = alloca i32 ; worker cancellation budget`);
|
|
2329
|
+
this.B.line(`store i32 0, ptr ${slot}`);
|
|
2330
|
+
return slot;
|
|
2331
|
+
}
|
|
2332
|
+
emitWorkerLoopCheck(slot) {
|
|
2333
|
+
if (slot === null)
|
|
2334
|
+
return;
|
|
2335
|
+
const B = this.B;
|
|
2336
|
+
const budget = B.tmp(), due = B.tmp(), remaining = B.tmp();
|
|
2337
|
+
const poll = B.newLabel("worker.poll"), next = B.newLabel("worker.next");
|
|
2338
|
+
B.line(`${budget} = load i32, ptr ${slot}`);
|
|
2339
|
+
B.line(`${remaining} = sub i32 ${budget}, 1`);
|
|
2340
|
+
B.line(`store i32 ${remaining}, ptr ${slot}`);
|
|
2341
|
+
B.line(`${due} = icmp eq i32 ${budget}, 0`);
|
|
2342
|
+
B.condBr(due, poll, next);
|
|
2343
|
+
B.startBlock(poll);
|
|
2344
|
+
B.line(`store i32 63, ptr ${slot}`);
|
|
2345
|
+
// Calls and throwing operations retain their own checks. Amortize the
|
|
2346
|
+
// extra cancellation poll across bounded loop batches so scalar work
|
|
2347
|
+
// does not cross the runtime ABI on every iteration.
|
|
2348
|
+
this.emitPendingCheck();
|
|
2349
|
+
B.br(next);
|
|
2350
|
+
B.startBlock(next);
|
|
2351
|
+
}
|
|
2272
2352
|
/** Moves an already-evaluated value into the runtime's exception cell —
|
|
2273
2353
|
* the `throw` statement's kind dispatch (stmts.ts's), shared with
|
|
2274
2354
|
* every synthetic thrower. Ownership of a refcounted payload must have
|
|
@@ -2973,6 +3053,17 @@ export class LlEmitter {
|
|
|
2973
3053
|
this.unwindCleanups.clear();
|
|
2974
3054
|
this.jumpTargets = [];
|
|
2975
3055
|
this.currentLocals = new Map(fn.locals.map((l) => [l.id, l]));
|
|
3056
|
+
this.currentConstantCallbacks =
|
|
3057
|
+
this.debug === null ? (this.constantCallbacks.get(fn.name) ?? new Map()) : new Map();
|
|
3058
|
+
// Preserve concrete source bindings for debugger inspection. Suspended
|
|
3059
|
+
// functions keep the established array lifetime across continuations.
|
|
3060
|
+
this.streamingSplitsEnabled = this.debug === null && !fn.async && !fn.generator;
|
|
3061
|
+
this.stackCallbacks.reset(this.streamingSplitsEnabled);
|
|
3062
|
+
this.stackCaptures.reset(fn, this.streamingSplitsEnabled);
|
|
3063
|
+
this.privateSplitLocals = this.streamingSplitsEnabled ? findPrivateSplitLocals(fn) : new Map();
|
|
3064
|
+
this.storedSplits.clear();
|
|
3065
|
+
this.splitSpans.clear();
|
|
3066
|
+
this.stringSlices.clear();
|
|
2976
3067
|
const initializerBindings = this.initializerBindings.get(fn.name) ?? [];
|
|
2977
3068
|
const numericFn = withInitializerBindings(fn, initializerBindings);
|
|
2978
3069
|
this.numericLocals = new Map(numericFn.locals.map((l) => [l.id, l]));
|
|
@@ -2986,11 +3077,22 @@ export class LlEmitter {
|
|
|
2986
3077
|
this.captureIds = new Set([...(fn.captures ?? []), ...(fn.classCaptures ?? [])].map((c) => c.localId));
|
|
2987
3078
|
this.integerLoopBindings.clear();
|
|
2988
3079
|
this.countedLoopsEnabled = this.debug === null && !fn.async && !fn.generator;
|
|
3080
|
+
this.byteWindowsEnabled = this.countedLoopsEnabled;
|
|
3081
|
+
this.byteWindowEntries =
|
|
3082
|
+
this.byteWindowsEnabled && numericFn.locals.some((l) => l.type.kind === "bytes")
|
|
3083
|
+
? findInitializedByteLoopBindings(fn)
|
|
3084
|
+
: new Map();
|
|
2989
3085
|
this.integerViews.clear();
|
|
2990
3086
|
this.fieldPointerTags.clear();
|
|
2991
3087
|
this.integerArrayBindings.clear();
|
|
2992
|
-
this.
|
|
3088
|
+
this.loopArrayBorrows =
|
|
3089
|
+
this.debug === null
|
|
3090
|
+
? findLoopArrayBorrows(fn, this.callLifetimes, this.referenceEffects, this.optionalArrayReads)
|
|
3091
|
+
: new Set();
|
|
3092
|
+
this.localArrayReads = findLocalArrayReads(fn, this.fnByName, this.unionsById, this.referenceEffects.functions, this.callLifetimes, this.optionalArrayReads, this.loopArrayBorrows);
|
|
2993
3093
|
this.callArrayReads = findCallArrayReads(fn, this.optionalArrayReads, this.referenceEffects.functions, this.callLifetimes);
|
|
3094
|
+
this.scalarStringSlices =
|
|
3095
|
+
this.debug === null ? findScalarStringSlices(fn, this.callLifetimes) : new Map();
|
|
2994
3096
|
this.mapReadLifetimes = findMapReadLifetimes(fn, this.unionsById, this.callLifetimes);
|
|
2995
3097
|
this.localStackUnions = findLocalStackUnions(fn, this.callLifetimes, this.unionsById);
|
|
2996
3098
|
this.localUnionStorageProofs = findLocalUnionStorage(fn, this.callLifetimes, this.unionsById);
|
|
@@ -3129,6 +3231,8 @@ export class LlEmitter {
|
|
|
3129
3231
|
B.line(`call void @scr_stack_enter(ptr %source_frame, ptr ${this.cstr(frame)})`);
|
|
3130
3232
|
B.returnEpilogue = `call void @scr_stack_leave(ptr %source_frame)`;
|
|
3131
3233
|
}
|
|
3234
|
+
if (this.mod.workers)
|
|
3235
|
+
this.emitPendingCheck();
|
|
3132
3236
|
this.emitStmts(fn.body);
|
|
3133
3237
|
// Implicit exit of a void function: release the function scope unless
|
|
3134
3238
|
// the body already terminated its final block (return, or a throw
|
|
@@ -3279,6 +3383,20 @@ export class LlEmitter {
|
|
|
3279
3383
|
switch (s.kind) {
|
|
3280
3384
|
case "varDecl": {
|
|
3281
3385
|
const b = this.binding(s.localId);
|
|
3386
|
+
const slice = this.scalarStringSlices.get(s.localId);
|
|
3387
|
+
if (slice) {
|
|
3388
|
+
const snapshot = emitStringSliceSnapshot(this, slice);
|
|
3389
|
+
this.stringSlices.set(s.localId, snapshot);
|
|
3390
|
+
this.scopes[this.scopes.length - 1].push({ slot: snapshot.source, type: STRING });
|
|
3391
|
+
break;
|
|
3392
|
+
}
|
|
3393
|
+
const split = this.privateSplitLocals.get(s.localId);
|
|
3394
|
+
if (split) {
|
|
3395
|
+
const snapshot = storeSplitSnapshot(this, emitSplitSnapshot(this, split));
|
|
3396
|
+
this.storedSplits.set(s.localId, snapshot);
|
|
3397
|
+
this.scopes[this.scopes.length - 1].push({ slot: snapshot.sourceSlot, type: STRING }, { slot: snapshot.separatorSlot, type: STRING });
|
|
3398
|
+
break;
|
|
3399
|
+
}
|
|
3282
3400
|
const localUnion = this.localStackUnions.get(s.localId);
|
|
3283
3401
|
if (localUnion) {
|
|
3284
3402
|
const union = emitStackUnion(this, localUnion);
|
|
@@ -3321,6 +3439,19 @@ export class LlEmitter {
|
|
|
3321
3439
|
break;
|
|
3322
3440
|
}
|
|
3323
3441
|
if (b.kind === "boxed") {
|
|
3442
|
+
const stack = this.stackCaptures.emit(this, s.localId, b.type);
|
|
3443
|
+
if (stack) {
|
|
3444
|
+
B.line(`store ptr ${stack.box}, ptr ${b.slot}`);
|
|
3445
|
+
if (stack.owner)
|
|
3446
|
+
this.scopes[this.scopes.length - 1].push(stack.owner);
|
|
3447
|
+
if (s.init) {
|
|
3448
|
+
const value = this.emitExpr(s.init);
|
|
3449
|
+
if (isRefCounted(value.type))
|
|
3450
|
+
this.moveTemp(value);
|
|
3451
|
+
this.boxSet(stack.box, b.type, value.name);
|
|
3452
|
+
}
|
|
3453
|
+
break;
|
|
3454
|
+
}
|
|
3324
3455
|
// Box FIRST, then evaluate the initializer: a named function
|
|
3325
3456
|
// expression's closure captures this box during init evaluation.
|
|
3326
3457
|
// A SCALAR TDZ box rides an ARR-kind box: the value lives in a
|
|
@@ -3357,13 +3488,16 @@ export class LlEmitter {
|
|
|
3357
3488
|
}
|
|
3358
3489
|
break;
|
|
3359
3490
|
}
|
|
3360
|
-
|
|
3491
|
+
if (this.loopArrayBorrows.has(s) && s.init.kind === "arrayGet") {
|
|
3492
|
+
emitBorrowedArrayRead(this, s.init, b.slot);
|
|
3493
|
+
break;
|
|
3494
|
+
}
|
|
3495
|
+
// A stable lexical alias cannot outlive its unchanged local owner.
|
|
3361
3496
|
// Whole-value uses still retain their own copies, so returning or
|
|
3362
3497
|
// storing the alias preserves the ordinary heap representation.
|
|
3363
3498
|
// Boxed captures, reassigned sources and projections need ownership.
|
|
3364
3499
|
if (b.kind === "local" &&
|
|
3365
3500
|
b.local &&
|
|
3366
|
-
!b.local.mutable &&
|
|
3367
3501
|
isRefCounted(b.type) &&
|
|
3368
3502
|
this.stableCallBindings.has(s.localId) &&
|
|
3369
3503
|
this.canBorrowCallArgument(s.init)) {
|
|
@@ -3694,11 +3828,13 @@ export class LlEmitter {
|
|
|
3694
3828
|
break;
|
|
3695
3829
|
}
|
|
3696
3830
|
case "while": {
|
|
3831
|
+
const workerBudget = this.workerLoopBudget();
|
|
3697
3832
|
const lc = B.newLabel("loop.c");
|
|
3698
3833
|
const lb = B.newLabel("loop.b");
|
|
3699
3834
|
const le = B.newLabel("loop.e");
|
|
3700
3835
|
B.br(lc);
|
|
3701
3836
|
B.startBlock(lc);
|
|
3837
|
+
this.emitWorkerLoopCheck(workerBudget);
|
|
3702
3838
|
B.condBr(this.emitCondition(s.cond), lb, le);
|
|
3703
3839
|
B.startBlock(lb);
|
|
3704
3840
|
this.jumpTargets.push({
|
|
@@ -3717,12 +3853,14 @@ export class LlEmitter {
|
|
|
3717
3853
|
break;
|
|
3718
3854
|
}
|
|
3719
3855
|
case "doWhile": {
|
|
3856
|
+
const workerBudget = this.workerLoopBudget();
|
|
3720
3857
|
// Body first (runs at least once); continue jumps to the CONDITION.
|
|
3721
3858
|
const lb = B.newLabel("loop.b");
|
|
3722
3859
|
const lc = B.newLabel("loop.c");
|
|
3723
3860
|
const le = B.newLabel("loop.e");
|
|
3724
3861
|
B.br(lb);
|
|
3725
3862
|
B.startBlock(lb);
|
|
3863
|
+
this.emitWorkerLoopCheck(workerBudget);
|
|
3726
3864
|
this.jumpTargets.push({
|
|
3727
3865
|
kind: "loop",
|
|
3728
3866
|
brkLabel: le,
|
|
@@ -3751,6 +3889,33 @@ export class LlEmitter {
|
|
|
3751
3889
|
const countedLoop = !integerLoop && this.countedLoopsEnabled
|
|
3752
3890
|
? matchIntegerCountedForLoop(s, this.numericLocals, this.integerRanges)
|
|
3753
3891
|
: null;
|
|
3892
|
+
const window = countedLoop && this.byteWindowsEnabled
|
|
3893
|
+
? matchByteWindow(s, countedLoop, this.numericLocals, this.captureIds, this.integerRanges, this.byteWindowEntries.get(s) ?? new Set())
|
|
3894
|
+
: null;
|
|
3895
|
+
if (window) {
|
|
3896
|
+
const valid = emitByteWindowGuard(this, window);
|
|
3897
|
+
const fast = B.newLabel("bytes.window.fast"), slow = B.newLabel("bytes.window.slow"), done = B.newLabel("bytes.window.done");
|
|
3898
|
+
B.condBr(valid, fast, slow);
|
|
3899
|
+
const originalRanges = this.integerRanges, originalBounds = this.bytesBounds;
|
|
3900
|
+
this.byteWindowsEnabled = false;
|
|
3901
|
+
try {
|
|
3902
|
+
B.startBlock(slow);
|
|
3903
|
+
this.emitStmt(s);
|
|
3904
|
+
B.br(done);
|
|
3905
|
+
B.startBlock(fast);
|
|
3906
|
+
this.integerRanges = window.ranges;
|
|
3907
|
+
this.bytesBounds = new Set([...originalBounds, ...window.bounds]);
|
|
3908
|
+
this.emitStmt(s);
|
|
3909
|
+
B.br(done);
|
|
3910
|
+
}
|
|
3911
|
+
finally {
|
|
3912
|
+
this.integerRanges = originalRanges;
|
|
3913
|
+
this.bytesBounds = originalBounds;
|
|
3914
|
+
this.byteWindowsEnabled = true;
|
|
3915
|
+
}
|
|
3916
|
+
B.startBlock(done);
|
|
3917
|
+
break;
|
|
3918
|
+
}
|
|
3754
3919
|
let countedJoin = null;
|
|
3755
3920
|
if (countedLoop?.guarded) {
|
|
3756
3921
|
const bound = this.emitExpr(countedLoop.limit);
|
|
@@ -3839,8 +4004,10 @@ export class LlEmitter {
|
|
|
3839
4004
|
};
|
|
3840
4005
|
const lu = s.update || capturedLets.length > 0 ? B.newLabel("loop.u") : lc;
|
|
3841
4006
|
freshenBindings();
|
|
4007
|
+
const workerBudget = this.workerLoopBudget();
|
|
3842
4008
|
B.br(lc);
|
|
3843
4009
|
B.startBlock(lc);
|
|
4010
|
+
this.emitWorkerLoopCheck(workerBudget);
|
|
3844
4011
|
if (integerLoop && integerSlot) {
|
|
3845
4012
|
const receiver = this.emitStableReceiver(integerLoop.limitReceiver, []);
|
|
3846
4013
|
const lenPtr = B.tmp();
|
|
@@ -3922,23 +4089,49 @@ export class LlEmitter {
|
|
|
3922
4089
|
if (s.iterable.type.kind !== "array")
|
|
3923
4090
|
throw new LlvmUnsupportedError(`forOf:${s.iterable.type.kind}`, s.loc);
|
|
3924
4091
|
const elem = s.iterable.type.elem;
|
|
3925
|
-
const
|
|
3926
|
-
const
|
|
3927
|
-
|
|
3928
|
-
|
|
4092
|
+
const stored = s.iterable.kind === "varRef" ? this.storedSplits.get(s.iterable.localId) : undefined;
|
|
4093
|
+
const direct = this.streamingSplitsEnabled ? stringSplit(s.iterable) : null;
|
|
4094
|
+
const snapshot = stored
|
|
4095
|
+
? loadSplitSnapshot(this, stored)
|
|
4096
|
+
: direct
|
|
4097
|
+
? emitSplitSnapshot(this, direct)
|
|
4098
|
+
: null;
|
|
4099
|
+
const arr = snapshot ? null : this.emitExpr(s.iterable);
|
|
4100
|
+
const cursor = snapshot ? emitSplitCursor(this, snapshot) : null;
|
|
4101
|
+
const scratch = snapshot ? emitSplitScratch(this) : null;
|
|
4102
|
+
const deferred = snapshot && canDeferSplitPiece(s, this.currentLocals.get(s.localId));
|
|
4103
|
+
const spanLength = deferred ? B.slot() : null;
|
|
4104
|
+
if (spanLength)
|
|
4105
|
+
B.entryAllocas.push(`${spanLength} = alloca ${this.sizeType}`);
|
|
4106
|
+
const idxSlot = snapshot ? null : B.slot();
|
|
4107
|
+
if (idxSlot) {
|
|
4108
|
+
B.entryAllocas.push(`${idxSlot} = alloca double`);
|
|
4109
|
+
B.line(`store double ${f64Lit(0)}, ptr ${idxSlot}`);
|
|
4110
|
+
}
|
|
3929
4111
|
const lc = B.newLabel("fof.c");
|
|
3930
4112
|
const lb = B.newLabel("fof.b");
|
|
3931
4113
|
const lu = B.newLabel("fof.u");
|
|
3932
4114
|
const le = B.newLabel("fof.e");
|
|
4115
|
+
const workerBudget = this.workerLoopBudget();
|
|
3933
4116
|
B.br(lc);
|
|
3934
4117
|
B.startBlock(lc);
|
|
3935
|
-
|
|
3936
|
-
const len = B.tmp();
|
|
4118
|
+
this.emitWorkerLoopCheck(workerBudget);
|
|
3937
4119
|
const inBounds = B.tmp();
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
4120
|
+
let cur;
|
|
4121
|
+
if (snapshot && cursor && scratch) {
|
|
4122
|
+
cur = spanLength
|
|
4123
|
+
? emitSplitSpanNext(this, snapshot, cursor, spanLength)
|
|
4124
|
+
: emitSplitNext(this, snapshot, cursor, scratch);
|
|
4125
|
+
B.line(`${inBounds} = icmp ne ptr ${cur}, null`);
|
|
4126
|
+
}
|
|
4127
|
+
else {
|
|
4128
|
+
const i = B.tmp(), len = B.tmp();
|
|
4129
|
+
this.declare(`declare double @scr_arr_len(ptr)`);
|
|
4130
|
+
B.line(`${i} = load double, ptr ${idxSlot}`);
|
|
4131
|
+
B.line(`${len} = call double @scr_arr_len(ptr ${arr.name})`);
|
|
4132
|
+
B.line(`${inBounds} = fcmp olt double ${i}, ${len}`);
|
|
4133
|
+
cur = i;
|
|
4134
|
+
}
|
|
3942
4135
|
B.condBr(inBounds, lb, le);
|
|
3943
4136
|
B.startBlock(lb);
|
|
3944
4137
|
this.jumpTargets.push({
|
|
@@ -3956,11 +4149,22 @@ export class LlEmitter {
|
|
|
3956
4149
|
this.scopes.push([]);
|
|
3957
4150
|
const localInfo = this.currentLocals.get(s.localId);
|
|
3958
4151
|
const slot = `%${mangleLocal(s.localId)}`;
|
|
3959
|
-
const
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
3963
|
-
|
|
4152
|
+
const borrowedElement = !snapshot && this.loopArrayBorrows.has(s);
|
|
4153
|
+
if (!snapshot) {
|
|
4154
|
+
const acc = elemAccess(elem);
|
|
4155
|
+
const accTy = acc === "f64" ? "double" : acc === "bool" ? "i1" : "ptr";
|
|
4156
|
+
const getter = borrowedElement ? "scr_arr_borrow_ref" : `scr_arr_get_${acc}`;
|
|
4157
|
+
this.declare(`declare ${acc === "bool" ? "zeroext i1" : accTy} @${getter}(ptr, double)`);
|
|
4158
|
+
const value = B.tmp();
|
|
4159
|
+
B.line(`${value} = call ${accTy} @${getter}(ptr ${arr.name}, double ${cur})`);
|
|
4160
|
+
cur = value;
|
|
4161
|
+
}
|
|
4162
|
+
if (spanLength) {
|
|
4163
|
+
const length = B.tmp();
|
|
4164
|
+
B.line(`${length} = load ${this.sizeType}, ptr ${spanLength}`);
|
|
4165
|
+
this.splitSpans.set(s.localId, { bytes: cur, length, scratch: scratch });
|
|
4166
|
+
cur = "null";
|
|
4167
|
+
}
|
|
3964
4168
|
if (localInfo?.boxed) {
|
|
3965
4169
|
// Captured loop variable: a fresh box per iteration, matching the
|
|
3966
4170
|
// fresh const binding. The box takes ownership of a ref element's
|
|
@@ -3973,10 +4177,12 @@ export class LlEmitter {
|
|
|
3973
4177
|
}
|
|
3974
4178
|
else {
|
|
3975
4179
|
B.line(`store ${this.llType(elem)} ${cur}, ptr ${slot}`);
|
|
3976
|
-
if (isRefCounted(elem))
|
|
4180
|
+
if (isRefCounted(elem) && !borrowedElement)
|
|
3977
4181
|
this.scopes[this.scopes.length - 1].push({ slot, type: elem });
|
|
3978
4182
|
}
|
|
3979
4183
|
this.emitStmts(s.body);
|
|
4184
|
+
if (spanLength)
|
|
4185
|
+
this.splitSpans.delete(s.localId);
|
|
3980
4186
|
const endedWithJump = endsWithJump(s.body);
|
|
3981
4187
|
const scope = this.scopes.pop();
|
|
3982
4188
|
if (!endedWithJump)
|
|
@@ -3984,11 +4190,12 @@ export class LlEmitter {
|
|
|
3984
4190
|
this.jumpTargets.pop();
|
|
3985
4191
|
B.br(lu);
|
|
3986
4192
|
B.startBlock(lu);
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
4193
|
+
if (idxSlot) {
|
|
4194
|
+
const i2 = B.tmp(), i3 = B.tmp();
|
|
4195
|
+
B.line(`${i2} = load double, ptr ${idxSlot}`);
|
|
4196
|
+
B.line(`${i3} = fadd double ${i2}, ${f64Lit(1)}`);
|
|
4197
|
+
B.line(`store double ${i3}, ptr ${idxSlot}`);
|
|
4198
|
+
}
|
|
3992
4199
|
B.br(lc);
|
|
3993
4200
|
B.startBlock(le);
|
|
3994
4201
|
break;
|
|
@@ -4517,10 +4724,20 @@ export class LlEmitter {
|
|
|
4517
4724
|
if (e.kind === "strLit")
|
|
4518
4725
|
return { name: this.internLiteral(e.value), type: e.type };
|
|
4519
4726
|
if (e.kind === "varRef") {
|
|
4727
|
+
this.materializeSplitLocal(e.localId);
|
|
4520
4728
|
const binding = this.binding(e.localId);
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4729
|
+
if (binding.kind === "boxed") {
|
|
4730
|
+
// A projection consumes this pointer before any user code runs.
|
|
4731
|
+
// Keep TDZ checks and caught-value conversion on the owned path.
|
|
4732
|
+
if (!this.canBorrowReceiver(e))
|
|
4733
|
+
return this.emitExpr(e);
|
|
4734
|
+
const box = this.loadBox(binding.slot);
|
|
4735
|
+
const payload = this.B.tmp();
|
|
4736
|
+
const value = this.B.tmp();
|
|
4737
|
+
this.B.line(`${payload} = getelementptr inbounds %ScrBox, ptr ${box}, i32 0, i32 5`);
|
|
4738
|
+
this.B.line(`${value} = load ptr, ptr ${payload}`);
|
|
4739
|
+
return { name: value, type: e.type };
|
|
4740
|
+
}
|
|
4524
4741
|
if (binding.kind === "global")
|
|
4525
4742
|
this.checkGlobalTdz(e.localId);
|
|
4526
4743
|
const value = this.B.tmp();
|
|
@@ -4576,8 +4793,14 @@ export class LlEmitter {
|
|
|
4576
4793
|
}
|
|
4577
4794
|
canBorrowReceiver(e) {
|
|
4578
4795
|
switch (e.kind) {
|
|
4579
|
-
case "varRef":
|
|
4580
|
-
|
|
4796
|
+
case "varRef": {
|
|
4797
|
+
const binding = this.binding(e.localId);
|
|
4798
|
+
return (binding.kind !== "boxed" ||
|
|
4799
|
+
(!binding.local.tdz &&
|
|
4800
|
+
binding.type.kind === e.type.kind &&
|
|
4801
|
+
e.type.kind !== "caught" &&
|
|
4802
|
+
isRefCounted(e.type)));
|
|
4803
|
+
}
|
|
4581
4804
|
case "unionNarrow":
|
|
4582
4805
|
return this.canBorrowReceiver(e.value);
|
|
4583
4806
|
case "fieldGet":
|
|
@@ -4593,6 +4816,11 @@ export class LlEmitter {
|
|
|
4593
4816
|
return false;
|
|
4594
4817
|
}
|
|
4595
4818
|
}
|
|
4819
|
+
materializeSplitLocal(localId) {
|
|
4820
|
+
const span = this.splitSpans.get(localId);
|
|
4821
|
+
if (span)
|
|
4822
|
+
materializeSplitPiece(this, localId, span);
|
|
4823
|
+
}
|
|
4596
4824
|
emitExpr(e) {
|
|
4597
4825
|
return emitExpr(this, e);
|
|
4598
4826
|
}
|