@scriptc/compiler 0.2.9 → 0.3.0
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 +2 -36
- package/ambient/scriptc-overrides.d.ts +1 -25
- package/ambient/scriptc.d.ts +1 -9
- package/dist/backend/cycle-analysis.d.ts +56 -0
- package/dist/backend/cycle-analysis.js +175 -14
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +95 -2
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/cycle-mutability.d.ts +3 -7
- package/dist/backend/cycle-mutability.js +4 -30
- package/dist/backend/cycle-mutability.js.map +1 -1
- package/dist/backend/executable-features.d.ts +1 -1
- package/dist/backend/executable-features.js +3 -8
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/immutability.d.ts +57 -0
- package/dist/backend/immutability.js +178 -0
- package/dist/backend/immutability.js.map +1 -0
- package/dist/backend/immutability.test.js +131 -0
- package/dist/backend/immutability.test.js.map +1 -0
- package/dist/backend/library-pack.js +0 -2
- package/dist/backend/library-pack.js.map +1 -1
- package/dist/backend/linker.js +1 -1
- package/dist/backend/linker.js.map +1 -1
- package/dist/backend/llvm/borrowed-inputs.d.ts +9 -2
- package/dist/backend/llvm/borrowed-inputs.js +31 -3
- package/dist/backend/llvm/borrowed-inputs.js.map +1 -1
- package/dist/backend/llvm/checked-narrows.test.js +1 -1
- package/dist/backend/llvm/classes.d.ts +28 -0
- package/dist/backend/llvm/classes.js +48 -14
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +134 -6
- package/dist/backend/llvm/classes.test.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +13 -0
- package/dist/backend/llvm/common.js +13 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.d.ts +1 -1
- package/dist/backend/llvm/constant-callbacks.js +3 -3
- package/dist/backend/llvm/constant-callbacks.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.test.js +1 -1
- package/dist/backend/llvm/dense-array-access.js +5 -4
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.test.js +10 -2
- package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +2 -1
- package/dist/backend/llvm/dyn.js +3 -76
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +67 -19
- package/dist/backend/llvm/emitter.js +443 -226
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +21 -3
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-async.test.js +1 -1
- package/dist/backend/llvm/expr-calls.js +14 -6
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +41 -14
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-control.js +4 -107
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dispatch.d.ts +1 -2
- package/dist/backend/llvm/expr-dispatch.js +0 -41
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.d.ts +1 -1
- package/dist/backend/llvm/expr-dynamic.js +13 -27
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +30 -3
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.test.js +55 -2
- package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +4 -4
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.test.js +1 -1
- package/dist/backend/llvm/lib-dispatch.js +0 -1
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +0 -13
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +0 -8
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +3 -3
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.test.js +1 -1
- package/dist/backend/llvm/local-union-storage.test.js +1 -1
- package/dist/backend/llvm/loop-array-borrows.d.ts +5 -2
- package/dist/backend/llvm/loop-array-borrows.js +27 -8
- package/dist/backend/llvm/loop-array-borrows.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.d.ts +14 -0
- package/dist/backend/llvm/map-number-lookup.js +33 -2
- package/dist/backend/llvm/map-number-lookup.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.d.ts +5 -0
- package/dist/backend/llvm/map-read-lifetimes.js +20 -4
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +25 -3
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/reference-writes.d.ts +124 -0
- package/dist/backend/llvm/reference-writes.js +1090 -0
- package/dist/backend/llvm/reference-writes.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +8 -5
- package/dist/backend/llvm/shapes.js +37 -13
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +3 -3
- 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 +40 -11
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/string-reads.d.ts +3 -0
- package/dist/backend/llvm/string-reads.js +31 -0
- package/dist/backend/llvm/string-reads.js.map +1 -1
- package/dist/backend/llvm/switch-dispatch.d.ts +2 -2
- package/dist/backend/llvm/switch-dispatch.js +35 -22
- package/dist/backend/llvm/switch-dispatch.js.map +1 -1
- package/dist/backend/llvm/switch-dispatch.test.js +29 -11
- package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
- package/dist/backend/llvm/walk-borrows.d.ts +8 -1
- package/dist/backend/llvm/walk-borrows.js +15 -4
- package/dist/backend/llvm/walk-borrows.js.map +1 -1
- package/dist/backend/may-throw.d.ts +36 -2
- package/dist/backend/may-throw.js +308 -21
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +147 -2
- package/dist/backend/may-throw.test.js.map +1 -1
- package/dist/backend/native/artifact-stamps.js +0 -2
- package/dist/backend/native/artifact-stamps.js.map +1 -1
- package/dist/backend/native/cache-warm.d.ts +1 -1
- package/dist/backend/native/cache-warm.js +2 -3
- package/dist/backend/native/cache-warm.js.map +1 -1
- package/dist/backend/native/compiler-fingerprint.d.ts +1 -1
- package/dist/backend/native/compiler-fingerprint.js +4 -7
- package/dist/backend/native/compiler-fingerprint.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +3 -28
- package/dist/backend/native/driver.js +1 -3
- package/dist/backend/native/driver.js.map +1 -1
- package/dist/backend/native/executable.d.ts +0 -15
- package/dist/backend/native/executable.js +17 -172
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/tool-identity.js +0 -1
- package/dist/backend/native/tool-identity.js.map +1 -1
- package/dist/backend/native/vendor.d.ts +1 -1
- package/dist/backend/native/vendor.js +1 -1
- package/dist/backend/native/vendor.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +0 -2
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +23 -33
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/publication.d.ts +5 -0
- package/dist/backend/publication.js +10 -0
- package/dist/backend/publication.js.map +1 -1
- package/dist/backend/publication.test.js +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 -2
- package/dist/backend/runtime-pack-core.js +5 -14
- package/dist/backend/runtime-pack-core.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +3 -8
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +22 -19
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/target-diagnostics.d.ts +0 -5
- package/dist/backend/target-diagnostics.js +1 -11
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/target-diagnostics.test.js +1 -1
- package/dist/backend/vendor-archives.d.ts +1 -7
- package/dist/backend/vendor-archives.js +9 -189
- package/dist/backend/vendor-archives.js.map +1 -1
- package/dist/backend/vendor-inputs.d.ts +0 -1
- package/dist/backend/vendor-inputs.js +0 -1
- package/dist/backend/vendor-inputs.js.map +1 -1
- package/dist/backend/warm-cache.js +3 -5
- package/dist/backend/warm-cache.js.map +1 -1
- package/dist/cli/command.js +4 -8
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/host.d.ts +1 -1
- package/dist/cli/usage.d.ts +1 -5
- package/dist/cli/usage.js +4 -9
- package/dist/cli/usage.js.map +1 -1
- package/dist/compat/fetch-profile.d.ts +2 -2
- package/dist/compat/fetch-profile.js +16 -25
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/compile-types.d.ts +2 -17
- package/dist/contracts/check.d.ts +8 -0
- package/dist/contracts/check.js +1573 -0
- package/dist/contracts/check.js.map +1 -0
- package/dist/coverage/report.d.ts +5 -22
- package/dist/coverage/report.js +12 -76
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/surface-manifest.d.ts +3 -3
- package/dist/coverage/surface-manifest.js +22 -27
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/coverage/verdict-cache.d.ts +1 -3
- package/dist/coverage/verdict-cache.js +2 -7
- package/dist/coverage/verdict-cache.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +11 -60
- package/dist/diagnostics/diagnostic.js +39 -118
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/envelope.d.ts +3 -4
- package/dist/diagnostics/envelope.js +0 -9
- package/dist/diagnostics/envelope.js.map +1 -1
- package/dist/diagnostics/envelope.test.js +1 -1
- package/dist/diagnostics/envelope.test.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +0 -3
- package/dist/executable/executable-cache.js +2 -4
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +0 -4
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/executable/prepare.js +14 -2
- package/dist/executable/prepare.js.map +1 -1
- package/dist/frontend/analysis.js +10 -10
- package/dist/frontend/analysis.js.map +1 -1
- package/dist/frontend/cjs-syntax.js +0 -88
- package/dist/frontend/cjs-syntax.js.map +1 -1
- package/dist/frontend/contract-types.d.ts +50 -0
- package/dist/frontend/contract-types.js +232 -0
- package/dist/frontend/contract-types.js.map +1 -0
- package/dist/frontend/dts-paths.d.ts +1 -1
- package/dist/frontend/dts-paths.js +1 -1
- package/dist/frontend/lowering/abstract-equality.js +1 -4
- package/dist/frontend/lowering/abstract-equality.js.map +1 -1
- package/dist/frontend/lowering/array-values.js +4 -11
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/builtins/arguments.js +0 -13
- package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
- package/dist/frontend/lowering/builtins/crypto.d.ts +0 -4
- package/dist/frontend/lowering/builtins/crypto.js +0 -4
- package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
- package/dist/frontend/lowering/builtins/json.js +1 -39
- package/dist/frontend/lowering/builtins/json.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-resolution.d.ts +0 -15
- package/dist/frontend/lowering/builtins/module-resolution.js +5 -44
- package/dist/frontend/lowering/builtins/module-resolution.js.map +1 -1
- package/dist/frontend/lowering/builtins/numbers.d.ts +0 -6
- package/dist/frontend/lowering/builtins/numbers.js +6 -57
- package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
- package/dist/frontend/lowering/builtins/promises.js +4 -67
- package/dist/frontend/lowering/builtins/promises.js.map +1 -1
- package/dist/frontend/lowering/builtins/workers.js +1 -1
- package/dist/frontend/lowering/builtins/workers.js.map +1 -1
- package/dist/frontend/lowering/call-arguments.d.ts +1 -37
- package/dist/frontend/lowering/call-arguments.js +11 -94
- package/dist/frontend/lowering/call-arguments.js.map +1 -1
- package/dist/frontend/lowering/call-signatures.d.ts +1 -6
- package/dist/frontend/lowering/call-signatures.js +16 -68
- package/dist/frontend/lowering/call-signatures.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +19 -4
- package/dist/frontend/lowering/class-dynamic-dispatch.js +168 -98
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +44 -4
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
- package/dist/frontend/lowering/class-method-mutations.js +0 -2
- package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
- package/dist/frontend/lowering/class-protocols.js +1 -1
- package/dist/frontend/lowering/class-protocols.js.map +1 -1
- package/dist/frontend/lowering/coercions/function-adapters.js +5 -35
- package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
- package/dist/frontend/lowering/coercions/state.d.ts +0 -1
- package/dist/frontend/lowering/coercions/state.js +0 -1
- package/dist/frontend/lowering/coercions/state.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural-plans.js +2 -4
- package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural.js +2 -12
- package/dist/frontend/lowering/coercions/structural.js.map +1 -1
- package/dist/frontend/lowering/coercions/unions.d.ts +12 -0
- package/dist/frontend/lowering/coercions/unions.js +63 -1
- package/dist/frontend/lowering/coercions/unions.js.map +1 -1
- package/dist/frontend/lowering/containers/array-callbacks.js +9 -28
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-construction.js +2 -3
- package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
- package/dist/frontend/lowering/containers/array-methods.js +10 -54
- package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +0 -1
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/callback-arguments.js +2 -10
- package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +1 -6
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/indexed-objects.js +0 -2
- package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.d.ts +0 -6
- package/dist/frontend/lowering/containers/string-and-regexp.js +2 -10
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/expressions/evaluation-safety.js +0 -3
- package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -1
- package/dist/frontend/lowering/expressions/native-proxy.js +1 -1
- package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
- package/dist/frontend/lowering/expressions/nullish-assignment.js +0 -1
- package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.d.ts +0 -8
- package/dist/frontend/lowering/expressions/object-literals.js +8 -35
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.d.ts +0 -4
- package/dist/frontend/lowering/expressions/optional-chains.js +7 -67
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/function-context.js +0 -1
- package/dist/frontend/lowering/function-context.js.map +1 -1
- package/dist/frontend/lowering/generic-functions.js +0 -1
- package/dist/frontend/lowering/generic-functions.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.js +10 -77
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-array-sort.js +1 -10
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
- package/dist/frontend/lowering/lower-array-sort.test.js +2 -2
- package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +2 -3
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-async-iteration.js +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +2 -27
- package/dist/frontend/lowering/lower-calls.js +56 -465
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +11 -49
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-comptime.js +2 -3
- package/dist/frontend/lowering/lower-comptime.js.map +1 -1
- package/dist/frontend/lowering/lower-enums.js +5 -8
- package/dist/frontend/lowering/lower-enums.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.js +3 -4
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-expando.js +3 -5
- package/dist/frontend/lowering/lower-expando.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +0 -8
- package/dist/frontend/lowering/lower-exprs.js +133 -908
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-functions.js +2 -5
- package/dist/frontend/lowering/lower-functions.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +1 -50
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +0 -43
- package/dist/frontend/lowering/lower-modules.js +25 -329
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.test.js +5 -5
- package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +0 -30
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stdlib.d.ts +98 -0
- package/dist/frontend/lowering/{lower-island.js → lower-stdlib.js} +97 -1160
- package/dist/frontend/lowering/lower-stdlib.js.map +1 -0
- package/dist/frontend/lowering/lower-stmts.d.ts +0 -16
- package/dist/frontend/lowering/lower-stmts.js +58 -1016
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.test.js +1 -1
- package/dist/frontend/lowering/lower-stmts.test.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +1 -3
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +26 -151
- package/dist/frontend/lowering/lowerer.js +120 -770
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.js +4 -51
- package/dist/frontend/lowering/lowerer.test.js.map +1 -1
- package/dist/frontend/lowering/narrowing-stability.d.ts +100 -0
- package/dist/frontend/lowering/narrowing-stability.js +1174 -0
- package/dist/frontend/lowering/narrowing-stability.js.map +1 -0
- package/dist/frontend/lowering/narrowing-stability.test.js +150 -0
- package/dist/frontend/lowering/narrowing-stability.test.js.map +1 -0
- package/dist/frontend/lowering/optional-arguments.js +0 -2
- package/dist/frontend/lowering/optional-arguments.js.map +1 -1
- package/dist/frontend/lowering/sanitize-class-types.test.js +2 -2
- package/dist/frontend/lowering/strict-equality.js +1 -1
- package/dist/frontend/lowering/strict-equality.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +6 -45
- package/dist/frontend/lowering/surfaces.js +5 -65
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/module-syntax.d.ts +0 -3
- package/dist/frontend/module-syntax.js.map +1 -1
- package/dist/frontend/npm-node.d.ts +0 -7
- package/dist/frontend/npm-node.js +0 -7
- package/dist/frontend/npm-node.js.map +1 -1
- package/dist/frontend/npm-static-rewrite-syntax.d.ts +1 -1
- package/dist/frontend/npm-static-rewrite-syntax.js +6 -82
- package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
- package/dist/frontend/npm-static.d.ts +1 -1
- package/dist/frontend/npm-static.js +6 -71
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/npm.d.ts +3 -319
- package/dist/frontend/npm.js +6 -1007
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/npm.test.js +2 -197
- package/dist/frontend/npm.test.js.map +1 -1
- package/dist/frontend/pipeline-native.js +1 -2
- package/dist/frontend/pipeline-native.js.map +1 -1
- package/dist/frontend/pipeline.d.ts +3 -11
- package/dist/frontend/pipeline.js +37 -56
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/pipeline.test.js +12 -6
- package/dist/frontend/pipeline.test.js.map +1 -1
- package/dist/frontend/program.d.ts +0 -34
- package/dist/frontend/program.js +13 -98
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/provenance-core.d.ts +0 -4
- package/dist/frontend/provenance-core.js +4 -37
- package/dist/frontend/provenance-core.js.map +1 -1
- package/dist/frontend/provenance-registry.d.ts +0 -4
- package/dist/frontend/provenance-registry.js +0 -20
- package/dist/frontend/provenance-registry.js.map +1 -1
- package/dist/frontend/resolve.d.ts +0 -12
- package/dist/frontend/resolve.js +0 -34
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/runtime-resolve.js +2 -2
- package/dist/frontend/runtime-resolve.js.map +1 -1
- package/dist/frontend/services-node.js +2 -3
- package/dist/frontend/services-node.js.map +1 -1
- package/dist/frontend/services.d.ts +1 -8
- package/dist/frontend/services.js +2 -22
- package/dist/frontend/services.js.map +1 -1
- package/dist/frontend/services.test.js +0 -38
- package/dist/frontend/services.test.js.map +1 -1
- package/dist/frontend/tsc-codes.js +0 -11
- package/dist/frontend/tsc-codes.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +2 -27
- package/dist/frontend/type-mapper.js +85 -153
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +7 -10
- package/dist/index.js.map +1 -1
- package/dist/ir/api.d.ts +1 -1
- package/dist/ir/api.js +1 -1
- package/dist/ir/api.js.map +1 -1
- package/dist/ir/builtin-effects.js +0 -5
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +1 -55
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/constant-globals.test.js +1 -1
- package/dist/ir/constant-tables.test.js +1 -1
- package/dist/ir/final-fields.test.js +1 -1
- package/dist/ir/initializer-bindings.test.js +1 -1
- package/dist/ir/int32-slots.d.ts +29 -3
- package/dist/ir/int32-slots.js +152 -66
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +1 -1
- package/dist/ir/integer-loops.js +3 -0
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-loops.test.js +26 -1
- package/dist/ir/integer-loops.test.js.map +1 -1
- package/dist/ir/integer-ranges.d.ts +20 -0
- package/dist/ir/integer-ranges.js +178 -21
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/integer-ranges.test.js +148 -3
- package/dist/ir/integer-ranges.test.js.map +1 -1
- package/dist/ir/ir.d.ts +44 -284
- package/dist/ir/ir.js +10 -259
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +2 -7
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/runtime-features.d.ts +3 -30
- package/dist/ir/runtime-features.js +5 -41
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/scalar-records.test.js +1 -1
- package/dist/ir/serialize.d.ts +6 -2
- package/dist/ir/serialize.js +11 -3
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/traverse.js +0 -21
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/unshare.d.ts +14 -0
- package/dist/ir/unshare.js +60 -0
- package/dist/ir/unshare.js.map +1 -0
- package/dist/ir/unshare.test.js +115 -0
- package/dist/ir/unshare.test.js.map +1 -0
- package/dist/ir/validate.js +9 -207
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +6 -6
- package/dist/library/fence-eval.test.js +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/library-cache.test.js +5 -5
- package/dist/library/prepare.js +14 -20
- package/dist/library/prepare.js.map +1 -1
- package/dist/native/cli.js +0 -2
- package/dist/native/cli.js.map +1 -1
- package/dist/native/compiler.test.js +2 -4
- package/dist/native/compiler.test.js.map +1 -1
- package/dist/native/prepare.js +2 -4
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/sanitizer.js +2 -16
- package/dist/native/sanitizer.js.map +1 -1
- package/dist/native/sanitizer.test.js +0 -3
- package/dist/native/sanitizer.test.js.map +1 -1
- package/dist/startup-cache.js +0 -2
- package/dist/startup-cache.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +80 -88
- package/dist/backend/llvm/expr-island.d.ts +0 -15
- package/dist/backend/llvm/expr-island.js +0 -709
- package/dist/backend/llvm/expr-island.js.map +0 -1
- package/dist/frontend/lowering/coercions/island.d.ts +0 -37
- package/dist/frontend/lowering/coercions/island.js +0 -350
- package/dist/frontend/lowering/coercions/island.js.map +0 -1
- package/dist/frontend/lowering/lower-island.d.ts +0 -229
- package/dist/frontend/lowering/lower-island.js.map +0 -1
- package/dist/frontend/lowering/lower-island.test.js +0 -56
- package/dist/frontend/lowering/lower-island.test.js.map +0 -1
- package/dist/frontend/npm-fetch-analysis.d.ts +0 -17
- package/dist/frontend/npm-fetch-analysis.js +0 -109
- package/dist/frontend/npm-fetch-analysis.js.map +0 -1
- package/dist/frontend/npm-fetch-analysis.test.js +0 -130
- package/dist/frontend/npm-fetch-analysis.test.js.map +0 -1
- package/dist/frontend/npm-fetch-node.d.ts +0 -2
- package/dist/frontend/npm-fetch-node.js +0 -12
- package/dist/frontend/npm-fetch-node.js.map +0 -1
- package/dist/frontend/npm-fetch-syntax.d.ts +0 -6
- package/dist/frontend/npm-fetch-syntax.js +0 -202
- package/dist/frontend/npm-fetch-syntax.js.map +0 -1
- package/dist/native/runtime-typescript.d.ts +0 -4
- package/dist/native/runtime-typescript.js +0 -74
- package/dist/native/runtime-typescript.js.map +0 -1
- package/dist/native/runtime-typescript.test.js +0 -41
- package/dist/native/runtime-typescript.test.js.map +0 -1
- /package/dist/{frontend/lowering/lower-island.test.d.ts → backend/immutability.test.d.ts} +0 -0
- /package/dist/frontend/{npm-fetch-analysis.test.d.ts → lowering/narrowing-stability.test.d.ts} +0 -0
- /package/dist/{native/runtime-typescript.test.d.ts → ir/unshare.test.d.ts} +0 -0
|
@@ -2,30 +2,12 @@ import { emitLlvmLayouts } from "./layouts.js";
|
|
|
2
2
|
import { FIRST_EMITTED_CYC_KIND, inlineAllocSupported } from "./alloc.js";
|
|
3
3
|
import { llvmBytes as llBytes } from "../literals.js";
|
|
4
4
|
import { InternalCompilerError } from "../../errors.js";
|
|
5
|
-
/** Lower typed IR to LLVM, using the runtime's C ABI.
|
|
6
|
-
*
|
|
7
|
-
* Reference-counted temporaries own one reference. Declarations, assignments,
|
|
8
|
-
* returns and arguments move that ownership; frame and scope exits release
|
|
9
|
-
* everything remaining. Slot-backed entries release the slot's current value.
|
|
10
|
-
*
|
|
11
|
-
* Exceptions use a pending flag and explicit cleanup edges. Throwing calls
|
|
12
|
-
* test scr_exc_pending before consuming results, release the scopes crossed,
|
|
13
|
-
* and branch to the innermost handler or return to the caller. Catch bindings
|
|
14
|
-
* hold ScrCaught snapshots; finally runs on normal, throwing and returning
|
|
15
|
-
* paths. This keeps ownership cleanup intact without nonlocal jumps.
|
|
16
|
-
*
|
|
17
|
-
* Program objects are emitted by the packaged LLVM helper and linked with
|
|
18
|
-
* runtime packs. Sanitizer development builds use an external LLVM driver.
|
|
19
|
-
* Dynamic values and islands share the runtime ABI; embedded npm modules use
|
|
20
|
-
* compressed source tables that the runtime inflates on demand.
|
|
21
|
-
*/
|
|
22
5
|
import { createHash } from "node:crypto";
|
|
23
|
-
import { deflateRawSync } from "node:zlib";
|
|
24
6
|
import { endsWithJump, matchStringSelfConcat, streamTypedRefEligible, undefinedArmTag, } from "../../ir/analysis.js";
|
|
25
7
|
import { emitLibraryIdentityLines } from "../library-identity-markers.js";
|
|
26
8
|
import { loopTestsEveryIteration } from "../loop-polls.js";
|
|
27
9
|
import { CAUGHT, ffiCallbackType, isDynTypedRefType, isFfiContextParam, isRefCounted, isUnitType, POINTER_KINDS, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, typeEquals, typeKey, STRING, VOID, } from "../../ir/ir.js";
|
|
28
|
-
import { moduleRuntimeFeatures
|
|
10
|
+
import { moduleRuntimeFeatures } from "../../ir/runtime-features.js";
|
|
29
11
|
import { matchIntegerArrayForLoop, matchIntegerBytesForLoop, matchIntegerCountedForLoop, } from "../../ir/integer-loops.js";
|
|
30
12
|
import { emitCountedLoopLimit } from "./counted-loops.js";
|
|
31
13
|
import { emitLiteralSwitch } from "./switch-dispatch.js";
|
|
@@ -36,6 +18,7 @@ import { scalarizeNumericRecords } from "../../ir/scalar-records.js";
|
|
|
36
18
|
import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js";
|
|
37
19
|
import { everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse.js";
|
|
38
20
|
import { analyzeIntegerRanges, INT32_RANGE } from "../../ir/integer-ranges.js";
|
|
21
|
+
import { unshareNodes } from "../../ir/unshare.js";
|
|
39
22
|
import { analyzeInt32Slots } from "../../ir/int32-slots.js";
|
|
40
23
|
import { analyzeFinalFields, constructorClass } from "../../ir/final-fields.js";
|
|
41
24
|
import { foldConstantGlobals } from "../../ir/constant-globals.js";
|
|
@@ -56,10 +39,11 @@ import { CheckedNarrows, emitCheckedNarrowReceiver } from "./checked-narrows.js"
|
|
|
56
39
|
import { emitDenseArrayGet, emitDenseArraySet } from "./dense-array-access.js";
|
|
57
40
|
import { emitStackMapRead, findMapReadLifetimes, matchMapRead, } from "./map-read-lifetimes.js";
|
|
58
41
|
import { emitBorrowedFieldSequence, guardedValue } from "./borrowed-receivers.js";
|
|
59
|
-
import { emitBorrowedInput } from "./borrowed-inputs.js";
|
|
42
|
+
import { borrowableInputs, emitBorrowedInput } from "./borrowed-inputs.js";
|
|
60
43
|
import { analyzeWalks, findWalkBorrows } from "./walk-borrows.js";
|
|
61
44
|
import { findReboundParameters } from "./rebound-parameters.js";
|
|
62
45
|
import { ReferenceEffects } from "./reference-effects.js";
|
|
46
|
+
import { ReferenceWrites } from "./reference-writes.js";
|
|
63
47
|
import { LlvmDebugInfo } from "./debug-info.js";
|
|
64
48
|
import { StackCallbacks } from "./stack-callbacks.js";
|
|
65
49
|
import { findLoopArrayBorrows } from "./loop-array-borrows.js";
|
|
@@ -75,9 +59,9 @@ import { emitBorrowedResultCall, emitCallExpr } from "./expr-calls.js";
|
|
|
75
59
|
import { emitDynamicExpr } from "./expr-dynamic.js";
|
|
76
60
|
import { emitIntrinsicExpr, emitSerializationExpr, emitAsyncExpr } from "./expr-async.js";
|
|
77
61
|
import { PublishWalkers } from "./publish.js";
|
|
62
|
+
import { computeImmutableFields, stableGlobals } from "../immutability.js";
|
|
78
63
|
import { computePublishedTypes } from "../publication.js";
|
|
79
|
-
import {
|
|
80
|
-
import { emitJsMarshal, emitJsOp, emitJsExit, islandAdapter, islandTypedAdapter, } from "./expr-island.js";
|
|
64
|
+
import { emitExpr } from "./expr-dispatch.js";
|
|
81
65
|
import { dynKind, raceAdapterFor, genResultThunkFor, childExitThunkFor, childExitSignalThunkFor, childDataThunkFor, execFileThunkFor, ipcMessageThunkFor, ipcSendThunkFor, emitterFixedAdapter, wrapEmitterListener, unwrapNullableClosure, closeBindThunkFor, closeOverrideWrapFor, } from "./expr-callbacks.js";
|
|
82
66
|
import { streamDataAdapter, streamDoneFnFor, cryptoBytesThunkFor, fsRenameThunkFor, streamCbThunkFor, zlibBytesThunkFor, } from "./expr-stream-callbacks.js";
|
|
83
67
|
import { emitStableReceiver, resolveThunkFor, tagInSet, arrPush, emitArrayCopyLoop, emitStrIntrinsic, emitArrIntrinsic, emitDiscardedSplice, wrapNullable, emitMapNew, mapSet, emitMapLikeIntrinsic, emitSetNew, } from "./expr-containers.js";
|
|
@@ -97,7 +81,7 @@ import { LlWalkers } from "./walkers.js";
|
|
|
97
81
|
import { isObjectArm, NULLABLE_ABSENT, NULLABLE_NULL, NullableUnions } from "./nullable-unions.js";
|
|
98
82
|
import { emitNullablePresent, emitUnionPeek, emitUnionTag } from "./union-repr.js";
|
|
99
83
|
import { literalCapWord, literalCapWord32 } from "./string-key-hash.js";
|
|
100
|
-
import { NUMBER_MAP_ENTRY_DECL } from "./map-number-lookup.js";
|
|
84
|
+
import { NUMBER_MAP_ENTRY_DECL, STRING_MAP_ENTRY_DECL } from "./map-number-lookup.js";
|
|
101
85
|
import { STRING_READ_HELPERS } from "./string-reads.js";
|
|
102
86
|
import { emitConcatInputs, emitMixedConcat, numberPart, stringParts, } from "./string-construction.js";
|
|
103
87
|
import { arrNewCall, boxAccess, boxNewCall, boxReleaseSym, computeTraced, elemAccess, emitInlineRcHelpers, emitNullableRetainWrappers, FN_ATTRS, inlineRcDecls, llFieldType, releaseSym, retainSym, traceArg, typedRefConstructor, vAdapters, } from "./shapes.js";
|
|
@@ -127,14 +111,18 @@ function ffiCallbackDummyLl(callback) {
|
|
|
127
111
|
return "i32 0";
|
|
128
112
|
}
|
|
129
113
|
}
|
|
130
|
-
export function emitLlvmModule(
|
|
114
|
+
export function emitLlvmModule(input, options = {}) {
|
|
115
|
+
// Facts are keyed by node identity: emit the same module whether it was
|
|
116
|
+
// lowered in memory or read back from its serialized form.
|
|
117
|
+
const mod = unshareNodes(input);
|
|
131
118
|
// Keep source storage intact for debugger inspection in dev builds.
|
|
132
119
|
return new LlEmitter(options.debugSources === undefined
|
|
133
120
|
? scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction))
|
|
134
121
|
: mod, options).emit();
|
|
135
122
|
}
|
|
136
123
|
/** Keep large translation units below the host's single-string limit. */
|
|
137
|
-
export function emitLlvmModuleSource(
|
|
124
|
+
export function emitLlvmModuleSource(input, options = {}) {
|
|
125
|
+
const mod = unshareNodes(input);
|
|
138
126
|
const parts = new LlEmitter(options.debugSources === undefined
|
|
139
127
|
? scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction))
|
|
140
128
|
: mod, options).emitParts();
|
|
@@ -302,6 +290,12 @@ export class LlEmitter {
|
|
|
302
290
|
* fiberless-async analysis scans it for suspension entry points. */
|
|
303
291
|
fnDefText = new Map();
|
|
304
292
|
referenceEffects;
|
|
293
|
+
/** Field-sensitive reference writes (null in debug builds). */
|
|
294
|
+
referenceWrites = null;
|
|
295
|
+
borrowedReturnKeyCache = new Map();
|
|
296
|
+
/** The statement list being emitted and the current index, for blocks
|
|
297
|
+
* whose bindings end with the list (emitBlock and function bodies). */
|
|
298
|
+
stmtCursor = null;
|
|
305
299
|
optionalArrayReads;
|
|
306
300
|
checkedNarrows;
|
|
307
301
|
callArrayReads = new Map();
|
|
@@ -345,6 +339,9 @@ export class LlEmitter {
|
|
|
345
339
|
ffiHasRetainedCallback;
|
|
346
340
|
ffiHasForeignCallback;
|
|
347
341
|
globalTypes = new Map();
|
|
342
|
+
/** Module constants that keep one value once initialized
|
|
343
|
+
* (immutability.ts stableGlobals). */
|
|
344
|
+
stableGlobals = new Set();
|
|
348
345
|
tdzGlobals = new Map();
|
|
349
346
|
constantNumericTables;
|
|
350
347
|
/** May-throw analysis (computeMayThrow): pending
|
|
@@ -360,6 +357,13 @@ export class LlEmitter {
|
|
|
360
357
|
/** Static types whose values can be published (@scriptc/threads): their
|
|
361
358
|
* stores carry the frozen-object guard. Null without publish calls. */
|
|
362
359
|
publishedTypes;
|
|
360
|
+
/** Construction-only class and record fields (immutability.ts); null
|
|
361
|
+
* where the facts are disabled. */
|
|
362
|
+
immutableFields;
|
|
363
|
+
/** Constructor function names: their bodies may still write their own
|
|
364
|
+
* `this`'s construction-only fields. */
|
|
365
|
+
constructorFunctions;
|
|
366
|
+
inConstructor = false;
|
|
363
367
|
/** Method names with at least one may-throw implementation — the
|
|
364
368
|
* virtualCall pending check's key. */
|
|
365
369
|
mayThrowMethods = new Set();
|
|
@@ -436,6 +440,12 @@ export class LlEmitter {
|
|
|
436
440
|
initializerBindings;
|
|
437
441
|
/** Whole-program int32 storage and parameter/result facts. */
|
|
438
442
|
int32Slots;
|
|
443
|
+
/** Immutable module constants (contract types) whose graphs become
|
|
444
|
+
* immortal once initialized: their reads need no reference counting. */
|
|
445
|
+
immortalGlobals;
|
|
446
|
+
/** ProgramLifetime hierarchy roots (contract types): their instances are
|
|
447
|
+
* immortal from construction (classes.ts programLifetimeClass). */
|
|
448
|
+
programLifetime;
|
|
439
449
|
numericLocals = new Map();
|
|
440
450
|
captureIds = new Set();
|
|
441
451
|
/** Active induction bindings retain their width independently of size_t. */
|
|
@@ -495,6 +505,8 @@ export class LlEmitter {
|
|
|
495
505
|
this.constantNumericTables = findConstantNumericTables(mod);
|
|
496
506
|
this.initializerBindings = findInitializerBindings(mod);
|
|
497
507
|
this.int32Slots = analyzeInt32Slots(mod);
|
|
508
|
+
this.immortalGlobals = new Set(mod.contracts?.immortalGlobals ?? []);
|
|
509
|
+
this.programLifetime = new Set(mod.contracts?.programLifetime ?? []);
|
|
498
510
|
this.finalFields = analyzeFinalFields(mod);
|
|
499
511
|
this.sizeType = options.pointerBits === 32 ? "i32" : "i64";
|
|
500
512
|
this.ffiExtendNarrowIntegers =
|
|
@@ -549,6 +561,8 @@ export class LlEmitter {
|
|
|
549
561
|
this.workerEntryPolls = mt.workerEntryPolls ?? null;
|
|
550
562
|
this.stackChecks = mt.stackChecks ?? null;
|
|
551
563
|
this.publishedTypes = computePublishedTypes(mod);
|
|
564
|
+
this.immutableFields = computeImmutableFields(mod);
|
|
565
|
+
this.constructorFunctions = new Set((mod.classes ?? []).map((c) => `%${c.name}.constructor`));
|
|
552
566
|
this.indirectMayThrow = mt.indirect || mod.workers === true;
|
|
553
567
|
for (const cls of mod.classes ?? []) {
|
|
554
568
|
for (const m of cls.methods ?? []) {
|
|
@@ -568,6 +582,8 @@ export class LlEmitter {
|
|
|
568
582
|
this.optionalArrayReads = new OptionalArrayReads(this.fnByName, this.unionsById, (id) => this.nullableUnions.has(id));
|
|
569
583
|
this.checkedNarrows = new CheckedNarrows(this.fnByName);
|
|
570
584
|
this.referenceEffects = new ReferenceEffects(this.fnByName, (call) => this.optionalArrayReads.get(call) !== null, mod.classes ?? []);
|
|
585
|
+
if (this.debug === null)
|
|
586
|
+
this.referenceWrites = new ReferenceWrites(this.fnByName, mod.classes ?? [], (call) => this.optionalArrayReads.get(call) !== null, new Set((mod.globals ?? []).map((g) => g.id)), { unions: mod.unions, records: mod.records }, this.immutableFields);
|
|
571
587
|
const walkParameters = new Map();
|
|
572
588
|
if (this.debug === null) {
|
|
573
589
|
const host = {
|
|
@@ -575,9 +591,10 @@ export class LlEmitter {
|
|
|
575
591
|
borrowsWithoutOwning: (e) => this.borrowsWithoutOwning(e),
|
|
576
592
|
};
|
|
577
593
|
for (const fn of this.fnByName.values()) {
|
|
578
|
-
|
|
594
|
+
const preserving = this.referenceEffects.functions.has(fn.name);
|
|
595
|
+
if (!preserving && this.referenceWrites === null)
|
|
579
596
|
continue;
|
|
580
|
-
const walks = findWalkBorrows(fn, host);
|
|
597
|
+
const walks = findWalkBorrows(fn, preserving ? host : this.unwrittenWalkHost(fn, host));
|
|
581
598
|
if (walks.size === 0)
|
|
582
599
|
continue;
|
|
583
600
|
this.walkBorrowsByFunction.set(fn.name, walks);
|
|
@@ -661,6 +678,7 @@ export class LlEmitter {
|
|
|
661
678
|
},
|
|
662
679
|
pendingTestLines: (dest) => this.pendingTestLines(dest),
|
|
663
680
|
virtualEntry: (implFn) => this.virtualEntry(implFn),
|
|
681
|
+
programLifetime: this.programLifetime,
|
|
664
682
|
};
|
|
665
683
|
this.walkers = new LlWalkers(this.shapeHost);
|
|
666
684
|
this.dyn = new LlDyn(this.shapeHost);
|
|
@@ -682,6 +700,7 @@ export class LlEmitter {
|
|
|
682
700
|
if (g.tdz)
|
|
683
701
|
this.tdzGlobals.set(g.id, g.name);
|
|
684
702
|
}
|
|
703
|
+
this.stableGlobals = stableGlobals(mod);
|
|
685
704
|
// Runtime error, EventEmitter, and stream classes have known layouts.
|
|
686
705
|
// Subclasses embed the ScrEmitter/ScrStream prefixes from classes.ts.
|
|
687
706
|
const classes = mod.classes ?? [];
|
|
@@ -1087,23 +1106,6 @@ export class LlEmitter {
|
|
|
1087
1106
|
const asyncDefs = this.emitAsyncScaffolding();
|
|
1088
1107
|
const ffiCallbacks = this.emitFfiCallbackDefs();
|
|
1089
1108
|
const hasNoInlineRecordClone = [...this.recordCloneShapes].some((shapeId) => (this.recordsById.get(shapeId)?.fields.length ?? 0) >= 16);
|
|
1090
|
-
const embedded = this.mod.embedded;
|
|
1091
|
-
const usesIsland = embedded !== undefined && embedded.modules.length > 0;
|
|
1092
|
-
const storeNpmText = (text) => {
|
|
1093
|
-
const plain = Buffer.from(text, "utf8");
|
|
1094
|
-
if (text.length < NPM_COMPRESS_MIN)
|
|
1095
|
-
return { bytes: plain, raw: 0 };
|
|
1096
|
-
const deflated = deflateRawSync(plain, { level: 9 });
|
|
1097
|
-
return deflated.length < plain.length
|
|
1098
|
-
? { bytes: deflated, raw: plain.length }
|
|
1099
|
-
: { bytes: plain, raw: 0 };
|
|
1100
|
-
};
|
|
1101
|
-
const npmStored = usesIsland
|
|
1102
|
-
? embedded.modules.map((m) => ({
|
|
1103
|
-
src: storeNpmText(m.source),
|
|
1104
|
-
esm: m.esm === undefined ? null : storeNpmText(m.esm),
|
|
1105
|
-
}))
|
|
1106
|
-
: [];
|
|
1107
1109
|
// Module globals, FIRST OCCURRENCE per id: a class-expression static
|
|
1108
1110
|
// instantiated through several mixin applications registers one global
|
|
1109
1111
|
// id several times (2041-mixin-values) — C's tentative definitions
|
|
@@ -1167,24 +1169,14 @@ export class LlEmitter {
|
|
|
1167
1169
|
const usesDgram = runtimeFeatures.dgram;
|
|
1168
1170
|
const usesHttp2 = runtimeFeatures.http2;
|
|
1169
1171
|
const usesHttp = runtimeFeatures.http;
|
|
1170
|
-
// Fetch-referencing programs register
|
|
1171
|
-
//
|
|
1172
|
-
// compiles scr_fetch.c on the same predicate.
|
|
1172
|
+
// Fetch-referencing programs register native fetch before main.
|
|
1173
|
+
// Runtime selection compiles scr_fetch.c on the same predicate.
|
|
1173
1174
|
const usesFetch = runtimeFeatures.fetch;
|
|
1174
|
-
const
|
|
1175
|
-
const embedsNet = moduleEmbedsBuiltin(this.mod, "node:http") ||
|
|
1176
|
-
moduleEmbedsBuiltin(this.mod, "node:https") ||
|
|
1177
|
-
moduleEmbedsBuiltin(this.mod, "node:net") ||
|
|
1178
|
-
moduleEmbedsBuiltin(this.mod, "node:tls");
|
|
1179
|
-
const snapshotsTlsCa = runtimeFeatures.tls ||
|
|
1180
|
-
runtimeFeatures.tlsCa ||
|
|
1181
|
-
moduleEmbedsBuiltin(this.mod, "node:https") ||
|
|
1182
|
-
moduleEmbedsBuiltin(this.mod, "node:tls");
|
|
1175
|
+
const snapshotsTlsCa = runtimeFeatures.tls || runtimeFeatures.tlsCa;
|
|
1183
1176
|
// The process verdict has the same precedence as the C reference
|
|
1184
1177
|
// emitter: node:test owns the final status when present; otherwise an
|
|
1185
1178
|
// embedded process.exitCode owns it; ordinary programs return zero.
|
|
1186
1179
|
const usesNodeTest = runtimeFeatures.nodeTest;
|
|
1187
|
-
const programExitUsesIsland = !usesNodeTest && usesIsland;
|
|
1188
1180
|
// Declared NOW — the extern block flushes before main assembles.
|
|
1189
1181
|
if (usesEvents)
|
|
1190
1182
|
this.declare(`declare void @scr_events_install()`);
|
|
@@ -1221,19 +1213,6 @@ export class LlEmitter {
|
|
|
1221
1213
|
this.declare(`declare void @scr_http_dyn_install()`);
|
|
1222
1214
|
if (usesFetch)
|
|
1223
1215
|
this.declare(`declare void @scr_fetch_install()`);
|
|
1224
|
-
if (embedsZlib)
|
|
1225
|
-
this.declare(`declare void @scr_zlib_island_install()`);
|
|
1226
|
-
if (embedsNet)
|
|
1227
|
-
this.declare(`declare void @scr_net_island_install()`);
|
|
1228
|
-
if (usesIsland) {
|
|
1229
|
-
this.declare(`declare void @scr_island_modules(ptr, ${this.sizeType}, ptr, ${this.sizeType})`);
|
|
1230
|
-
this.declare(`declare void @scr_island_entry_module(ptr)`);
|
|
1231
|
-
this.declare(`declare i32 @scr_island_exit_code()`);
|
|
1232
|
-
if (moduleEmbedsCompressedNpm(this.mod)) {
|
|
1233
|
-
this.declare(`declare void @scr_island_set_inflate(ptr)`);
|
|
1234
|
-
this.declare(`declare zeroext i1 @scr_zlib_inflate_exact(ptr, ${this.sizeType}, ptr, ${this.sizeType})`);
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
1216
|
if (usesNodeTest)
|
|
1238
1217
|
this.declare(`declare i32 @scr_test_exit_code()`);
|
|
1239
1218
|
if (snapshotsTlsCa) {
|
|
@@ -1272,7 +1251,6 @@ export class LlEmitter {
|
|
|
1272
1251
|
// fibers as abandoned, so the RC audit downgrades exactly like the
|
|
1273
1252
|
// async loop-exhaustion story.
|
|
1274
1253
|
const runsLoop = this.usesTimers ||
|
|
1275
|
-
usesIsland ||
|
|
1276
1254
|
this.ffiHasForeignCallback ||
|
|
1277
1255
|
this.mod.functions.some((f) => f.async === true || f.generator !== undefined);
|
|
1278
1256
|
const uncaughtReleases = entryMayThrow && !asyncEntry ? globalReleaseLines("gu") : [];
|
|
@@ -1299,9 +1277,6 @@ export class LlEmitter {
|
|
|
1299
1277
|
this.declare(`declare void @scr_promise_rethrow_top_level(ptr)`);
|
|
1300
1278
|
this.declare(`declare void @scr_promise_release(ptr)`);
|
|
1301
1279
|
this.declare(`declare void @scr_exit_code_note(i32)`);
|
|
1302
|
-
if (programExitUsesIsland && inlineExitListeners) {
|
|
1303
|
-
this.declare(`declare ${this.sizeType} @scr_island_exit_code_version()`);
|
|
1304
|
-
}
|
|
1305
1280
|
}
|
|
1306
1281
|
const topPendingExitLines = () => {
|
|
1307
1282
|
if (!asyncEntry)
|
|
@@ -1310,28 +1285,18 @@ export class LlEmitter {
|
|
|
1310
1285
|
if (usesNodeTest) {
|
|
1311
1286
|
lines.push(` %tla_program_exit = call i32 @scr_test_exit_code()`);
|
|
1312
1287
|
}
|
|
1313
|
-
|
|
1314
|
-
lines.push(` %tla_program_exit = call i32 @scr_island_exit_code()`);
|
|
1315
|
-
}
|
|
1316
|
-
if (usesNodeTest || usesIsland) {
|
|
1288
|
+
if (usesNodeTest) {
|
|
1317
1289
|
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`);
|
|
1318
1290
|
}
|
|
1319
|
-
const exitStatus = usesNodeTest
|
|
1320
|
-
const tracksIslandExit = programExitUsesIsland && inlineExitListeners;
|
|
1321
|
-
if (tracksIslandExit) {
|
|
1322
|
-
lines.push(` %tla_exit_version = call ${this.sizeType} @scr_island_exit_code_version()`);
|
|
1323
|
-
}
|
|
1291
|
+
const exitStatus = usesNodeTest ? "%tla_exit_status" : "%tla_status";
|
|
1324
1292
|
// finish_top_level initially notes 13. Replace that hint before exit
|
|
1325
1293
|
// listeners run when a higher-priority verdict was already selected.
|
|
1326
1294
|
lines.push(` call void @scr_exit_code_note(i32 ${exitStatus})`);
|
|
1327
1295
|
for (const line of exitListenerLines("xp"))
|
|
1328
1296
|
lines.push(line);
|
|
1329
|
-
if (tracksIslandExit) {
|
|
1330
|
-
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 ]`);
|
|
1331
|
-
}
|
|
1332
1297
|
for (const line of topPendingReleases)
|
|
1333
1298
|
lines.push(line);
|
|
1334
|
-
lines.push(` ret i32 ${
|
|
1299
|
+
lines.push(` ret i32 ${exitStatus}`);
|
|
1335
1300
|
return lines;
|
|
1336
1301
|
};
|
|
1337
1302
|
// LIBRARY mode: the runtime entry points the generated library
|
|
@@ -1403,12 +1368,14 @@ export class LlEmitter {
|
|
|
1403
1368
|
`%ScrFfiTable = type { ptr, ${this.sizeType}, ${this.sizeType}, ptr, i8, ptr, ptr, ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, ptr, ptr }`,
|
|
1404
1369
|
`%ScrRegex = type { ${this.sizeType}, ptr, ptr, ptr, double, ptr, ptr }`,
|
|
1405
1370
|
// ScrArr mirrors scr_runtime.h field-for-field: { rc, len, cap, elem,
|
|
1406
|
-
//
|
|
1407
|
-
//
|
|
1408
|
-
// (
|
|
1409
|
-
//
|
|
1410
|
-
//
|
|
1411
|
-
|
|
1371
|
+
// cyc, ops, data, present, ext } (field numbers in SCR_ARR_FIELD),
|
|
1372
|
+
// where ops points at the element type's constant RC descriptor
|
|
1373
|
+
// (%ScrArrOps, SCR_ELEM_REF only) and ext at the out-of-line sparse,
|
|
1374
|
+
// property and metadata storage (NULL until first used). Live dynamic
|
|
1375
|
+
// stream commits swap its dense, presence and out-of-line storage while
|
|
1376
|
+
// preserving the target object's identity.
|
|
1377
|
+
`%ScrArr = type { ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, i32, i32, ptr, ptr, ptr, ptr }`,
|
|
1378
|
+
`%ScrArrOps = type { ptr, ptr, ptr }`,
|
|
1412
1379
|
// The ScrMap prefix { rc, key_kind, val_kind, val_retain, val_release,
|
|
1413
1380
|
// val_trace, key_retain, key_release, key_trace } — the inline RC
|
|
1414
1381
|
// fast paths test the two trace slots (shapes.ts).
|
|
@@ -1416,14 +1383,19 @@ export class LlEmitter {
|
|
|
1416
1383
|
? []
|
|
1417
1384
|
: [`%ScrMapRc = type { ${this.sizeType}, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr }`]),
|
|
1418
1385
|
// The complete ScrMap and its { key, val, hash } entry, read by the
|
|
1419
|
-
// inline number-key lookup (sc_map_entry_f64):
|
|
1420
|
-
//
|
|
1421
|
-
|
|
1386
|
+
// inline number-key lookup (sc_map_entry_f64): field 11 is the i64
|
|
1387
|
+
// absent-key filter, entries is field 13, the direct index and its
|
|
1388
|
+
// length fields 19 and 20.
|
|
1389
|
+
...(this.decls.has(NUMBER_MAP_ENTRY_DECL) || this.decls.has(STRING_MAP_ENTRY_DECL)
|
|
1422
1390
|
? [
|
|
1423
|
-
`%ScrMapIx = type { ${this.sizeType}, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, ptr, ${this.sizeType}, ptr, ${this.sizeType}, ptr, ptr, ptr, ${this.sizeType} }`,
|
|
1424
|
-
`%ScrMapEntry = type { i64, i64, i64 }`,
|
|
1391
|
+
`%ScrMapIx = type { ${this.sizeType}, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ${this.sizeType}, ${this.sizeType}, i64, ${this.sizeType}, ptr, ${this.sizeType}, ptr, ${this.sizeType}, ptr, ptr, ptr, ${this.sizeType} }`,
|
|
1425
1392
|
]
|
|
1426
1393
|
: []),
|
|
1394
|
+
// String-keyed reference reads load the value slot of the entry
|
|
1395
|
+
// scr_map_entry_str returns (map-number-lookup.ts).
|
|
1396
|
+
...(this.decls.has(NUMBER_MAP_ENTRY_DECL) || this.decls.has(STRING_MAP_ENTRY_DECL)
|
|
1397
|
+
? [`%ScrMapEntry = type { i64, i64, i64 }`]
|
|
1398
|
+
: []),
|
|
1427
1399
|
// The runtime error prefix { rc, vt, name, message, code, cause } and the
|
|
1428
1400
|
// class-object shape { rc, pre, post, ctor, name } — field reads on
|
|
1429
1401
|
// builtin errors and classval loads GEP through these.
|
|
@@ -1551,56 +1523,16 @@ export class LlEmitter {
|
|
|
1551
1523
|
// strings — a no-op.
|
|
1552
1524
|
const n = inst.slots.length;
|
|
1553
1525
|
const present = n === 0 ? "zeroinitializer" : `[ ${inst.slots.map(() => "i8 1").join(", ")} ]`;
|
|
1554
|
-
out.push(`@${inst.sym}_data = internal constant [${n} x ptr] [ ${inst.slots.map((s) => `ptr ${s}`).join(", ")} ]`, `@${inst.sym}_present = internal constant [${n} x i8] ${present}`, `@${inst.sym} = internal global %ScrArr { ${this.sizeType} -1, ${this.sizeType} ${n}, ${this.sizeType} ${n}, i32 2,
|
|
1526
|
+
out.push(`@${inst.sym}_data = internal constant [${n} x ptr] [ ${inst.slots.map((s) => `ptr ${s}`).join(", ")} ]`, `@${inst.sym}_present = internal constant [${n} x i8] ${present}`, `@${inst.sym} = internal global %ScrArr { ${this.sizeType} -1, ${this.sizeType} ${n}, ${this.sizeType} ${n}, i32 2, i32 0, ptr null, ptr @${inst.sym}_data, ptr @${inst.sym}_present, ptr null }`);
|
|
1555
1527
|
}
|
|
1556
1528
|
if (this.templateStringsInstances.size > 0)
|
|
1557
1529
|
out.push(``);
|
|
1558
|
-
const islandEntryPath = usesIsland ? this.cstr(this.mod.sourceFile) : null;
|
|
1559
1530
|
for (const [text, c] of this.cstrs) {
|
|
1560
1531
|
// NUL-terminated byte-array constants for scr_jb_puts and indentation.
|
|
1561
1532
|
out.push(`@${c.sym} = internal constant [${c.len + 1} x i8] c"${llStrBytes(text)}"`);
|
|
1562
1533
|
}
|
|
1563
1534
|
if (this.cstrs.size > 0)
|
|
1564
1535
|
out.push(``);
|
|
1565
|
-
if (usesIsland) {
|
|
1566
|
-
const fmt = { esm: 0, cjs: 1, json: 2 };
|
|
1567
|
-
const edgeKind = { any: 0, import: 1, require: 2 };
|
|
1568
|
-
embedded.modules.forEach((m, i) => {
|
|
1569
|
-
const stored = npmStored[i];
|
|
1570
|
-
const key = Buffer.from(m.key, "utf8");
|
|
1571
|
-
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)}"`);
|
|
1572
|
-
if (stored.esm !== null) {
|
|
1573
|
-
out.push(`@sc_npm_esm_${i} = internal constant [${stored.esm.bytes.length + 1} x i8] c"${llBytes(stored.esm.bytes)}"`);
|
|
1574
|
-
}
|
|
1575
|
-
});
|
|
1576
|
-
const moduleRows = embedded.modules.map((m, i) => {
|
|
1577
|
-
const stored = npmStored[i];
|
|
1578
|
-
const esm = stored.esm === null
|
|
1579
|
-
? `ptr null, ${this.sizeType} 0, ${this.sizeType} 0`
|
|
1580
|
-
: `ptr @sc_npm_esm_${i}, ${this.sizeType} ${stored.esm.bytes.length}, ${this.sizeType} ${stored.esm.raw}`;
|
|
1581
|
-
return (`%ScrIslandModule { ptr @sc_npm_key_${i}, ptr @sc_npm_src_${i}, ` +
|
|
1582
|
-
`${this.sizeType} ${stored.src.bytes.length}, ${this.sizeType} ${stored.src.raw}, ` +
|
|
1583
|
-
`i32 ${fmt[m.format]}, ${esm} }`);
|
|
1584
|
-
});
|
|
1585
|
-
out.push(`@sc_npm_modules = internal constant [${moduleRows.length} x %ScrIslandModule] [ ${moduleRows.join(", ")} ]`);
|
|
1586
|
-
embedded.edges.forEach((edge, i) => {
|
|
1587
|
-
const parts = [
|
|
1588
|
-
["from", edge.from],
|
|
1589
|
-
["spec", edge.specifier],
|
|
1590
|
-
["to", edge.to],
|
|
1591
|
-
];
|
|
1592
|
-
for (const [part, text] of parts) {
|
|
1593
|
-
const bytes = Buffer.from(text, "utf8");
|
|
1594
|
-
out.push(`@sc_npm_edge_${i}_${part} = internal constant [${bytes.length + 1} x i8] c"${llBytes(bytes)}"`);
|
|
1595
|
-
}
|
|
1596
|
-
});
|
|
1597
|
-
if (embedded.edges.length > 0) {
|
|
1598
|
-
const edgeRows = embedded.edges.map((edge, i) => `%ScrIslandEdge { ptr @sc_npm_edge_${i}_from, ptr @sc_npm_edge_${i}_spec, ` +
|
|
1599
|
-
`ptr @sc_npm_edge_${i}_to, i32 ${edgeKind[edge.kind]} }`);
|
|
1600
|
-
out.push(`@sc_npm_edges = internal constant [${edgeRows.length} x %ScrIslandEdge] [ ${edgeRows.join(", ")} ]`);
|
|
1601
|
-
}
|
|
1602
|
-
out.push(``);
|
|
1603
|
-
}
|
|
1604
1536
|
for (const line of ffiCallbacks.globals)
|
|
1605
1537
|
out.push(line);
|
|
1606
1538
|
if (ffiCallbacks.globals.length > 0)
|
|
@@ -1714,16 +1646,7 @@ export class LlEmitter {
|
|
|
1714
1646
|
: []),
|
|
1715
1647
|
// fs.watch programs fill the loop's watch hooks the same way —
|
|
1716
1648
|
// scr_watch.c links only when this line is emitted.
|
|
1717
|
-
...(usesFsWatch ? [` call void @scr_watch_install()`] : []), ...(this.ffiHasForeignCallback ? [` call void @scr_ffi_install()`] : []), ...(snapshotsTlsCa ? [` call void @scr_tls_ca_install()`] : []), ...(usesFetch ? [` call void @scr_fetch_install()`] : []), ...(
|
|
1718
|
-
? [
|
|
1719
|
-
` call void @scr_island_entry_module(ptr ${islandEntryPath})`,
|
|
1720
|
-
...(moduleEmbedsCompressedNpm(this.mod)
|
|
1721
|
-
? [` call void @scr_island_set_inflate(ptr @scr_zlib_inflate_exact)`]
|
|
1722
|
-
: []),
|
|
1723
|
-
` call void @scr_island_modules(ptr @sc_npm_modules, ${this.sizeType} ${embedded.modules.length}, ` +
|
|
1724
|
-
`ptr ${embedded.edges.length > 0 ? "@sc_npm_edges" : "null"}, ${this.sizeType} ${embedded.edges.length})`,
|
|
1725
|
-
]
|
|
1726
|
-
: []), ...(asyncEntry
|
|
1649
|
+
...(usesFsWatch ? [` call void @scr_watch_install()`] : []), ...(this.ffiHasForeignCallback ? [` call void @scr_ffi_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()`] : []), ...(usesDgram ? [` call void @scr_dgram_install()`] : []), ...(usesHttp2 ? [` call void @scr_http2_dyn_install()`] : []), ...(usesStream ? [` call void @scr_stream_install()`] : []), ` call void @scr_lib_init(i32 %argc, ptr %argv)`, ...(asyncEntry
|
|
1727
1650
|
? [` %top = call ptr @${mangleAsyncSpawn(this.mod.entry)}()`]
|
|
1728
1651
|
: [` call void @${mangleFunction(this.mod.entry)}()`]),
|
|
1729
1652
|
// Uncaught exception from top-level code: Node exits 1.
|
|
@@ -1810,9 +1733,7 @@ export class LlEmitter {
|
|
|
1810
1733
|
]
|
|
1811
1734
|
: []), ...exitListenerLines("xn"), ...globalReleases, ...(usesNodeTest
|
|
1812
1735
|
? [` %test_exit = call i32 @scr_test_exit_code()`, ` ret i32 %test_exit`]
|
|
1813
|
-
:
|
|
1814
|
-
? [` %island_exit = call i32 @scr_island_exit_code()`, ` ret i32 %island_exit`]
|
|
1815
|
-
: [` %native_exit = call i32 @scr_exit_code_hint_get()`, ` ret i32 %native_exit`]), `}`, ``, ...this.inlineRcTail(flushedDecls),
|
|
1736
|
+
: [` %native_exit = call i32 @scr_exit_code_hint_get()`, ` ret i32 %native_exit`]), `}`, ``, ...this.inlineRcTail(flushedDecls),
|
|
1816
1737
|
// sanitize_address is inert under the plain pipeline; the sanitized
|
|
1817
1738
|
// lane's -fsanitize=address link activates instrumentation over the
|
|
1818
1739
|
// emitted functions too (the runtime TUs get theirs from clang).
|
|
@@ -2078,11 +1999,44 @@ export class LlEmitter {
|
|
|
2078
1999
|
const sz = this.sizeType;
|
|
2079
2000
|
let mapTmp = 0;
|
|
2080
2001
|
const mapIndex = exactIndexLines("%k", "%nd", sz, () => `%ix${mapTmp++}`);
|
|
2081
|
-
defs.push(`define internal ptr @sc_map_entry_f64(ptr %m, double %k) ${FN_ATTRS} {`, `entry:`, ` %ndp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32
|
|
2002
|
+
defs.push(`define internal ptr @sc_map_entry_f64(ptr %m, double %k) ${FN_ATTRS} {`, `entry:`, ` %ndp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 20`, ` %nd = load ${sz}, ptr %ndp`,
|
|
2082
2003
|
// A non-integral key inside the table is as absent as one outside it.
|
|
2083
2004
|
...mapIndex.lines.map((line) => ` ${line}`), ` br i1 ${mapIndex.ok}, label %slot, label %outside`, `slot:`, sz === "i64"
|
|
2084
2005
|
? ` %i = add i64 ${mapIndex.wide}, 0`
|
|
2085
|
-
: ` %i = trunc i64 ${mapIndex.wide} to ${sz}`, ` %dp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32
|
|
2006
|
+
: ` %i = trunc i64 ${mapIndex.wide} to ${sz}`, ` %dp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 19`, ` %dense = load ptr, ptr %dp`, ` %sp = getelementptr inbounds i32, ptr %dense, ${sz} %i`, ` %s = load i32, ptr %sp`, ` %empty = icmp eq i32 %s, 0`, ` br i1 %empty, label %miss, label %hit`, `hit:`, ` %e32 = sub i32 %s, 1`, sz === "i32" ? ` %e = add i32 %e32, 0` : ` %e = zext i32 %e32 to ${sz}`, ` %ep = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 13`, ` %entries = load ptr, ptr %ep`, ` %found = getelementptr inbounds %ScrMapEntry, ptr %entries, ${sz} %e`, ` ret ptr %found`, `miss:`, ` ret ptr null`, `outside:`, ` %dense.any = icmp ne ${sz} %nd, 0`, ` br i1 %dense.any, label %miss, label %slow`, `slow:`, ` %r = call ptr @scr_map_entry_f64(ptr %m, double %k)`, ` ret ptr %r`, `}`, ``);
|
|
2007
|
+
}
|
|
2008
|
+
// String-key Map/Set lookups test the map's absent-key filter inline
|
|
2009
|
+
// (scr_map.c scr_map_filter_bits): a key whose two filter bits are not
|
|
2010
|
+
// both set is absent, so most misses on small and medium maps return
|
|
2011
|
+
// without a call. On 64-bit targets the key's cached hash h is the high
|
|
2012
|
+
// half of its capacity word, the runtime's widened hash is (h << 32) | h,
|
|
2013
|
+
// and the filter reads its bits 44..55, which are the capacity word's
|
|
2014
|
+
// own. A key without a cached hash, and every possible hit, take the
|
|
2015
|
+
// runtime lookup.
|
|
2016
|
+
if (this.decls.has(STRING_MAP_ENTRY_DECL)) {
|
|
2017
|
+
defs.push(`define internal ptr @sc_map_entry_str(ptr %m, ptr %k) ${FN_ATTRS} {`, `entry:`, ...(this.sizeType === "i64"
|
|
2018
|
+
? [
|
|
2019
|
+
` %fp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 11`,
|
|
2020
|
+
` %filter = load i64, ptr %fp`,
|
|
2021
|
+
` %capp = getelementptr inbounds %ScrStr, ptr %k, i32 0, i32 2`,
|
|
2022
|
+
` %cap = load i64, ptr %capp`,
|
|
2023
|
+
` %cached = icmp uge i64 %cap, 4294967296`,
|
|
2024
|
+
` br i1 %cached, label %test, label %slow`,
|
|
2025
|
+
`test:`,
|
|
2026
|
+
` %s1 = lshr i64 %cap, 44`,
|
|
2027
|
+
` %i1 = and i64 %s1, 63`,
|
|
2028
|
+
` %b1 = shl i64 1, %i1`,
|
|
2029
|
+
` %s2 = lshr i64 %cap, 50`,
|
|
2030
|
+
` %i2 = and i64 %s2, 63`,
|
|
2031
|
+
` %b2 = shl i64 1, %i2`,
|
|
2032
|
+
` %bits = or i64 %b1, %b2`,
|
|
2033
|
+
` %have = and i64 %filter, %bits`,
|
|
2034
|
+
` %maybe = icmp eq i64 %have, %bits`,
|
|
2035
|
+
` br i1 %maybe, label %slow, label %absent`,
|
|
2036
|
+
`absent:`,
|
|
2037
|
+
` ret ptr null`,
|
|
2038
|
+
]
|
|
2039
|
+
: [` br label %slow`]), `slow:`, ` %r = call ptr @scr_map_entry_str(ptr %m, ptr %k)`, ` ret ptr %r`, `}`, ``);
|
|
2086
2040
|
}
|
|
2087
2041
|
// String comparisons enter through small internal wrappers that LLVM
|
|
2088
2042
|
// inlines at each site: interned literals and shared values compare by
|
|
@@ -2261,8 +2215,8 @@ export class LlEmitter {
|
|
|
2261
2215
|
* mentions (transitively), contains no suspension entry point. Such a
|
|
2262
2216
|
* body always completes before the call returns, which is exactly the
|
|
2263
2217
|
* behavior of a fiber that never suspends. Excluded conservatively:
|
|
2264
|
-
* wasm32 (its coroutine lowering owns async bodies),
|
|
2265
|
-
*
|
|
2218
|
+
* wasm32 (its coroutine lowering owns async bodies), module-evaluation
|
|
2219
|
+
* bodies (their promise caches),
|
|
2266
2220
|
* `dyn` results (resolution may adopt a thenable), and every program
|
|
2267
2221
|
* that uses node:test subtests — `t.test()` runs a subtest inline and
|
|
2268
2222
|
* awaits it on the CURRENT fiber even from synchronous code. Worker
|
|
@@ -2275,9 +2229,6 @@ export class LlEmitter {
|
|
|
2275
2229
|
const eligible = new Set();
|
|
2276
2230
|
if (this.wasi || this.mod.workers === true)
|
|
2277
2231
|
return eligible;
|
|
2278
|
-
const embedded = this.mod.embedded;
|
|
2279
|
-
if (embedded !== undefined && embedded.modules.length > 0)
|
|
2280
|
-
return eligible;
|
|
2281
2232
|
const suspends = /@scr_(?:await_|module_await\b|promise_await_settled\b|test_sub\b|gen_yield_|async_gen_|fiber_)/;
|
|
2282
2233
|
for (const decl of this.decls)
|
|
2283
2234
|
if (/@scr_test_sub\b/.test(decl))
|
|
@@ -3280,15 +3231,6 @@ export class LlEmitter {
|
|
|
3280
3231
|
this.declare(`declare void @scr_dyn_throw(ptr)`);
|
|
3281
3232
|
B.line(`call void @scr_dyn_throw(ptr ${v.name})`);
|
|
3282
3233
|
}
|
|
3283
|
-
else if (t.kind === "jsval") {
|
|
3284
|
-
const rc = vAdapters(this.shapeHost, t);
|
|
3285
|
-
const test = "scr_jsval_is_object";
|
|
3286
|
-
this.declare(`declare zeroext i1 @${test}(ptr)`);
|
|
3287
|
-
this.declare(`declare void @scr_throw_ref_classified(ptr, ptr, ptr, ptr, i1 zeroext)`);
|
|
3288
|
-
const object = B.tmp();
|
|
3289
|
-
B.line(`${object} = call zeroext i1 @${test}(ptr ${v.name})`);
|
|
3290
|
-
B.line(`call void @scr_throw_ref_classified(ptr ${v.name}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${traceArg(this.shapeHost, t)}, i1 zeroext ${object})`);
|
|
3291
|
-
}
|
|
3292
3234
|
else {
|
|
3293
3235
|
const rc = vAdapters(this.shapeHost, t);
|
|
3294
3236
|
this.declare(`declare void @scr_throw_ref(ptr, ptr, ptr, ptr)`);
|
|
@@ -3326,7 +3268,7 @@ export class LlEmitter {
|
|
|
3326
3268
|
else if (arm.kind === "string") {
|
|
3327
3269
|
valueName = this.unionPeek(v.name, unionId);
|
|
3328
3270
|
}
|
|
3329
|
-
else if (arm.kind === "bigint" || arm.kind === "dyn"
|
|
3271
|
+
else if (arm.kind === "bigint" || arm.kind === "dyn") {
|
|
3330
3272
|
valueName = this.unionPeek(v.name, unionId);
|
|
3331
3273
|
}
|
|
3332
3274
|
const truthy = this.truthyOf(arm.kind, valueName, true);
|
|
@@ -3420,14 +3362,6 @@ export class LlEmitter {
|
|
|
3420
3362
|
B.line(`${truthy} = call zeroext i1 @scr_dyn_truthy(ptr ${valueName})`);
|
|
3421
3363
|
return truthy;
|
|
3422
3364
|
}
|
|
3423
|
-
case "jsval": {
|
|
3424
|
-
this.declare(`declare i32 @scr_jsval_truthy(ptr)`);
|
|
3425
|
-
const raw = B.tmp();
|
|
3426
|
-
const truthy = B.tmp();
|
|
3427
|
-
B.line(`${raw} = call i32 @scr_jsval_truthy(ptr ${valueName})`);
|
|
3428
|
-
B.line(`${truthy} = icmp ne i32 ${raw}, 0`);
|
|
3429
|
-
return truthy;
|
|
3430
|
-
}
|
|
3431
3365
|
default:
|
|
3432
3366
|
throw new LlvmUnsupportedError(`truthy:${unionArm ? "union:" : ""}${kind}`);
|
|
3433
3367
|
}
|
|
@@ -4086,6 +4020,7 @@ export class LlEmitter {
|
|
|
4086
4020
|
const numericFn = withInitializerBindings(fn, initializerBindings);
|
|
4087
4021
|
this.numericLocals = new Map(numericFn.locals.map((l) => [l.id, l]));
|
|
4088
4022
|
this.borrowedParameters.clear();
|
|
4023
|
+
this.referenceWrites?.enter(fn);
|
|
4089
4024
|
this.reboundOwnerSlots.clear();
|
|
4090
4025
|
this.projectedParameters.clear();
|
|
4091
4026
|
const projectedParameterIndexes = this.callLifetimes.parameters.get(fn.name);
|
|
@@ -4117,7 +4052,7 @@ export class LlEmitter {
|
|
|
4117
4052
|
this.integerArrayBindings.clear();
|
|
4118
4053
|
this.loopArrayBorrows =
|
|
4119
4054
|
this.debug === null
|
|
4120
|
-
? findLoopArrayBorrows(fn, this.callLifetimes, this.referenceEffects, this.optionalArrayReads)
|
|
4055
|
+
? findLoopArrayBorrows(fn, this.callLifetimes, this.referenceEffects, this.optionalArrayReads, this.referenceWrites)
|
|
4121
4056
|
: new Set();
|
|
4122
4057
|
this.localArrayReads = findLocalArrayReads(fn, this.fnByName, this.unionsById, this.referenceEffects.functions, this.callLifetimes, this.optionalArrayReads, this.loopArrayBorrows, this.debug === null ? this.referenceEffects : undefined);
|
|
4123
4058
|
this.callArrayReads = findCallArrayReads(fn, this.optionalArrayReads, this.referenceEffects.functions, this.callLifetimes, this.debug === null ? this.referenceEffects : undefined);
|
|
@@ -4137,6 +4072,7 @@ export class LlEmitter {
|
|
|
4137
4072
|
this.currentReturnType = fn.returnType;
|
|
4138
4073
|
this.currentGenerator = fn.generator ?? null;
|
|
4139
4074
|
this.currentBorrowedReturn = this.borrowedReturns.has(fn.name);
|
|
4075
|
+
this.inConstructor = this.constructorFunctions.has(fn.name);
|
|
4140
4076
|
this.currentWasiCoro = null;
|
|
4141
4077
|
this.logArgSlots = 0;
|
|
4142
4078
|
if (this.wasi && (fn.async === true || fn.generator !== undefined)) {
|
|
@@ -4297,7 +4233,7 @@ export class LlEmitter {
|
|
|
4297
4233
|
this.emitStackCheck();
|
|
4298
4234
|
if (this.workerEntryPolls?.has(fn.name))
|
|
4299
4235
|
this.emitPendingCheck(undefined, true);
|
|
4300
|
-
this.emitStmts(fn.body);
|
|
4236
|
+
this.emitStmts(fn.body, true);
|
|
4301
4237
|
// Implicit exit of a void function: release the function scope unless
|
|
4302
4238
|
// the body already terminated its final block (return, or a throw
|
|
4303
4239
|
// whose unwind released everything down to depth 0).
|
|
@@ -4363,7 +4299,14 @@ export class LlEmitter {
|
|
|
4363
4299
|
if (fn.captures !== undefined)
|
|
4364
4300
|
params.unshift("ptr %sc_env");
|
|
4365
4301
|
const ret = this.llType(fn.returnType);
|
|
4366
|
-
|
|
4302
|
+
let attrs = coro !== null ? "#1" : FN_ATTRS;
|
|
4303
|
+
// The shared indexed-read helper (lowerSafeIndexRead) is a dense bounds
|
|
4304
|
+
// test, a state test and a load behind cold runtime fallbacks, called
|
|
4305
|
+
// from every `a[i]` of one element type. Without the hint LLVM keeps the
|
|
4306
|
+
// hot instances out of line once they have many callers: every read pays
|
|
4307
|
+
// a call, and an integer index converts to a double and back across it.
|
|
4308
|
+
if (fn.name.startsWith("%arr.idxOr."))
|
|
4309
|
+
attrs = `inlinehint ${attrs}`;
|
|
4367
4310
|
const debug = this.debugScope === null ? "" : ` !dbg ${this.debugScope}`;
|
|
4368
4311
|
const symbol = borrowed ? mangleBorrowedFunction(fn.name) : mangleFunction(fn.name);
|
|
4369
4312
|
const body = `define internal ${ret} @${symbol}(${params.join(", ")}) ${attrs}${debug} { ; ${fn.name}\n${B.render()}\n}`;
|
|
@@ -4460,6 +4403,10 @@ export class LlEmitter {
|
|
|
4460
4403
|
this.canBorrowReceiver(value.else_) &&
|
|
4461
4404
|
this.canBorrowCallArgument(value.then) &&
|
|
4462
4405
|
this.canBorrowCallArgument(value.else_));
|
|
4406
|
+
// A construction-only field of a stable owner keeps its value until the
|
|
4407
|
+
// owner dies: no later operand or callee can replace and release it.
|
|
4408
|
+
if ((value.kind === "fieldGet" || value.kind === "recordGet") && this.immutableRead(value))
|
|
4409
|
+
return this.canBorrowCallArgument(value.obj);
|
|
4463
4410
|
// An optional chain's bound receiver stays unchanged until its body
|
|
4464
4411
|
// finishes (see emitReadReceiver).
|
|
4465
4412
|
if (value.kind === "chainRecv")
|
|
@@ -4467,6 +4414,9 @@ export class LlEmitter {
|
|
|
4467
4414
|
if (value.kind !== "varRef")
|
|
4468
4415
|
return false;
|
|
4469
4416
|
const binding = this.binding(value.localId);
|
|
4417
|
+
// A module constant owns its value for the rest of the program.
|
|
4418
|
+
if (binding.kind === "global")
|
|
4419
|
+
return this.stableGlobals.has(value.localId);
|
|
4470
4420
|
return (binding.kind === "local" &&
|
|
4471
4421
|
binding.local !== undefined &&
|
|
4472
4422
|
(!binding.local.mutable ||
|
|
@@ -4476,15 +4426,212 @@ export class LlEmitter {
|
|
|
4476
4426
|
!binding.local.boxed &&
|
|
4477
4427
|
!binding.local.tdz);
|
|
4478
4428
|
}
|
|
4429
|
+
/** A plain-pointer read of a construction-only field outside any
|
|
4430
|
+
* constructor (ImmutableFields). */
|
|
4431
|
+
immutableRead(e) {
|
|
4432
|
+
if (this.inConstructor || this.immutableFields === null)
|
|
4433
|
+
return false;
|
|
4434
|
+
const t = e.type.kind;
|
|
4435
|
+
if (t !== "object" && t !== "record" && t !== "array" && t !== "string")
|
|
4436
|
+
return false;
|
|
4437
|
+
return e.kind === "fieldGet"
|
|
4438
|
+
? this.immutableFields.classField(e.className, e.field)
|
|
4439
|
+
: this.immutableFields.recordField(e.shapeId, e.field);
|
|
4440
|
+
}
|
|
4441
|
+
/** A projection read whose locations nothing writes while a borrowed
|
|
4442
|
+
* read of it is in use (ReferenceWrites), given the writes of that
|
|
4443
|
+
* extent. The root binding itself must stay alive across it too, which
|
|
4444
|
+
* its own location (`l:`, `g:`, `bx`) covers. */
|
|
4445
|
+
unwrittenRead(e, writes) {
|
|
4446
|
+
const rw = this.referenceWrites;
|
|
4447
|
+
if (rw === null)
|
|
4448
|
+
return false;
|
|
4449
|
+
const keys = rw.readKeys(e, (call) => this.borrowedReturnKeys(call.callee));
|
|
4450
|
+
return keys !== null && !rw.conflicts(keys, writes);
|
|
4451
|
+
}
|
|
4452
|
+
/** A stable binding initialized by a projection can borrow it when the
|
|
4453
|
+
* rest of its block (its whole lifetime) writes none of the projection's
|
|
4454
|
+
* locations: the source edge then keeps the value alive, and uses that
|
|
4455
|
+
* escape still retain their own copies. */
|
|
4456
|
+
unwrittenAlias(s) {
|
|
4457
|
+
const cursor = this.stmtCursor;
|
|
4458
|
+
const rw = this.referenceWrites;
|
|
4459
|
+
if (rw === null || s.init === null || cursor === null || cursor.stmts[cursor.index] !== s)
|
|
4460
|
+
return false;
|
|
4461
|
+
if (!this.plainReference(s.init.type) ||
|
|
4462
|
+
!this.canBorrowReceiver(s.init) ||
|
|
4463
|
+
!this.unownedWalk(s.init))
|
|
4464
|
+
return false;
|
|
4465
|
+
const writes = rw.union([rw.expr(s.init), rw.stmts(cursor.stmts.slice(cursor.index + 1))]);
|
|
4466
|
+
return this.unwrittenRead(s.init, writes);
|
|
4467
|
+
}
|
|
4468
|
+
/** An optional element read into a projection-only local can borrow the
|
|
4469
|
+
* element when the rest of the block writes no array element and none of
|
|
4470
|
+
* the locations keeping the array alive (which must itself be read
|
|
4471
|
+
* without a frame owner). */
|
|
4472
|
+
unwrittenLocalArrayRead(s, read) {
|
|
4473
|
+
const cursor = this.stmtCursor;
|
|
4474
|
+
const rw = this.referenceWrites;
|
|
4475
|
+
if (rw === null || s.init === null || cursor === null || cursor.stmts[cursor.index] !== s)
|
|
4476
|
+
return false;
|
|
4477
|
+
if (!this.unownedWalk(read.array))
|
|
4478
|
+
return false;
|
|
4479
|
+
const keys = rw.readKeys(read.array);
|
|
4480
|
+
if (keys === null || rw.expr(read.index) !== null)
|
|
4481
|
+
return false;
|
|
4482
|
+
const writes = rw.union([rw.expr(s.init), rw.stmts(cursor.stmts.slice(cursor.index + 1))]);
|
|
4483
|
+
return !rw.conflicts(["a", ...keys], writes);
|
|
4484
|
+
}
|
|
4485
|
+
/** An optional element read passed to a projection-only parameter can
|
|
4486
|
+
* borrow the element when the callee and later arguments (`writes`)
|
|
4487
|
+
* write no array element and nothing keeping the array alive. */
|
|
4488
|
+
unwrittenCallArrayRead(read, writes) {
|
|
4489
|
+
const rw = this.referenceWrites;
|
|
4490
|
+
if (rw === null)
|
|
4491
|
+
return false;
|
|
4492
|
+
const keys = rw.readKeys(read.array);
|
|
4493
|
+
if (keys === null || rw.expr(read.index) !== null)
|
|
4494
|
+
return false;
|
|
4495
|
+
return !rw.conflicts(["a", ...keys], writes);
|
|
4496
|
+
}
|
|
4497
|
+
/** `return x` of a local whose slot is an owned scope entry of the same
|
|
4498
|
+
* type: the return can take over the local's reference. */
|
|
4499
|
+
movableReturn(value) {
|
|
4500
|
+
if (value === null || value.kind !== "varRef" || !isRefCounted(value.type))
|
|
4501
|
+
return null;
|
|
4502
|
+
if (this.currentBorrowedReturn || this.currentWasiCoro !== null)
|
|
4503
|
+
return null;
|
|
4504
|
+
const binding = this.binding(value.localId);
|
|
4505
|
+
if (binding.kind !== "local" || binding.local === undefined || binding.local.boxed)
|
|
4506
|
+
return null;
|
|
4507
|
+
if (!typeEquals(binding.type, value.type) || !typeEquals(this.currentReturnType, value.type))
|
|
4508
|
+
return null;
|
|
4509
|
+
for (const scope of this.scopes) {
|
|
4510
|
+
const index = scope.findIndex((entry) => entry.slot === binding.slot);
|
|
4511
|
+
if (index < 0)
|
|
4512
|
+
continue;
|
|
4513
|
+
const entry = scope[index];
|
|
4514
|
+
if (entry.boxed || entry.lazy || !typeEquals(entry.type, value.type))
|
|
4515
|
+
return null;
|
|
4516
|
+
return { scope, entry, index };
|
|
4517
|
+
}
|
|
4518
|
+
return null;
|
|
4519
|
+
}
|
|
4520
|
+
/** A walk host for a body that may write the heap: each walk must read
|
|
4521
|
+
* only locations the whole body (with its callees) never writes;
|
|
4522
|
+
* rebinding the walk locals themselves releases nothing. */
|
|
4523
|
+
unwrittenWalkHost(fn, host) {
|
|
4524
|
+
return {
|
|
4525
|
+
...host,
|
|
4526
|
+
unwritten: (value, candidates) => this.referenceWrites?.unwrittenWalk(fn, value, candidates, (call) => this.borrowedReturnKeys(call.callee)) ?? false,
|
|
4527
|
+
};
|
|
4528
|
+
}
|
|
4529
|
+
/** emitReadReceiver yields a plain pointer for `e` that no statement
|
|
4530
|
+
* frame owns, so it can outlive the statement (walk-borrows' walks, from
|
|
4531
|
+
* any unboxed plain-pointer binding, plus element reads). */
|
|
4532
|
+
unownedWalk(e) {
|
|
4533
|
+
switch (e.kind) {
|
|
4534
|
+
case "varRef": {
|
|
4535
|
+
const binding = this.binding(e.localId);
|
|
4536
|
+
if (binding.kind === "global")
|
|
4537
|
+
return this.plainReference(binding.type);
|
|
4538
|
+
return (binding.kind === "local" &&
|
|
4539
|
+
binding.local !== undefined &&
|
|
4540
|
+
!binding.local.boxed &&
|
|
4541
|
+
!binding.local.tdz &&
|
|
4542
|
+
this.plainReference(binding.local.type) &&
|
|
4543
|
+
!this.stringSlices.has(e.localId) &&
|
|
4544
|
+
!this.storedSplits.has(e.localId) &&
|
|
4545
|
+
!this.localUnionStorage.has(e.localId));
|
|
4546
|
+
}
|
|
4547
|
+
case "fieldGet":
|
|
4548
|
+
case "recordGet":
|
|
4549
|
+
return this.borrowsWithoutOwning(e) && this.unownedWalk(e.obj);
|
|
4550
|
+
case "unionNarrow":
|
|
4551
|
+
case "downcast":
|
|
4552
|
+
case "upcast":
|
|
4553
|
+
return this.borrowsWithoutOwning(e) && this.unownedWalk(e.value);
|
|
4554
|
+
case "unionWrap":
|
|
4555
|
+
if (!this.borrowsWithoutOwning(e))
|
|
4556
|
+
return false;
|
|
4557
|
+
return e.value.kind === "unitLit" || this.unownedWalk(e.value);
|
|
4558
|
+
case "ternary": {
|
|
4559
|
+
const arm = (v) => (v.kind === "libCall" && v.fn === "error.nodeThrow") || this.unownedWalk(v);
|
|
4560
|
+
return this.borrowsWithoutOwning(e) && arm(e.then) && arm(e.else_);
|
|
4561
|
+
}
|
|
4562
|
+
case "call":
|
|
4563
|
+
return (this.borrowsWithoutOwning(e) &&
|
|
4564
|
+
e.args.every((arg) => !isRefCounted(arg.type) || this.unownedWalk(arg)));
|
|
4565
|
+
case "arrayGet":
|
|
4566
|
+
return (!this.isStackUnionSource(e) &&
|
|
4567
|
+
this.optionalArrayReads.get(e) === null &&
|
|
4568
|
+
this.unownedWalk(e.arr));
|
|
4569
|
+
case "seqExpr": {
|
|
4570
|
+
const guarded = guardedValue(e);
|
|
4571
|
+
return guarded !== null && this.unownedWalk(guarded);
|
|
4572
|
+
}
|
|
4573
|
+
default:
|
|
4574
|
+
return false;
|
|
4575
|
+
}
|
|
4576
|
+
}
|
|
4577
|
+
/** Every location a borrowed-return callee's walks can read (its body's
|
|
4578
|
+
* field, record and element reads, through nested borrowed returns). */
|
|
4579
|
+
borrowedReturnKeys(callee) {
|
|
4580
|
+
if (!this.borrowedReturns.has(callee))
|
|
4581
|
+
return null;
|
|
4582
|
+
const known = this.borrowedReturnKeyCache.get(callee);
|
|
4583
|
+
if (known)
|
|
4584
|
+
return known;
|
|
4585
|
+
const rw = this.referenceWrites;
|
|
4586
|
+
const keys = new Set();
|
|
4587
|
+
const seen = new Set([callee]);
|
|
4588
|
+
const pending = [callee];
|
|
4589
|
+
while (pending.length > 0) {
|
|
4590
|
+
const fn = this.fnByName.get(pending.pop());
|
|
4591
|
+
if (!fn)
|
|
4592
|
+
continue;
|
|
4593
|
+
everyStmtList(fn.body, {
|
|
4594
|
+
stmt: () => true,
|
|
4595
|
+
expr: (e) => {
|
|
4596
|
+
if (e.kind === "fieldGet")
|
|
4597
|
+
keys.add(rw.fieldKey(e.className, e.field));
|
|
4598
|
+
else if (e.kind === "recordGet") {
|
|
4599
|
+
keys.add(`r:${e.field}`);
|
|
4600
|
+
keys.add("r:*");
|
|
4601
|
+
}
|
|
4602
|
+
else if (e.kind === "arrayGet")
|
|
4603
|
+
keys.add("a");
|
|
4604
|
+
else if (e.kind === "call" && this.borrowedReturns.has(e.callee) && !seen.has(e.callee)) {
|
|
4605
|
+
seen.add(e.callee);
|
|
4606
|
+
pending.push(e.callee);
|
|
4607
|
+
}
|
|
4608
|
+
return true;
|
|
4609
|
+
},
|
|
4610
|
+
});
|
|
4611
|
+
}
|
|
4612
|
+
const result = [...keys];
|
|
4613
|
+
this.borrowedReturnKeyCache.set(callee, result);
|
|
4614
|
+
return result;
|
|
4615
|
+
}
|
|
4479
4616
|
// ── statements ──────────────────────────────────────────────────────────
|
|
4480
|
-
emitStmts(stmts) {
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
return
|
|
4487
|
-
|
|
4617
|
+
emitStmts(stmts, scoped = false) {
|
|
4618
|
+
const saved = this.stmtCursor;
|
|
4619
|
+
const cursor = scoped ? { stmts, index: 0 } : null;
|
|
4620
|
+
try {
|
|
4621
|
+
for (let i = 0; i < stmts.length; i++) {
|
|
4622
|
+
// Statements after a terminator are unreachable (dead code after
|
|
4623
|
+
// return/break/continue). Skip them so no dropped SSA definition
|
|
4624
|
+
// can leak forward.
|
|
4625
|
+
if (this.B.isTerminated())
|
|
4626
|
+
return;
|
|
4627
|
+
if (cursor)
|
|
4628
|
+
cursor.index = i;
|
|
4629
|
+
this.stmtCursor = cursor;
|
|
4630
|
+
this.emitStmt(stmts[i]);
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
finally {
|
|
4634
|
+
this.stmtCursor = saved;
|
|
4488
4635
|
}
|
|
4489
4636
|
}
|
|
4490
4637
|
/** Emits a block in its own lexical scope (refcounted locals released at
|
|
@@ -4496,7 +4643,7 @@ export class LlEmitter {
|
|
|
4496
4643
|
const scope = [];
|
|
4497
4644
|
this.scopes.push(scope);
|
|
4498
4645
|
setup?.(scope);
|
|
4499
|
-
this.emitStmts(stmts);
|
|
4646
|
+
this.emitStmts(stmts, true);
|
|
4500
4647
|
const ended = endsWithJump(stmts);
|
|
4501
4648
|
this.scopes.pop();
|
|
4502
4649
|
if (!ended)
|
|
@@ -4558,7 +4705,9 @@ export class LlEmitter {
|
|
|
4558
4705
|
}
|
|
4559
4706
|
const localRead = this.localArrayReads.get(s.localId);
|
|
4560
4707
|
if (localRead) {
|
|
4561
|
-
const owner = emitLocalArrayRead(this, localRead,
|
|
4708
|
+
const owner = emitLocalArrayRead(this, !localRead.borrow && this.unwrittenLocalArrayRead(s, localRead)
|
|
4709
|
+
? { ...localRead, borrow: true }
|
|
4710
|
+
: localRead, b.slot);
|
|
4562
4711
|
if (owner)
|
|
4563
4712
|
this.scopes[this.scopes.length - 1].push(owner);
|
|
4564
4713
|
break;
|
|
@@ -4652,7 +4801,7 @@ export class LlEmitter {
|
|
|
4652
4801
|
b.local &&
|
|
4653
4802
|
isRefCounted(b.type) &&
|
|
4654
4803
|
this.stableCallBindings.has(s.localId) &&
|
|
4655
|
-
this.canBorrowCallArgument(s.init)) {
|
|
4804
|
+
(this.canBorrowCallArgument(s.init) || this.unwrittenAlias(s))) {
|
|
4656
4805
|
const v = this.emitReadReceiver(s.init);
|
|
4657
4806
|
B.line(`store ptr ${v.name}, ptr ${b.slot}`);
|
|
4658
4807
|
break;
|
|
@@ -4719,6 +4868,32 @@ export class LlEmitter {
|
|
|
4719
4868
|
}
|
|
4720
4869
|
B.line(`store ${this.llType(b.type)} ${v.name}, ptr ${b.slot}`);
|
|
4721
4870
|
this.storeIntegerView(s.localId, v, s.value);
|
|
4871
|
+
if (b.kind === "global" && this.immortalGlobals.has(s.localId)) {
|
|
4872
|
+
// An Immutable module constant (contracts/check.ts proved it is
|
|
4873
|
+
// fresh, publishable and never written): its graph becomes
|
|
4874
|
+
// immortal, so reads skip reference counting and the collector
|
|
4875
|
+
// never visits it.
|
|
4876
|
+
const lines = this.publishWalkers.emitPublish(v.name, v.type, s.loc);
|
|
4877
|
+
for (const line of lines)
|
|
4878
|
+
B.line(line.trimStart());
|
|
4879
|
+
// Reads of this global skip retains from here on, which is only
|
|
4880
|
+
// sound once the graph really is immortal. Node.js never fails
|
|
4881
|
+
// here, so a refusal means the contract proof was wrong: stop
|
|
4882
|
+
// rather than keep running with a mortal graph read as immortal.
|
|
4883
|
+
if (lines.length > 0) {
|
|
4884
|
+
this.declare(`declare zeroext i1 @scr_exc_pending()`);
|
|
4885
|
+
this.declare(`declare void @scr_trap(ptr)`);
|
|
4886
|
+
const refused = B.tmp();
|
|
4887
|
+
B.line(`${refused} = call zeroext i1 @scr_exc_pending()`);
|
|
4888
|
+
const stop = B.newLabel("immutable.refused");
|
|
4889
|
+
const done = B.newLabel("immutable.published");
|
|
4890
|
+
B.condBr(refused, stop, done);
|
|
4891
|
+
B.startBlock(stop);
|
|
4892
|
+
B.line(`call void @scr_trap(ptr ${this.cstr("scriptc: internal error: an Immutable value could not be published\n")})`);
|
|
4893
|
+
B.terminate("unreachable");
|
|
4894
|
+
B.startBlock(done);
|
|
4895
|
+
}
|
|
4896
|
+
}
|
|
4722
4897
|
break;
|
|
4723
4898
|
}
|
|
4724
4899
|
case "exprStmt":
|
|
@@ -4816,14 +4991,14 @@ export class LlEmitter {
|
|
|
4816
4991
|
const obj = this.emitStableReceiver(s.obj, [s.value]);
|
|
4817
4992
|
// (The guard precedes the value here: the nullable store
|
|
4818
4993
|
// evaluates it itself.)
|
|
4819
|
-
this.
|
|
4994
|
+
this.emitStoreGuard(obj.name, s);
|
|
4820
4995
|
this.emitNullableFieldStore(obj.name, s.className, s.field, nullable, s.value);
|
|
4821
4996
|
break;
|
|
4822
4997
|
}
|
|
4823
4998
|
if (s.kind === "fieldSet" && this.int32Slots.isField(s.className, s.field)) {
|
|
4824
4999
|
const obj = this.emitStableReceiver(s.obj, [s.value]);
|
|
4825
5000
|
const v = this.emitExpr(s.value);
|
|
4826
|
-
this.
|
|
5001
|
+
this.emitStoreGuard(obj.name, s);
|
|
4827
5002
|
const { ptr } = this.classFieldPtr(obj.name, s.className, s.field);
|
|
4828
5003
|
this.storeInt32Field(ptr, v, s.value);
|
|
4829
5004
|
break;
|
|
@@ -4831,7 +5006,7 @@ export class LlEmitter {
|
|
|
4831
5006
|
const obj = this.emitStableReceiver(s.obj, [s.value]);
|
|
4832
5007
|
const v = this.emitExpr(s.value);
|
|
4833
5008
|
if (s.kind === "fieldSet")
|
|
4834
|
-
this.
|
|
5009
|
+
this.emitStoreGuard(obj.name, s);
|
|
4835
5010
|
else if (this.publishedTypes?.recordGuarded(s.shapeId) === true)
|
|
4836
5011
|
this.emitPublishedFieldGuard(obj.name, null, s.field);
|
|
4837
5012
|
const { ptr, type } = s.kind === "fieldSet"
|
|
@@ -5194,7 +5369,11 @@ export class LlEmitter {
|
|
|
5194
5369
|
if (integerArrayLoop && s.init?.kind === "varDecl" && s.init.init) {
|
|
5195
5370
|
const value = this.emitExpr(s.init.init);
|
|
5196
5371
|
start = B.tmp();
|
|
5197
|
-
|
|
5372
|
+
// The start is 0 or an enclosing array index plus one (at most
|
|
5373
|
+
// 2^32 - 1): on 64-bit targets the signed conversion is exact
|
|
5374
|
+
// and avoids x86-64's unsigned 64-bit conversion sequence.
|
|
5375
|
+
const conversion = this.sizeType === "i64" ? "fptosi" : "fptoui";
|
|
5376
|
+
B.line(`${start} = ${conversion} double ${value.name} to ${this.sizeType}`);
|
|
5198
5377
|
this.integerArrayBindings.add(integerLoop.localId);
|
|
5199
5378
|
}
|
|
5200
5379
|
B.line(`store ${this.sizeType} ${start}, ptr ${integerSlot}`);
|
|
@@ -5500,10 +5679,32 @@ export class LlEmitter {
|
|
|
5500
5679
|
// the actual ret. The parked value owns a synthetic slot-backed
|
|
5501
5680
|
// scope entry during each copy so a throwing finally releases it.
|
|
5502
5681
|
let v = null;
|
|
5503
|
-
|
|
5682
|
+
const moved = this.finallyStack.length === 0 ? this.movableReturn(s.value) : null;
|
|
5683
|
+
if (moved !== null) {
|
|
5684
|
+
// Returning an owned local hands its reference to the caller: no
|
|
5685
|
+
// retain now and no release of the local below.
|
|
5686
|
+
const t = B.tmp();
|
|
5687
|
+
B.line(`${t} = load ptr, ptr ${moved.entry.slot}`);
|
|
5688
|
+
v = { name: t, type: s.value.type };
|
|
5689
|
+
moved.scope.splice(moved.scope.indexOf(moved.entry), 1);
|
|
5690
|
+
this.releaseForJump(0, 0);
|
|
5691
|
+
moved.scope.splice(moved.index, 0, moved.entry);
|
|
5692
|
+
}
|
|
5693
|
+
else if (s.value !== null && this.currentBorrowedReturn) {
|
|
5504
5694
|
// A borrowed-return body hands back its walk without a reference
|
|
5505
|
-
// (it has no try statements, so no finally can intervene).
|
|
5506
|
-
|
|
5695
|
+
// (it has no try statements, so no finally can intervene). An
|
|
5696
|
+
// optional element read lends the element its array keeps alive.
|
|
5697
|
+
const read = this.optionalArrayReads.get(s.value);
|
|
5698
|
+
if (read) {
|
|
5699
|
+
const slot = B.slot();
|
|
5700
|
+
B.entryAllocas.push(`${slot} = alloca ptr`);
|
|
5701
|
+
emitLocalArrayRead(this, { ...read, borrow: true }, slot);
|
|
5702
|
+
const t = B.tmp();
|
|
5703
|
+
B.line(`${t} = load ptr, ptr ${slot}`);
|
|
5704
|
+
v = { name: t, type: s.value.type };
|
|
5705
|
+
}
|
|
5706
|
+
else
|
|
5707
|
+
v = this.emitReadReceiver(s.value);
|
|
5507
5708
|
}
|
|
5508
5709
|
else if (s.value !== null) {
|
|
5509
5710
|
v = this.emitExpr(s.value);
|
|
@@ -5540,7 +5741,7 @@ export class LlEmitter {
|
|
|
5540
5741
|
this.finallyStack = savedFinally;
|
|
5541
5742
|
this.tryStack = savedTry;
|
|
5542
5743
|
}
|
|
5543
|
-
else {
|
|
5744
|
+
else if (moved === null) {
|
|
5544
5745
|
this.releaseForJump(0, 0);
|
|
5545
5746
|
}
|
|
5546
5747
|
if (!B.isTerminated()) {
|
|
@@ -5798,7 +5999,7 @@ export class LlEmitter {
|
|
|
5798
5999
|
const caseLabels = s.cases.map(() => B.newLabel("sw.c"));
|
|
5799
6000
|
const defaultIdx = s.cases.findIndex((c) => c.test === null);
|
|
5800
6001
|
const fallback = defaultIdx >= 0 ? caseLabels[defaultIdx] : end;
|
|
5801
|
-
if (!emitLiteralSwitch(this, disc, s.cases, caseLabels, fallback)) {
|
|
6002
|
+
if (!emitLiteralSwitch(this, disc, s.disc, s.cases, caseLabels, fallback)) {
|
|
5802
6003
|
s.cases.forEach((c, i) => {
|
|
5803
6004
|
if (c.test === null)
|
|
5804
6005
|
return;
|
|
@@ -6134,6 +6335,13 @@ export class LlEmitter {
|
|
|
6134
6335
|
``,
|
|
6135
6336
|
];
|
|
6136
6337
|
}
|
|
6338
|
+
/** The frozen-object guard of a class field store, unless the store
|
|
6339
|
+
* provably targets a still-private `this` (PublishedTypes.privateStores). */
|
|
6340
|
+
emitStoreGuard(obj, s) {
|
|
6341
|
+
if (this.publishedTypes?.privateStores.has(s) === true)
|
|
6342
|
+
return;
|
|
6343
|
+
this.emitPublishedFieldGuard(obj, s.className, s.field);
|
|
6344
|
+
}
|
|
6137
6345
|
/** The frozen-object guard of a class field or record field store:
|
|
6138
6346
|
* Node's "Cannot assign to read only property" TypeError when the target
|
|
6139
6347
|
* is published. `className` null means a record (`#<Object>`). */
|
|
@@ -6200,9 +6408,6 @@ export class LlEmitter {
|
|
|
6200
6408
|
emitAsyncExpr(e) {
|
|
6201
6409
|
return emitAsyncExpr(this, e);
|
|
6202
6410
|
}
|
|
6203
|
-
emitJsInteropExpr(e) {
|
|
6204
|
-
return emitJsInteropExpr(this, e);
|
|
6205
|
-
}
|
|
6206
6411
|
/** Read a receiver whose value is consumed immediately by a field or tag
|
|
6207
6412
|
* load. No user code may run between this read and its consumer. Locals
|
|
6208
6413
|
* and their projections already have an owner; other expressions keep
|
|
@@ -6273,6 +6478,10 @@ export class LlEmitter {
|
|
|
6273
6478
|
this.ownSlot(result.owner.slot, result.owner.type);
|
|
6274
6479
|
return result.value;
|
|
6275
6480
|
}
|
|
6481
|
+
// A borrowed-return helper (such as an optional element read) lends its
|
|
6482
|
+
// result like any borrowed-return call.
|
|
6483
|
+
if (e.kind === "call" && this.borrowedReturns.has(e.callee) && this.canBorrowReceiver(e))
|
|
6484
|
+
return emitBorrowedResultCall(this, e);
|
|
6276
6485
|
const arrayRead = this.optionalArrayReads.get(e);
|
|
6277
6486
|
if (arrayRead)
|
|
6278
6487
|
return emitProjectedArrayRead(this, arrayRead);
|
|
@@ -6518,12 +6727,24 @@ export class LlEmitter {
|
|
|
6518
6727
|
const wrap = this.borrowableNullableWrap(e);
|
|
6519
6728
|
return wrap === "unit" || (wrap === "ref" && this.canBorrowReceiver(e.value));
|
|
6520
6729
|
}
|
|
6521
|
-
// A borrowed-return
|
|
6522
|
-
//
|
|
6523
|
-
|
|
6524
|
-
|
|
6525
|
-
|
|
6526
|
-
|
|
6730
|
+
// A borrowed-return result stays reachable from its borrowed
|
|
6731
|
+
// arguments until the consumer runs. Each argument is lent without a
|
|
6732
|
+
// snapshot, so neither the callee nor a later argument may replace
|
|
6733
|
+
// what it was read from: a callee that preserves every edge cannot,
|
|
6734
|
+
// and any other one must leave the argument's locations unwritten.
|
|
6735
|
+
case "call": {
|
|
6736
|
+
if (!this.borrowedReturns.has(e.callee))
|
|
6737
|
+
return false;
|
|
6738
|
+
if (!e.args.every((arg) => this.referenceEffects.preserves(arg)))
|
|
6739
|
+
return false;
|
|
6740
|
+
const preserving = this.referenceEffects.functions.has(e.callee);
|
|
6741
|
+
if (preserving)
|
|
6742
|
+
return e.args.every((arg) => !isRefCounted(arg.type) || this.canBorrowReceiver(arg));
|
|
6743
|
+
if (this.referenceWrites === null)
|
|
6744
|
+
return false;
|
|
6745
|
+
const lent = borrowableInputs(this, e.args, false, this.referenceWrites.summary(e.callee));
|
|
6746
|
+
return e.args.every((arg, i) => !isRefCounted(arg.type) || lent[i] === true);
|
|
6747
|
+
}
|
|
6527
6748
|
// A required element read: the (borrowed) array owns the element
|
|
6528
6749
|
// while an edge-preserving index computes.
|
|
6529
6750
|
case "arrayGet":
|
|
@@ -6569,14 +6790,17 @@ export class LlEmitter {
|
|
|
6569
6790
|
};
|
|
6570
6791
|
const hostFor = (fn) => {
|
|
6571
6792
|
const allowed = borrowedIds(fn);
|
|
6572
|
-
|
|
6793
|
+
const host = {
|
|
6573
6794
|
pointerLocal: (local) => pointer(local.type),
|
|
6574
6795
|
borrowsWithoutOwning: (e) => this.borrowsWithoutOwning(e),
|
|
6575
6796
|
borrowedReturn: (callee) => this.borrowedReturns.has(callee),
|
|
6576
6797
|
parameterAllowed: (id) => allowed.has(id),
|
|
6577
6798
|
};
|
|
6799
|
+
return this.referenceEffects.functions.has(fn.name) ? host : this.unwrittenWalkHost(fn, host);
|
|
6578
6800
|
};
|
|
6579
|
-
|
|
6801
|
+
// With ReferenceWrites, a body that writes none of its walks' locations
|
|
6802
|
+
// qualifies like one that preserves every edge.
|
|
6803
|
+
const preserving = [...this.fnByName.values()].filter((fn) => this.referenceEffects.functions.has(fn.name) || this.referenceWrites !== null);
|
|
6580
6804
|
const candidates = preserving.filter((fn) => {
|
|
6581
6805
|
if (!pointer(fn.returnType) || fn.async || fn.generator || fn.captures)
|
|
6582
6806
|
return false;
|
|
@@ -6597,6 +6821,8 @@ export class LlEmitter {
|
|
|
6597
6821
|
if (!analyzeWalks(fn, hostFor(fn)).returnsWalk)
|
|
6598
6822
|
continue;
|
|
6599
6823
|
this.borrowedReturns.add(fn.name);
|
|
6824
|
+
// Nested borrowed returns extend the locations a caller depends on.
|
|
6825
|
+
this.borrowedReturnKeyCache.clear();
|
|
6600
6826
|
changed = true;
|
|
6601
6827
|
}
|
|
6602
6828
|
}
|
|
@@ -6624,6 +6850,12 @@ export class LlEmitter {
|
|
|
6624
6850
|
return this.nullableFieldGet(e) === null;
|
|
6625
6851
|
case "recordGet":
|
|
6626
6852
|
return true;
|
|
6853
|
+
// emitReadReceiver lends a required element of a borrowed array when
|
|
6854
|
+
// computing the index removes no edge.
|
|
6855
|
+
case "arrayGet":
|
|
6856
|
+
return (e.arr.type.kind === "array" &&
|
|
6857
|
+
this.optionalArrayReads.get(e) === null &&
|
|
6858
|
+
this.referenceEffects.preserves(e.index));
|
|
6627
6859
|
case "unionNarrow":
|
|
6628
6860
|
return this.nullableUnions.has(e.unionId);
|
|
6629
6861
|
case "downcast":
|
|
@@ -6665,21 +6897,6 @@ export class LlEmitter {
|
|
|
6665
6897
|
emitExpr(e) {
|
|
6666
6898
|
return emitExpr(this, e);
|
|
6667
6899
|
}
|
|
6668
|
-
emitJsMarshal(e) {
|
|
6669
|
-
return emitJsMarshal(this, e);
|
|
6670
|
-
}
|
|
6671
|
-
emitJsOp(e) {
|
|
6672
|
-
return emitJsOp(this, e);
|
|
6673
|
-
}
|
|
6674
|
-
emitJsExit(e) {
|
|
6675
|
-
return emitJsExit(this, e);
|
|
6676
|
-
}
|
|
6677
|
-
islandAdapter(arity, retKind) {
|
|
6678
|
-
return islandAdapter(this, arity, retKind);
|
|
6679
|
-
}
|
|
6680
|
-
islandTypedAdapter(fn) {
|
|
6681
|
-
return islandTypedAdapter(this, fn);
|
|
6682
|
-
}
|
|
6683
6900
|
dynKind(d) {
|
|
6684
6901
|
return dynKind(this, d);
|
|
6685
6902
|
}
|