@scriptc/compiler 0.4.2 → 0.4.3
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 +397 -37
- package/dist/backend/cycle-analysis.d.ts +4 -1
- package/dist/backend/cycle-analysis.js +6 -4
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +55 -0
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/cycle-mutability.d.ts +7 -0
- package/dist/backend/cycle-mutability.js +19 -1
- package/dist/backend/cycle-mutability.js.map +1 -1
- package/dist/backend/executable-features.js +2 -0
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/immutability.d.ts +6 -3
- package/dist/backend/immutability.js +33 -29
- package/dist/backend/immutability.js.map +1 -1
- package/dist/backend/library-pack.js +1 -0
- package/dist/backend/library-pack.js.map +1 -1
- package/dist/backend/llvm/alloc.d.ts +16 -1
- package/dist/backend/llvm/alloc.js +54 -4
- package/dist/backend/llvm/alloc.js.map +1 -1
- package/dist/backend/llvm/appended-array-literals.d.ts +2 -1
- package/dist/backend/llvm/appended-array-literals.js +44 -36
- package/dist/backend/llvm/appended-array-literals.js.map +1 -1
- package/dist/backend/llvm/appended-array-literals.test.js +4 -3
- package/dist/backend/llvm/appended-array-literals.test.js.map +1 -1
- package/dist/backend/llvm/array-search.d.ts +4 -3
- package/dist/backend/llvm/array-search.js +21 -9
- package/dist/backend/llvm/array-search.js.map +1 -1
- package/dist/backend/llvm/blocks.d.ts +1 -1
- package/dist/backend/llvm/blocks.js +2 -2
- package/dist/backend/llvm/blocks.js.map +1 -1
- package/dist/backend/llvm/byte-windows.js +2 -0
- package/dist/backend/llvm/byte-windows.js.map +1 -1
- package/dist/backend/llvm/bytes-alias.d.ts +6 -1
- package/dist/backend/llvm/bytes-alias.js +8 -2
- package/dist/backend/llvm/bytes-alias.js.map +1 -1
- package/dist/backend/llvm/bytes-loop-versions.d.ts +47 -5
- package/dist/backend/llvm/bytes-loop-versions.js +473 -32
- package/dist/backend/llvm/bytes-loop-versions.js.map +1 -1
- package/dist/backend/llvm/bytes-loop-versions.test.js +258 -2
- package/dist/backend/llvm/bytes-loop-versions.test.js.map +1 -1
- package/dist/backend/llvm/checked-value-lifetimes.js +2 -0
- package/dist/backend/llvm/checked-value-lifetimes.js.map +1 -1
- package/dist/backend/llvm/classes.d.ts +7 -5
- package/dist/backend/llvm/classes.js +44 -20
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +167 -7
- package/dist/backend/llvm/classes.test.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +9 -3
- package/dist/backend/llvm/common.js +9 -3
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.d.ts +2 -1
- package/dist/backend/llvm/constant-callbacks.js +83 -52
- package/dist/backend/llvm/constant-callbacks.js.map +1 -1
- package/dist/backend/llvm/counted-loops.d.ts +7 -0
- package/dist/backend/llvm/counted-loops.js +18 -0
- package/dist/backend/llvm/counted-loops.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.d.ts +39 -8
- package/dist/backend/llvm/dense-array-access.js +222 -52
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.test.js +36 -0
- package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
- package/dist/backend/llvm/dense-array-loops.d.ts +17 -1
- package/dist/backend/llvm/dense-array-loops.js +194 -5
- package/dist/backend/llvm/dense-array-loops.js.map +1 -1
- package/dist/backend/llvm/dense-array-loops.test.js +90 -1
- package/dist/backend/llvm/dense-array-loops.test.js.map +1 -1
- package/dist/backend/llvm/dyn-handle-tags.test.js +6 -1
- package/dist/backend/llvm/dyn-handle-tags.test.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +26 -0
- package/dist/backend/llvm/dyn.js +352 -61
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emit-function.js +11 -20
- package/dist/backend/llvm/emit-function.js.map +1 -1
- package/dist/backend/llvm/emit-journal.d.ts +93 -0
- package/dist/backend/llvm/emit-journal.js +170 -0
- package/dist/backend/llvm/emit-journal.js.map +1 -0
- package/dist/backend/llvm/emit-module.js +195 -27
- package/dist/backend/llvm/emit-module.js.map +1 -1
- package/dist/backend/llvm/emit-statements.d.ts +0 -4
- package/dist/backend/llvm/emit-statements.js +268 -84
- package/dist/backend/llvm/emit-statements.js.map +1 -1
- package/dist/backend/llvm/emitter-state.d.ts +7 -0
- package/dist/backend/llvm/emitter-state.js +14 -0
- package/dist/backend/llvm/emitter-state.js.map +1 -0
- package/dist/backend/llvm/emitter.d.ts +176 -37
- package/dist/backend/llvm/emitter.js +724 -85
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +54 -5
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.js +34 -12
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-callbacks.js +47 -0
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-calls.js +28 -14
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.d.ts +14 -2
- package/dist/backend/llvm/expr-containers.js +129 -37
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-context.d.ts +14 -0
- package/dist/backend/llvm/expr-dynamic.js +18 -11
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +100 -28
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.test.js +11 -6
- package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
- package/dist/backend/llvm/expr-records.d.ts +12 -0
- package/dist/backend/llvm/expr-records.js +106 -0
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.d.ts +2 -2
- package/dist/backend/llvm/expr-stream-bridges.js +194 -65
- 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/expr-stream-bridges.test.js.map +1 -1
- package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
- package/dist/backend/llvm/expr-stream-callbacks.js +74 -20
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/int32-kind-loops.d.ts +39 -0
- package/dist/backend/llvm/int32-kind-loops.js +106 -0
- package/dist/backend/llvm/int32-kind-loops.js.map +1 -0
- package/dist/backend/llvm/integer-or-nan-indexes.test.d.ts +1 -0
- package/dist/backend/llvm/integer-or-nan-indexes.test.js +118 -0
- package/dist/backend/llvm/integer-or-nan-indexes.test.js.map +1 -0
- package/dist/backend/llvm/integer-values.d.ts +20 -1
- package/dist/backend/llvm/integer-values.js +71 -0
- package/dist/backend/llvm/integer-values.js.map +1 -1
- package/dist/backend/llvm/js-ic.d.ts +1 -1
- package/dist/backend/llvm/js-ic.js +1 -1
- package/dist/backend/llvm/js-ic.js.map +1 -1
- package/dist/backend/llvm/key-orders.d.ts +7 -0
- package/dist/backend/llvm/key-orders.js +33 -0
- package/dist/backend/llvm/key-orders.js.map +1 -0
- package/dist/backend/llvm/lib-connect.js +4 -0
- package/dist/backend/llvm/lib-connect.js.map +1 -1
- package/dist/backend/llvm/lib-datagram.js +11 -0
- package/dist/backend/llvm/lib-datagram.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +80 -2
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +4 -4
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-http2.js +4 -0
- package/dist/backend/llvm/lib-http2.js.map +1 -1
- package/dist/backend/llvm/lib-lookup.js +16 -6
- package/dist/backend/llvm/lib-lookup.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +73 -2
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-stream.js +35 -5
- package/dist/backend/llvm/lib-stream.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +115 -19
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.test.js +14 -0
- package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
- package/dist/backend/llvm/loop-state.d.ts +33 -0
- package/dist/backend/llvm/loop-state.js +42 -0
- package/dist/backend/llvm/loop-state.js.map +1 -0
- package/dist/backend/llvm/map-number-lookup.d.ts +26 -8
- package/dist/backend/llvm/map-number-lookup.js +91 -31
- package/dist/backend/llvm/map-number-lookup.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.test.js +55 -0
- package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.js +4 -2
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/nullable-unions.d.ts +2 -1
- package/dist/backend/llvm/nullable-unions.js +15 -3
- package/dist/backend/llvm/nullable-unions.js.map +1 -1
- package/dist/backend/llvm/publish.d.ts +10 -0
- package/dist/backend/llvm/publish.js +12 -0
- package/dist/backend/llvm/publish.js.map +1 -1
- package/dist/backend/llvm/receivers.js +6 -1
- package/dist/backend/llvm/receivers.js.map +1 -1
- package/dist/backend/llvm/record-results.d.ts +1 -9
- package/dist/backend/llvm/record-results.js +2 -11
- package/dist/backend/llvm/record-results.js.map +1 -1
- package/dist/backend/llvm/reference-writes.d.ts +7 -2
- package/dist/backend/llvm/reference-writes.js +89 -72
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/running-extrema.d.ts +11 -0
- package/dist/backend/llvm/running-extrema.js +115 -0
- package/dist/backend/llvm/running-extrema.js.map +1 -0
- package/dist/backend/llvm/running-extrema.test.d.ts +1 -0
- package/dist/backend/llvm/running-extrema.test.js +89 -0
- package/dist/backend/llvm/running-extrema.test.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +71 -15
- package/dist/backend/llvm/shapes.js +222 -33
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +53 -7
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/speculative-integers.d.ts +6 -0
- package/dist/backend/llvm/speculative-integers.js +2 -2
- package/dist/backend/llvm/speculative-integers.js.map +1 -1
- package/dist/backend/llvm/stack-objects.d.ts +3 -2
- package/dist/backend/llvm/stack-objects.js +5 -2
- package/dist/backend/llvm/stack-objects.js.map +1 -1
- package/dist/backend/llvm/string-reads.d.ts +12 -0
- package/dist/backend/llvm/string-reads.js +44 -0
- package/dist/backend/llvm/string-reads.js.map +1 -1
- package/dist/backend/llvm/walk-borrows.d.ts +3 -0
- package/dist/backend/llvm/walk-borrows.js +46 -41
- package/dist/backend/llvm/walk-borrows.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +3 -0
- package/dist/backend/llvm/walkers.js +88 -65
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/llvm/wrapping-sums.d.ts +16 -1
- package/dist/backend/llvm/wrapping-sums.js +126 -0
- package/dist/backend/llvm/wrapping-sums.js.map +1 -1
- package/dist/backend/may-throw.d.ts +8 -10
- package/dist/backend/may-throw.js +14 -10
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +5 -0
- package/dist/backend/native/executable.js +7 -0
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +1 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +4 -0
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/publication.d.ts +12 -1
- package/dist/backend/publication.js +37 -14
- package/dist/backend/publication.js.map +1 -1
- package/dist/backend/publication.test.js +30 -0
- package/dist/backend/publication.test.js.map +1 -1
- package/dist/backend/result-slots.d.ts +16 -0
- package/dist/backend/result-slots.js +23 -0
- package/dist/backend/result-slots.js.map +1 -0
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-core.d.ts +1 -0
- package/dist/backend/runtime-pack-core.js +1 -0
- package/dist/backend/runtime-pack-core.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +2 -1
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +2 -1
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/stack-observations.d.ts +2 -1
- package/dist/backend/stack-observations.js +67 -42
- package/dist/backend/stack-observations.js.map +1 -1
- package/dist/backend/target-diagnostics.js +5 -3
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/warm-cache.js +1 -0
- package/dist/backend/warm-cache.js.map +1 -1
- package/dist/cli/usage.d.ts +1 -1
- package/dist/cli/usage.js +3 -3
- package/dist/compat/fetch-profile.js +1 -1
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/contracts/check.js +4 -3
- package/dist/contracts/check.js.map +1 -1
- package/dist/contracts/int32-elements.js +10 -2
- package/dist/contracts/int32-elements.js.map +1 -1
- package/dist/coverage/report.js +12 -3
- package/dist/coverage/report.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +4 -0
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/envelope.d.ts +3 -0
- package/dist/diagnostics/envelope.js +1 -0
- package/dist/diagnostics/envelope.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +2 -0
- package/dist/executable/executable-cache.js +1 -0
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +1 -0
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/frontend/decl-projection.d.ts +41 -0
- package/dist/frontend/decl-projection.js +854 -0
- package/dist/frontend/decl-projection.js.map +1 -0
- package/dist/frontend/decl-projection.test.d.ts +1 -0
- package/dist/frontend/decl-projection.test.js +30 -0
- package/dist/frontend/decl-projection.test.js.map +1 -0
- package/dist/frontend/dts-paths.d.ts +15 -0
- package/dist/frontend/dts-paths.js +25 -0
- package/dist/frontend/dts-paths.js.map +1 -1
- package/dist/frontend/input-tracker.d.ts +6 -0
- package/dist/frontend/input-tracker.js +51 -28
- package/dist/frontend/input-tracker.js.map +1 -1
- package/dist/frontend/input-tracker.test.js +19 -0
- package/dist/frontend/input-tracker.test.js.map +1 -1
- package/dist/frontend/lowering/array-values.js +100 -2
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process-methods.js +46 -15
- package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process.js +13 -2
- package/dist/frontend/lowering/builtins/child-process.js.map +1 -1
- package/dist/frontend/lowering/builtins/crypto.js +84 -9
- package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
- package/dist/frontend/lowering/builtins/global-namespace-keys.d.ts +3 -0
- package/dist/frontend/lowering/builtins/global-namespace-keys.js +122 -0
- package/dist/frontend/lowering/builtins/global-namespace-keys.js.map +1 -0
- package/dist/frontend/lowering/builtins/numbers.js +9 -1
- package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
- package/dist/frontend/lowering/builtins/promises.d.ts +6 -0
- package/dist/frontend/lowering/builtins/promises.js +88 -2
- package/dist/frontend/lowering/builtins/promises.js.map +1 -1
- package/dist/frontend/lowering/builtins/readline.d.ts +5 -1
- package/dist/frontend/lowering/builtins/readline.js +35 -3
- package/dist/frontend/lowering/builtins/readline.js.map +1 -1
- package/dist/frontend/lowering/builtins/url.js +24 -1
- package/dist/frontend/lowering/builtins/url.js.map +1 -1
- package/dist/frontend/lowering/builtins/webassembly.js +6 -3
- package/dist/frontend/lowering/builtins/webassembly.js.map +1 -1
- package/dist/frontend/lowering/class-callbacks.d.ts +5 -2
- package/dist/frontend/lowering/class-callbacks.js +82 -12
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-construction.d.ts +4 -1
- package/dist/frontend/lowering/class-construction.js +17 -3
- package/dist/frontend/lowering/class-construction.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +39 -2
- package/dist/frontend/lowering/class-dynamic-dispatch.js +766 -108
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +47 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
- package/dist/frontend/lowering/class-iterables.d.ts +2 -1
- package/dist/frontend/lowering/class-iterables.js +9 -1
- package/dist/frontend/lowering/class-iterables.js.map +1 -1
- package/dist/frontend/lowering/class-method-mutations.js +32 -9
- package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
- package/dist/frontend/lowering/class-prototypes.js +31 -2
- package/dist/frontend/lowering/class-prototypes.js.map +1 -1
- package/dist/frontend/lowering/class-runtime-statics.d.ts +9 -3
- package/dist/frontend/lowering/class-runtime-statics.js +29 -4
- package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural-plans.js +48 -1
- package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural.js +91 -1
- package/dist/frontend/lowering/coercions/structural.js.map +1 -1
- package/dist/frontend/lowering/containers/array-callback-call.js +2 -2
- package/dist/frontend/lowering/containers/array-callback-call.js.map +1 -1
- package/dist/frontend/lowering/containers/array-callbacks.js +338 -18
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-concat.js +10 -0
- package/dist/frontend/lowering/containers/array-concat.js.map +1 -1
- package/dist/frontend/lowering/containers/array-methods.js +15 -0
- package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/array-pipelines.js +19 -8
- package/dist/frontend/lowering/containers/array-pipelines.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +2 -1
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/callback-arguments.js +3 -0
- package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +7 -2
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/filter-predicates.d.ts +6 -0
- package/dist/frontend/lowering/containers/filter-predicates.js +205 -0
- package/dist/frontend/lowering/containers/filter-predicates.js.map +1 -0
- package/dist/frontend/lowering/containers/indexed-objects.d.ts +0 -12
- package/dist/frontend/lowering/containers/indexed-objects.js +46 -7
- package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +55 -9
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/containers/string-replacement.js +43 -19
- package/dist/frontend/lowering/containers/string-replacement.js.map +1 -1
- package/dist/frontend/lowering/dispatch-sites.js +15 -1
- package/dist/frontend/lowering/dispatch-sites.js.map +1 -1
- package/dist/frontend/lowering/divergences.js +9 -1
- package/dist/frontend/lowering/divergences.js.map +1 -1
- package/dist/frontend/lowering/error-methods.js +47 -2
- package/dist/frontend/lowering/error-methods.js.map +1 -1
- package/dist/frontend/lowering/expressions/array-literals.js +47 -0
- package/dist/frontend/lowering/expressions/array-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/binary.js +36 -2
- package/dist/frontend/lowering/expressions/binary.js.map +1 -1
- package/dist/frontend/lowering/expressions/element-access.js +90 -13
- package/dist/frontend/lowering/expressions/element-access.js.map +1 -1
- package/dist/frontend/lowering/expressions/identifiers.js +33 -4
- package/dist/frontend/lowering/expressions/identifiers.js.map +1 -1
- package/dist/frontend/lowering/expressions/narrowing.js +95 -1
- package/dist/frontend/lowering/expressions/narrowing.js.map +1 -1
- package/dist/frontend/lowering/expressions/nullish-assignment.js +3 -1
- package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.d.ts +10 -0
- package/dist/frontend/lowering/expressions/object-literals.js +138 -51
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.js +12 -0
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/expressions/property-access.js +113 -11
- package/dist/frontend/lowering/expressions/property-access.js.map +1 -1
- package/dist/frontend/lowering/expressions/relational.js +212 -33
- package/dist/frontend/lowering/expressions/relational.js.map +1 -1
- package/dist/frontend/lowering/expressions/union-fields.js +4 -0
- package/dist/frontend/lowering/expressions/union-fields.js.map +1 -1
- package/dist/frontend/lowering/expressions/updates.js +22 -3
- package/dist/frontend/lowering/expressions/updates.js.map +1 -1
- package/dist/frontend/lowering/frozen-records.d.ts +28 -0
- package/dist/frontend/lowering/frozen-records.js +322 -0
- package/dist/frontend/lowering/frozen-records.js.map +1 -0
- package/dist/frontend/lowering/function-returns.js +49 -0
- package/dist/frontend/lowering/function-returns.js.map +1 -1
- package/dist/frontend/lowering/generic-functions.js +7 -2
- package/dist/frontend/lowering/generic-functions.js.map +1 -1
- package/dist/frontend/lowering/iterable-values.d.ts +49 -0
- package/dist/frontend/lowering/iterable-values.js +297 -0
- package/dist/frontend/lowering/iterable-values.js.map +1 -0
- package/dist/frontend/lowering/iterator-adapters.js +186 -1
- package/dist/frontend/lowering/iterator-adapters.js.map +1 -1
- package/dist/frontend/lowering/js-class-fields.d.ts +8 -0
- package/dist/frontend/lowering/js-class-fields.js +45 -10
- package/dist/frontend/lowering/js-class-fields.js.map +1 -1
- package/dist/frontend/lowering/key-order-witness.d.ts +18 -3
- package/dist/frontend/lowering/key-order-witness.js +770 -22
- package/dist/frontend/lowering/key-order-witness.js.map +1 -1
- package/dist/frontend/lowering/key-order-witness.test.js +428 -8
- package/dist/frontend/lowering/key-order-witness.test.js.map +1 -1
- package/dist/frontend/lowering/lower-async-iteration.js +4 -1
- package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +7 -0
- package/dist/frontend/lowering/lower-calls.js +443 -41
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +11 -2
- package/dist/frontend/lowering/lower-classes.js +302 -22
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +3 -1
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +10 -2
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-functions.d.ts +11 -0
- package/dist/frontend/lowering/lower-functions.js +83 -0
- package/dist/frontend/lowering/lower-functions.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.js +41 -31
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-global-value.js +6 -3
- package/dist/frontend/lowering/lower-global-value.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +18 -6
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +32 -0
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.js +5 -1
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.js +2 -2
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stdlib.d.ts +5 -0
- package/dist/frontend/lowering/lower-stdlib.js +30 -0
- package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +23 -0
- package/dist/frontend/lowering/lower-stmts.js +454 -48
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +20 -2
- package/dist/frontend/lowering/lower-stream.js +1483 -156
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +77 -6
- package/dist/frontend/lowering/lowerer.js +313 -29
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/module-namespace-elements.d.ts +11 -1
- package/dist/frontend/lowering/module-namespace-elements.js +82 -5
- package/dist/frontend/lowering/module-namespace-elements.js.map +1 -1
- package/dist/frontend/lowering/new-target.d.ts +12 -0
- package/dist/frontend/lowering/new-target.js +280 -0
- package/dist/frontend/lowering/new-target.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +3 -0
- package/dist/frontend/lowering/surfaces.js +18 -6
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/undefined-index.d.ts +27 -0
- package/dist/frontend/lowering/undefined-index.js +82 -0
- package/dist/frontend/lowering/undefined-index.js.map +1 -0
- package/dist/frontend/lowering/var-hoisting.js +29 -13
- package/dist/frontend/lowering/var-hoisting.js.map +1 -1
- package/dist/frontend/lowering/width-lift.d.ts +18 -0
- package/dist/frontend/npm-static-bundled-chunks.js +9 -11
- package/dist/frontend/npm-static-bundled-chunks.js.map +1 -1
- package/dist/frontend/npm-static-bundled-chunks.test.js +6 -5
- package/dist/frontend/npm-static-bundled-chunks.test.js.map +1 -1
- package/dist/frontend/npm-static-rewrite-syntax.js +9 -1
- package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
- package/dist/frontend/npm-static.js +4 -20
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/package-shims.d.ts +3 -0
- package/dist/frontend/package-shims.js +71 -8
- package/dist/frontend/package-shims.js.map +1 -1
- package/dist/frontend/pipeline.js +18 -10
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/process-fork.d.ts +25 -0
- package/dist/frontend/process-fork.js +2 -0
- package/dist/frontend/process-fork.js.map +1 -0
- package/dist/frontend/program.d.ts +8 -1
- package/dist/frontend/program.js +484 -69
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +43 -3
- package/dist/frontend/program.test.js.map +1 -1
- package/dist/frontend/token-equivalence.d.ts +3 -0
- package/dist/frontend/token-equivalence.js +409 -0
- package/dist/frontend/token-equivalence.js.map +1 -0
- package/dist/frontend/token-equivalence.test.d.ts +1 -0
- package/dist/frontend/token-equivalence.test.js +67 -0
- package/dist/frontend/token-equivalence.test.js.map +1 -0
- package/dist/frontend/ts7/ast-node.d.ts +22 -0
- package/dist/frontend/ts7/ast-node.js +1048 -103
- package/dist/frontend/ts7/ast-node.js.map +1 -1
- package/dist/frontend/ts7/ast-node.test.js +24 -0
- package/dist/frontend/ts7/ast-node.test.js.map +1 -1
- package/dist/frontend/ts7/ast-wire.d.ts +4 -3
- package/dist/frontend/ts7/ast-wire.js +34 -24
- package/dist/frontend/ts7/ast-wire.js.map +1 -1
- package/dist/frontend/ts7/ast-wire.test.js +23 -0
- package/dist/frontend/ts7/ast-wire.test.js.map +1 -1
- package/dist/frontend/ts7/checker-backend.d.ts +3 -4
- package/dist/frontend/ts7/checker-backend.js +2 -2
- package/dist/frontend/ts7/checker-backend.js.map +1 -1
- package/dist/frontend/ts7/checker-backend.test.js +5 -9
- package/dist/frontend/ts7/checker-backend.test.js.map +1 -1
- package/dist/frontend/ts7/checker.d.ts +4 -0
- package/dist/frontend/ts7/checker.js +7 -0
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/lib-diagnostics.d.ts +24 -0
- package/dist/frontend/ts7/lib-diagnostics.js +307 -0
- package/dist/frontend/ts7/lib-diagnostics.js.map +1 -0
- package/dist/frontend/ts7/lib-diagnostics.test.d.ts +1 -0
- package/dist/frontend/ts7/lib-diagnostics.test.js +199 -0
- package/dist/frontend/ts7/lib-diagnostics.test.js.map +1 -0
- package/dist/frontend/ts7/program-host.d.ts +7 -0
- package/dist/frontend/ts7/program-host.js +25 -2
- package/dist/frontend/ts7/program-host.js.map +1 -1
- package/dist/frontend/ts7/session.d.ts +14 -1
- package/dist/frontend/ts7/session.js +22 -0
- package/dist/frontend/ts7/session.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +13 -1
- package/dist/frontend/type-mapper.js +191 -11
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.d.ts +0 -5
- package/dist/index.js +34 -4
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.js +5 -3
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/array-length-stability.d.ts +4 -0
- package/dist/ir/array-length-stability.js +19 -6
- package/dist/ir/array-length-stability.js.map +1 -1
- package/dist/ir/array-length-stability.test.js +24 -0
- package/dist/ir/array-length-stability.test.js.map +1 -1
- package/dist/ir/builtin-effects.d.ts +7 -0
- package/dist/ir/builtin-effects.js +52 -0
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +6 -4
- package/dist/ir/builtin-signatures.js +166 -13
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/callback-specialization.d.ts +2 -1
- package/dist/ir/callback-specialization.js +23 -18
- package/dist/ir/callback-specialization.js.map +1 -1
- package/dist/ir/char-unit-locals.d.ts +19 -0
- package/dist/ir/char-unit-locals.js +185 -0
- package/dist/ir/char-unit-locals.js.map +1 -0
- package/dist/ir/char-unit-locals.test.d.ts +1 -0
- package/dist/ir/char-unit-locals.test.js +94 -0
- package/dist/ir/char-unit-locals.test.js.map +1 -0
- package/dist/ir/final-fields.d.ts +2 -1
- package/dist/ir/final-fields.js +14 -16
- package/dist/ir/final-fields.js.map +1 -1
- package/dist/ir/function-references.d.ts +2 -0
- package/dist/ir/function-references.js +2 -0
- package/dist/ir/function-references.js.map +1 -1
- package/dist/ir/function-references.test.js +3 -0
- package/dist/ir/function-references.test.js.map +1 -1
- package/dist/ir/initializer-bindings.d.ts +2 -1
- package/dist/ir/initializer-bindings.js +27 -20
- package/dist/ir/initializer-bindings.js.map +1 -1
- package/dist/ir/int32-arrays.d.ts +108 -0
- package/dist/ir/int32-arrays.js +831 -0
- package/dist/ir/int32-arrays.js.map +1 -0
- package/dist/ir/int32-slots.d.ts +24 -2
- package/dist/ir/int32-slots.js +259 -57
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/integer-loops.d.ts +3 -3
- package/dist/ir/integer-loops.js +14 -6
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-loops.test.js +10 -0
- package/dist/ir/integer-loops.test.js.map +1 -1
- package/dist/ir/integer-ranges.d.ts +5 -0
- package/dist/ir/integer-ranges.js +125 -12
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/integer-ranges.test.js +30 -0
- package/dist/ir/integer-ranges.test.js.map +1 -1
- package/dist/ir/ir.d.ts +70 -7
- package/dist/ir/ir.js +58 -1
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +21 -1
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/js-ic.d.ts +19 -2
- package/dist/ir/js-ic.js +95 -11
- package/dist/ir/js-ic.js.map +1 -1
- package/dist/ir/js-ic.test.js +188 -0
- package/dist/ir/js-ic.test.js.map +1 -1
- package/dist/ir/node-index.d.ts +57 -0
- package/dist/ir/node-index.js +215 -0
- package/dist/ir/node-index.js.map +1 -0
- package/dist/ir/paired-while-loops.d.ts +25 -0
- package/dist/ir/paired-while-loops.js +335 -0
- package/dist/ir/paired-while-loops.js.map +1 -0
- package/dist/ir/paired-while-loops.test.d.ts +1 -0
- package/dist/ir/paired-while-loops.test.js +163 -0
- package/dist/ir/paired-while-loops.test.js.map +1 -0
- package/dist/ir/parameter-versions.d.ts +25 -0
- package/dist/ir/parameter-versions.js +300 -0
- package/dist/ir/parameter-versions.js.map +1 -0
- package/dist/ir/runtime-features.d.ts +34 -13
- package/dist/ir/runtime-features.js +152 -38
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/serialize.d.ts +12 -2
- package/dist/ir/serialize.js +16 -3
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +17 -0
- package/dist/ir/serialize.test.js.map +1 -1
- package/dist/ir/traverse.js +18 -6
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +122 -36
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/ir-policy.js +2 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/dist/native/cache.d.ts +6 -1
- package/dist/native/cache.js +28 -5
- package/dist/native/cache.js.map +1 -1
- package/dist/native/cache.test.js +16 -2
- package/dist/native/cache.test.js.map +1 -1
- package/dist/native/cli.js +21 -1
- package/dist/native/cli.js.map +1 -1
- package/dist/native/compiler.js +8 -6
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/executable-cache.d.ts +1 -1
- package/dist/native/executable-cache.js +2 -2
- package/dist/native/executable-cache.js.map +1 -1
- package/dist/native/prepare.d.ts +3 -1
- package/dist/native/prepare.js +119 -31
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/prepare.test.js +78 -18
- package/dist/native/prepare.test.js.map +1 -1
- package/dist/native/sanitizer.test.js +2 -0
- package/dist/native/sanitizer.test.js.map +1 -1
- package/dist/native/text-file.d.ts +13 -3
- package/dist/native/text-file.js +63 -9
- package/dist/native/text-file.js.map +1 -1
- package/dist/native/text-file.test.d.ts +1 -0
- package/dist/native/text-file.test.js +49 -0
- package/dist/native/text-file.test.js.map +1 -0
- package/dist/native/toolchain.js +4 -4
- package/dist/native/toolchain.js.map +1 -1
- package/dist/native/toolchain.test.js +3 -3
- package/dist/native/toolchain.test.js.map +1 -1
- package/package.json +21 -21
- package/shims/chalk/v5.ts +688 -0
- package/shims/hono-node-server/v2.ts +645 -0
- package/shims/hot-shots/client.ts +1126 -0
- package/shims/hot-shots/v8-unix-dgram.ts +8 -0
- package/shims/hot-shots/v8.ts +8 -0
- package/surface-manifest.json +26 -4
|
@@ -1,11 +1,13 @@
|
|
|
1
|
+
import { F64 } from "../../ir/ir.js";
|
|
1
2
|
import { byteNumberAccess } from "../../ir/byte-numbers.js";
|
|
2
3
|
import { everyExprChild, everyStmtChild } from "../../ir/traverse.js";
|
|
3
4
|
import { exactInteger, widenInteger } from "./integer-values.js";
|
|
4
|
-
import { emitCountedLoopLimit, emitCountedLoopSafety } from "./counted-loops.js";
|
|
5
|
+
import { emitCountedLoopLimit, emitCountedLoopSafety, emitExactIntegerTest, } from "./counted-loops.js";
|
|
5
6
|
import { emitBytesHeaderLength, emitBytesSharedStorage } from "./expr-bytes.js";
|
|
6
7
|
import { f64Lit } from "./common.js";
|
|
8
|
+
import { emitStringAsciiFlag, emitStringByteLength } from "./string-reads.js";
|
|
7
9
|
const MAX_COST = 400;
|
|
8
|
-
const MAX_FIXED_END = 2 **
|
|
10
|
+
const MAX_FIXED_END = 2 ** 31;
|
|
9
11
|
const MAX_CHECKS = 8;
|
|
10
12
|
const MAX_OFFSET = 2 ** 31;
|
|
11
13
|
const SAFE = Number.MAX_SAFE_INTEGER;
|
|
@@ -27,6 +29,14 @@ const INVARIANT_OPS = new Set(["+", "-", "*", "&", "|", "^", "<<", ">>", ">>>"])
|
|
|
27
29
|
* such as `base` for `const base = r * cols`, must also be an exact
|
|
28
30
|
* integer between -2^32 and 2^32, which the guard tests.
|
|
29
31
|
*
|
|
32
|
+
* `s.charCodeAt(index)` and `s.charAt(index)` (so `s[index]`) of a string
|
|
33
|
+
* binding qualify the same way. A string is immutable: its bytes, its
|
|
34
|
+
* length and the capacity-word bit that proves it ASCII (string-reads.ts)
|
|
35
|
+
* are fixed when it is built. The guard also requires that bit, so each
|
|
36
|
+
* UTF-16 unit is one byte and the length is the byte length. The fast copy
|
|
37
|
+
* reads each unit with one byte load, and each character as the immortal
|
|
38
|
+
* one-character string for its byte.
|
|
39
|
+
*
|
|
30
40
|
* In worker programs, every access of a view that may be shared tests its
|
|
31
41
|
* shared storage. A view's storage is also fixed at construction, so the
|
|
32
42
|
* same guard tests each invariant receiver once, and the fast copy reads
|
|
@@ -36,7 +46,7 @@ const INVARIANT_OPS = new Set(["+", "-", "*", "&", "|", "^", "<<", ">>", ">>>"])
|
|
|
36
46
|
* the emitter bounds how deeply versions nest. The checked loop runs
|
|
37
47
|
* whenever the guard fails, and keeps every out-of-bounds read, ignored
|
|
38
48
|
* write and NaN-index behavior. */
|
|
39
|
-
export function matchBytesLoopVersion(loop, counted, facts) {
|
|
49
|
+
export function matchBytesLoopVersion(loop, counted, facts, paired = null) {
|
|
40
50
|
const written = new Set();
|
|
41
51
|
const temps = new Map();
|
|
42
52
|
let cost = 0;
|
|
@@ -77,10 +87,10 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
77
87
|
// The guard runs before the initializer, so a binding the initializer
|
|
78
88
|
// writes is not invariant either: `for (let i = (a = b, 0); ...)` must
|
|
79
89
|
// not keep the bounds the guard proved for the old `a`.
|
|
80
|
-
if ((loop.init !== null && !scanStmt(loop.init)) ||
|
|
90
|
+
if ((loop.kind === "for" && loop.init !== null && !scanStmt(loop.init)) ||
|
|
81
91
|
!loop.body.every(scanStmt) ||
|
|
82
92
|
(loop.cond !== null && !scanExpr(loop.cond)) ||
|
|
83
|
-
(loop.update !== null && !scanStmt(loop.update)))
|
|
93
|
+
(loop.kind === "for" && loop.update !== null && !scanStmt(loop.update)))
|
|
84
94
|
return null;
|
|
85
95
|
// A body temp stands for its initializer only when it is a constant
|
|
86
96
|
// binding assigned exactly once, by that declaration.
|
|
@@ -117,7 +127,9 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
117
127
|
};
|
|
118
128
|
const resolving = new Set();
|
|
119
129
|
const root = (e) => {
|
|
120
|
-
if (e.kind !== "varRef" || e.type.kind !== "bytes")
|
|
130
|
+
if (e.kind !== "varRef" || (e.type.kind !== "bytes" && e.type.kind !== "string"))
|
|
131
|
+
return null;
|
|
132
|
+
if (facts.scalarStrings.has(e.localId))
|
|
121
133
|
return null;
|
|
122
134
|
const init = temp(e.localId);
|
|
123
135
|
if (init) {
|
|
@@ -254,6 +266,39 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
254
266
|
const r = termRange(t.expr);
|
|
255
267
|
return sum + Math.max(Math.abs(r.min), Math.abs(r.max));
|
|
256
268
|
}, 0);
|
|
269
|
+
const whileAccesses = loop.kind === "while" ? whileCounterAccesses(loop) : null;
|
|
270
|
+
function whileCounterAccesses(loop) {
|
|
271
|
+
return findWhileCounterAccesses(loop, {
|
|
272
|
+
counterLocal: (id) => {
|
|
273
|
+
const local = facts.locals.get(id);
|
|
274
|
+
return (local?.type.kind === "f64" &&
|
|
275
|
+
!local.boxed &&
|
|
276
|
+
!local.tdz &&
|
|
277
|
+
!facts.captured.has(id) &&
|
|
278
|
+
facts.initialized.has(id));
|
|
279
|
+
},
|
|
280
|
+
boundKey: (e) => {
|
|
281
|
+
if (e.type.kind !== "f64")
|
|
282
|
+
return null;
|
|
283
|
+
// The guard evaluates the bound before the loop: a typed array's
|
|
284
|
+
// length needs the binding itself, not a temp the body declares.
|
|
285
|
+
if (e.kind === "bytesIntrinsic" &&
|
|
286
|
+
e.method === "length" &&
|
|
287
|
+
e.receiver.kind === "varRef" &&
|
|
288
|
+
e.receiver.type.kind === "bytes" &&
|
|
289
|
+
invariant(e.receiver.localId))
|
|
290
|
+
return `bytes-length:${e.receiver.localId}`;
|
|
291
|
+
if (e.kind === "strIntrinsic" &&
|
|
292
|
+
e.method === "length" &&
|
|
293
|
+
e.args.length === 0 &&
|
|
294
|
+
e.receiver.kind === "varRef" &&
|
|
295
|
+
e.receiver.type.kind === "string" &&
|
|
296
|
+
invariant(e.receiver.localId))
|
|
297
|
+
return `string-length:${e.receiver.localId}`;
|
|
298
|
+
return pureKey(e);
|
|
299
|
+
},
|
|
300
|
+
});
|
|
301
|
+
}
|
|
257
302
|
const receivers = [];
|
|
258
303
|
const receiverIndex = new Map();
|
|
259
304
|
const fixed = new Map();
|
|
@@ -263,18 +308,26 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
263
308
|
if (index === undefined) {
|
|
264
309
|
index = receivers.length;
|
|
265
310
|
receiverIndex.set(ref.localId, index);
|
|
266
|
-
receivers.push({
|
|
311
|
+
receivers.push({
|
|
312
|
+
ref,
|
|
313
|
+
global: !facts.locals.has(ref.localId),
|
|
314
|
+
string: ref.type.kind === "string",
|
|
315
|
+
});
|
|
267
316
|
}
|
|
268
317
|
return index;
|
|
269
318
|
};
|
|
270
319
|
// Worker programs: accesses through invariant receivers, proven or not,
|
|
271
320
|
// become thread-owned when the guard finds no shared storage.
|
|
272
321
|
const owned = new Map();
|
|
322
|
+
// While loops: accesses at a counter below a bound, by receiver and bound.
|
|
323
|
+
const boundedChecks = new Map();
|
|
324
|
+
const pairedCounters = paired !== null && counted === null ? new Set([paired.low.localId, paired.high.localId]) : null;
|
|
325
|
+
const pairedNodes = new Map();
|
|
273
326
|
const access = (node, array, index, width) => {
|
|
274
327
|
const ref = root(array);
|
|
275
328
|
if (!ref)
|
|
276
329
|
return;
|
|
277
|
-
if (facts.workers && !facts.owned.has(node)) {
|
|
330
|
+
if (facts.workers && ref.type.kind === "bytes" && !facts.owned.has(node)) {
|
|
278
331
|
const receiver = receiverOf(ref);
|
|
279
332
|
const nodes = owned.get(receiver);
|
|
280
333
|
if (nodes)
|
|
@@ -284,6 +337,20 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
284
337
|
}
|
|
285
338
|
if (facts.proven.has(node))
|
|
286
339
|
return;
|
|
340
|
+
// An element at either counter of a two-counter loop.
|
|
341
|
+
if (pairedCounters !== null &&
|
|
342
|
+
width === 1 &&
|
|
343
|
+
ref.type.kind === "bytes" &&
|
|
344
|
+
index.kind === "varRef" &&
|
|
345
|
+
pairedCounters.has(index.localId)) {
|
|
346
|
+
const receiver = receiverOf(ref);
|
|
347
|
+
const nodes = pairedNodes.get(receiver);
|
|
348
|
+
if (nodes)
|
|
349
|
+
nodes.push(node);
|
|
350
|
+
else
|
|
351
|
+
pairedNodes.set(receiver, [node]);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
287
354
|
const shape = counter !== null ? affine(index) : null;
|
|
288
355
|
if (shape && shape.counter !== 0) {
|
|
289
356
|
const operands = new Set();
|
|
@@ -308,12 +375,32 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
308
375
|
});
|
|
309
376
|
return;
|
|
310
377
|
}
|
|
378
|
+
const bounded = whileAccesses?.accesses.get(node);
|
|
379
|
+
const loopCounter = bounded && whileAccesses.counters.get(bounded.counter);
|
|
380
|
+
if (bounded && loopCounter && (!loopCounter.wraps || loopCounter.bounds !== null)) {
|
|
381
|
+
const receiver = receiverOf(ref);
|
|
382
|
+
const key = `${receiver}|${bounded.key}|${bounded.adj}`;
|
|
383
|
+
const slack = bounded.offset + width - 1 + bounded.adj;
|
|
384
|
+
const group = boundedChecks.get(key);
|
|
385
|
+
if (group) {
|
|
386
|
+
group.check.slack = Math.max(group.check.slack, slack);
|
|
387
|
+
group.nodes.push({ node, access: bounded });
|
|
388
|
+
}
|
|
389
|
+
else
|
|
390
|
+
boundedChecks.set(key, {
|
|
391
|
+
check: { receiver, bound: bounded.bound, slack },
|
|
392
|
+
nodes: [{ node, access: bounded }],
|
|
393
|
+
});
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
311
396
|
const range = facts.ranges.get(index);
|
|
312
397
|
if (!range)
|
|
313
398
|
return;
|
|
314
399
|
const end = range.max + width - 1;
|
|
315
|
-
// Only
|
|
316
|
-
//
|
|
400
|
+
// Only an end below 2^31: an outer loop must not pay for a guard that
|
|
401
|
+
// bounds an inner loop's unbounded counter, and the counter of a loop to
|
|
402
|
+
// an array's length reaches 2^32 - 2, a length no typed array in
|
|
403
|
+
// practice has.
|
|
317
404
|
if (range.min < 0 || end >= MAX_FIXED_END)
|
|
318
405
|
return;
|
|
319
406
|
const receiver = receiverOf(ref);
|
|
@@ -333,6 +420,10 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
333
420
|
else if (e.method === "get" && e.args[0])
|
|
334
421
|
access(e, e.receiver, e.args[0], 1);
|
|
335
422
|
}
|
|
423
|
+
else if (e.kind === "strIntrinsic" &&
|
|
424
|
+
(e.method === "charCodeAt" || e.method === "charAt") &&
|
|
425
|
+
e.args[0])
|
|
426
|
+
access(e, e.receiver, e.args[0], 1);
|
|
336
427
|
return everyExprChild(e, visitExpr, visitStmt);
|
|
337
428
|
};
|
|
338
429
|
const visitStmt = (s) => {
|
|
@@ -341,6 +432,8 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
341
432
|
return everyStmtChild(s, visitExpr, visitStmt);
|
|
342
433
|
};
|
|
343
434
|
loop.body.every(visitStmt);
|
|
435
|
+
if (loop.kind === "while")
|
|
436
|
+
visitExpr(loop.cond);
|
|
344
437
|
// Bound the counter so every counter operand stays a safe integer.
|
|
345
438
|
let bound = SAFE;
|
|
346
439
|
const affineGroups = [...affineChecks.values()].filter((group) => {
|
|
@@ -357,8 +450,14 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
357
450
|
});
|
|
358
451
|
const fixedKept = [...fixed.values()].slice(0, MAX_CHECKS);
|
|
359
452
|
const affineKept = affineGroups.slice(0, MAX_CHECKS - fixedKept.length);
|
|
453
|
+
const boundedKept = [...boundedChecks.values()].slice(0, Math.max(0, MAX_CHECKS - fixedKept.length - affineKept.length));
|
|
360
454
|
const ownedKept = [...owned.entries()].slice(0, MAX_CHECKS);
|
|
361
|
-
|
|
455
|
+
const pairedKept = [...pairedNodes.entries()].slice(0, Math.max(0, MAX_CHECKS - fixedKept.length - affineKept.length - boundedKept.length));
|
|
456
|
+
if (fixedKept.length === 0 &&
|
|
457
|
+
affineKept.length === 0 &&
|
|
458
|
+
boundedKept.length === 0 &&
|
|
459
|
+
ownedKept.length === 0 &&
|
|
460
|
+
pairedKept.length === 0)
|
|
362
461
|
return null;
|
|
363
462
|
const bounds = new Set();
|
|
364
463
|
const ownedNodes = new Set();
|
|
@@ -410,6 +509,42 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
410
509
|
for (const [node, key] of guardedNodes)
|
|
411
510
|
if (guarded.has(key))
|
|
412
511
|
ranges.set(node, GUARDED_TERM);
|
|
512
|
+
// While loop counters of the kept checks: each entry value is an exact
|
|
513
|
+
// integer that no access offset takes below 0. In the fast copy each
|
|
514
|
+
// access's index is below its length, and its counter read at least the
|
|
515
|
+
// most negative offset.
|
|
516
|
+
const narrow = (e, range) => {
|
|
517
|
+
const known = ranges.get(e) ?? facts.ranges.get(e);
|
|
518
|
+
ranges.set(e, known ? { min: Math.max(known.min, range.min), max: Math.min(known.max, range.max) } : range);
|
|
519
|
+
};
|
|
520
|
+
const counterMins = new Map();
|
|
521
|
+
for (const group of boundedKept) {
|
|
522
|
+
used.add(group.check.receiver);
|
|
523
|
+
for (const { node, access } of group.nodes) {
|
|
524
|
+
bounds.add(node);
|
|
525
|
+
const min = 0 - access.offset;
|
|
526
|
+
counterMins.set(access.counter, Math.max(counterMins.get(access.counter) ?? -SAFE, min));
|
|
527
|
+
narrow(access.ref, { min: -MAX_OFFSET, max: SAFE });
|
|
528
|
+
if (access.index !== access.ref)
|
|
529
|
+
narrow(access.index, { min: 0, max: SAFE });
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
for (const [receiver, nodes] of pairedKept) {
|
|
533
|
+
used.add(receiver);
|
|
534
|
+
for (const node of nodes)
|
|
535
|
+
bounds.add(node);
|
|
536
|
+
}
|
|
537
|
+
const counterChecks = [];
|
|
538
|
+
for (const [id, min] of counterMins) {
|
|
539
|
+
const info = whileAccesses.counters.get(id);
|
|
540
|
+
counterChecks.push({
|
|
541
|
+
ref: { kind: "varRef", localId: id, type: F64, loc: loop.loc },
|
|
542
|
+
min,
|
|
543
|
+
wrapBounds: info.wraps
|
|
544
|
+
? info.bounds.map((b) => ({ bound: b.bound, limit: 2 ** 31 - info.sum - b.adj }))
|
|
545
|
+
: [],
|
|
546
|
+
});
|
|
547
|
+
}
|
|
413
548
|
// Renumber the receivers the kept checks use.
|
|
414
549
|
const order = [...used].sort((a, b) => a - b);
|
|
415
550
|
const renumber = new Map(order.map((old, index) => [old, index]));
|
|
@@ -432,12 +567,276 @@ export function matchBytesLoopVersion(loop, counted, facts) {
|
|
|
432
567
|
minOffset: g.check.minOffset,
|
|
433
568
|
maxEnd: g.check.maxEnd,
|
|
434
569
|
})),
|
|
570
|
+
bounded: boundedKept.map((g) => ({
|
|
571
|
+
receiver: renumber.get(g.check.receiver),
|
|
572
|
+
bound: g.check.bound,
|
|
573
|
+
slack: g.check.slack,
|
|
574
|
+
})),
|
|
575
|
+
counters: counterChecks,
|
|
435
576
|
guarded,
|
|
436
577
|
counted: affineKept.length > 0 ? counted : null,
|
|
578
|
+
paired: paired !== null && pairedKept.length > 0
|
|
579
|
+
? { loop: paired, receivers: pairedKept.map(([receiver]) => renumber.get(receiver)) }
|
|
580
|
+
: null,
|
|
437
581
|
counterBound: needsBound ? bound : null,
|
|
438
582
|
ranges,
|
|
439
583
|
};
|
|
440
584
|
}
|
|
585
|
+
/** `counter = counter + k`, `counter = (counter + k) | 0` or `counter++`. */
|
|
586
|
+
function counterStep(s) {
|
|
587
|
+
if (s.kind === "exprStmt" && s.expr.kind === "incDec" && s.expr.op === "+")
|
|
588
|
+
return { id: s.expr.localId, k: 1, wraps: false };
|
|
589
|
+
if (s.kind !== "assign")
|
|
590
|
+
return null;
|
|
591
|
+
let value = s.value, wraps = false;
|
|
592
|
+
if (value.kind === "bin" &&
|
|
593
|
+
value.op === "|" &&
|
|
594
|
+
value.right.kind === "numLit" &&
|
|
595
|
+
value.right.value === 0 &&
|
|
596
|
+
value.left.kind === "bin") {
|
|
597
|
+
value = value.left;
|
|
598
|
+
wraps = true;
|
|
599
|
+
}
|
|
600
|
+
if (value.kind !== "bin" ||
|
|
601
|
+
value.op !== "+" ||
|
|
602
|
+
value.left.kind !== "varRef" ||
|
|
603
|
+
value.left.localId !== s.localId ||
|
|
604
|
+
value.right.kind !== "numLit" ||
|
|
605
|
+
!Number.isSafeInteger(value.right.value) ||
|
|
606
|
+
value.right.value <= 0 ||
|
|
607
|
+
value.right.value > MAX_OFFSET)
|
|
608
|
+
return null;
|
|
609
|
+
return { id: s.localId, k: value.right.value, wraps };
|
|
610
|
+
}
|
|
611
|
+
/** Typed-array and string accesses of a while loop that happen at a
|
|
612
|
+
* counter below a loop-invariant bound. A counter is a number local that
|
|
613
|
+
* the loop changes only by positive integer increments, written as
|
|
614
|
+
* statements of the body, of its blocks and branches, or of nested while
|
|
615
|
+
* loops. The condition of the loop, an `if` or a `&&` chain that compares
|
|
616
|
+
* the counter below a bound (`while (pos < end && bytes[pos] === 32)
|
|
617
|
+
* pos++`, or `s.charCodeAt(pos)` of a string) makes it below that bound
|
|
618
|
+
* until the next increment on the path. The counter starts at its entry
|
|
619
|
+
* value and only grows (a `| 0` increment never wraps when every bound is
|
|
620
|
+
* at most 2^31 minus the increments), so an access at `counter + d` is in
|
|
621
|
+
* bounds for the whole loop when the entry value is at least `-d` and
|
|
622
|
+
* `bound + d < length` (`+ 1` for `<=`). */
|
|
623
|
+
function findWhileCounterAccesses(loop, host) {
|
|
624
|
+
const steps = new Map();
|
|
625
|
+
const refused = new Set();
|
|
626
|
+
// Increments count only as statements of the loop's straight-line
|
|
627
|
+
// structure; any other write refuses the binding.
|
|
628
|
+
const writes = (list, direct) => {
|
|
629
|
+
for (const s of list) {
|
|
630
|
+
const step = counterStep(s);
|
|
631
|
+
if (step && direct) {
|
|
632
|
+
const prior = steps.get(step.id);
|
|
633
|
+
steps.set(step.id, {
|
|
634
|
+
sum: (prior?.sum ?? 0) + step.k,
|
|
635
|
+
wraps: (prior?.wraps ?? false) || step.wraps,
|
|
636
|
+
});
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
if (step)
|
|
640
|
+
refused.add(step.id);
|
|
641
|
+
const nested = direct &&
|
|
642
|
+
(s.kind === "if" || s.kind === "while" || (s.kind === "block" && !s.labels?.length));
|
|
643
|
+
if (s.kind === "assign" || s.kind === "varDecl" || s.kind === "forOf")
|
|
644
|
+
refused.add(s.localId);
|
|
645
|
+
if (s.kind === "tryCatch" && s.catchLocalId)
|
|
646
|
+
refused.add(s.catchLocalId);
|
|
647
|
+
everyStmtChild(s, (e) => (exprWrites(e), true), (c) => (writes([c], nested), true));
|
|
648
|
+
}
|
|
649
|
+
};
|
|
650
|
+
const exprWrites = (e) => {
|
|
651
|
+
if (e.kind === "assignExpr" || e.kind === "incDec")
|
|
652
|
+
refused.add(e.localId);
|
|
653
|
+
everyExprChild(e, (c) => (exprWrites(c), true), (c) => (writes([c], false), true));
|
|
654
|
+
};
|
|
655
|
+
exprWrites(loop.cond);
|
|
656
|
+
writes(loop.body, true);
|
|
657
|
+
const counter = (id) => steps.has(id) && !refused.has(id) && host.counterLocal(id);
|
|
658
|
+
// The bounds a condition puts on counters while it holds.
|
|
659
|
+
const facts = (cond, into) => {
|
|
660
|
+
if (cond.kind === "toBool")
|
|
661
|
+
return facts(cond.operand, into);
|
|
662
|
+
if (cond.kind === "logical" && cond.op === "&&") {
|
|
663
|
+
facts(cond.left, into);
|
|
664
|
+
facts(cond.right, into);
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
if (cond.kind !== "bin")
|
|
668
|
+
return;
|
|
669
|
+
const below = cond.op === "<" || cond.op === "<=", above = cond.op === ">" || cond.op === ">=";
|
|
670
|
+
const c = below ? cond.left : above ? cond.right : null, bound = below ? cond.right : cond.left;
|
|
671
|
+
if (c?.kind !== "varRef" || !counter(c.localId) || into.has(c.localId))
|
|
672
|
+
return;
|
|
673
|
+
const key = host.boundKey(bound);
|
|
674
|
+
if (key === null)
|
|
675
|
+
return;
|
|
676
|
+
into.set(c.localId, { bound, key, adj: cond.op === "<=" || cond.op === ">=" ? 1 : 0 });
|
|
677
|
+
};
|
|
678
|
+
// The facts that hold after either of two paths.
|
|
679
|
+
const meet = (a, b) => {
|
|
680
|
+
if (a === null)
|
|
681
|
+
return b;
|
|
682
|
+
if (b === null)
|
|
683
|
+
return a;
|
|
684
|
+
const out = new Map();
|
|
685
|
+
for (const [id, fact] of a)
|
|
686
|
+
if (b.get(id) === fact)
|
|
687
|
+
out.set(id, fact);
|
|
688
|
+
return out;
|
|
689
|
+
};
|
|
690
|
+
const withFacts = (clean, cond) => {
|
|
691
|
+
const out = new Map(clean);
|
|
692
|
+
facts(cond, out);
|
|
693
|
+
return out;
|
|
694
|
+
};
|
|
695
|
+
const accesses = new Map();
|
|
696
|
+
const record = (node, index, clean) => {
|
|
697
|
+
let ref = index, offset = 0;
|
|
698
|
+
if (index.kind === "bin" && (index.op === "+" || index.op === "-")) {
|
|
699
|
+
const literal = index.right.kind === "numLit" ? index.right : index.op === "+" ? index.left : null;
|
|
700
|
+
const other = literal === index.right ? index.left : index.right;
|
|
701
|
+
if (literal?.kind !== "numLit" || !Number.isSafeInteger(literal.value))
|
|
702
|
+
return;
|
|
703
|
+
if (Math.abs(literal.value) > MAX_OFFSET || Object.is(literal.value, -0))
|
|
704
|
+
return;
|
|
705
|
+
offset = index.op === "-" ? -literal.value : literal.value;
|
|
706
|
+
ref = other;
|
|
707
|
+
}
|
|
708
|
+
if (ref.kind !== "varRef")
|
|
709
|
+
return;
|
|
710
|
+
const fact = clean.get(ref.localId);
|
|
711
|
+
if (fact)
|
|
712
|
+
accesses.set(node, { counter: ref.localId, index, ref, ...fact, offset });
|
|
713
|
+
};
|
|
714
|
+
const expr = (e, clean) => {
|
|
715
|
+
if (e.kind === "bytesIntrinsic") {
|
|
716
|
+
const numeric = byteNumberAccess(e);
|
|
717
|
+
const index = numeric
|
|
718
|
+
? e.args[numeric.offsetArg]
|
|
719
|
+
: e.method === "get"
|
|
720
|
+
? e.args[0]
|
|
721
|
+
: undefined;
|
|
722
|
+
if (index)
|
|
723
|
+
record(e, index, clean);
|
|
724
|
+
}
|
|
725
|
+
if (e.kind === "strIntrinsic" &&
|
|
726
|
+
(e.method === "charCodeAt" || e.method === "charAt") &&
|
|
727
|
+
e.args[0])
|
|
728
|
+
record(e, e.args[0], clean);
|
|
729
|
+
if (e.kind === "logical" && e.op === "&&") {
|
|
730
|
+
expr(e.left, clean);
|
|
731
|
+
expr(e.right, withFacts(clean, e.left));
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
if (e.kind === "ternary") {
|
|
735
|
+
expr(e.cond, clean);
|
|
736
|
+
expr(e.then, withFacts(clean, e.cond));
|
|
737
|
+
expr(e.else_, clean);
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
everyExprChild(e, (c) => (expr(c, clean), true), (c) => (stmts([c], clean), true));
|
|
741
|
+
};
|
|
742
|
+
// Walks statements in order; the result is the clean state where the
|
|
743
|
+
// list falls through, or null when it never does.
|
|
744
|
+
const stmts = (list, clean) => {
|
|
745
|
+
let current = clean;
|
|
746
|
+
for (const s of list) {
|
|
747
|
+
if (current === null)
|
|
748
|
+
return null;
|
|
749
|
+
const step = counterStep(s);
|
|
750
|
+
if (step) {
|
|
751
|
+
const next = new Map(current);
|
|
752
|
+
next.delete(step.id);
|
|
753
|
+
current = next;
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
switch (s.kind) {
|
|
757
|
+
case "if": {
|
|
758
|
+
expr(s.cond, current);
|
|
759
|
+
const then = stmts(s.then, withFacts(current, s.cond));
|
|
760
|
+
const otherwise = stmts(s.else_ ?? [], current);
|
|
761
|
+
current = meet(then, otherwise);
|
|
762
|
+
break;
|
|
763
|
+
}
|
|
764
|
+
case "while": {
|
|
765
|
+
// A pass of the nested loop may follow its own increments.
|
|
766
|
+
const advanced = new Map(current);
|
|
767
|
+
for (const id of writtenCounters(s.body))
|
|
768
|
+
advanced.delete(id);
|
|
769
|
+
expr(s.cond, advanced);
|
|
770
|
+
stmts(s.body, withFacts(advanced, s.cond));
|
|
771
|
+
current = advanced;
|
|
772
|
+
break;
|
|
773
|
+
}
|
|
774
|
+
case "block":
|
|
775
|
+
if (!s.labels?.length) {
|
|
776
|
+
current = stmts(s.body, current);
|
|
777
|
+
break;
|
|
778
|
+
}
|
|
779
|
+
everyStmtChild(s, (e) => (expr(e, current), true), (c) => (stmts([c], current), true));
|
|
780
|
+
break;
|
|
781
|
+
case "bytesSet":
|
|
782
|
+
record(s, s.index, current);
|
|
783
|
+
everyStmtChild(s, (e) => (expr(e, current), true), (c) => (stmts([c], current), true));
|
|
784
|
+
break;
|
|
785
|
+
case "break":
|
|
786
|
+
case "continue":
|
|
787
|
+
case "return":
|
|
788
|
+
case "throw":
|
|
789
|
+
everyStmtChild(s, (e) => (expr(e, current), true), (c) => (stmts([c], current), true));
|
|
790
|
+
current = null;
|
|
791
|
+
break;
|
|
792
|
+
default:
|
|
793
|
+
everyStmtChild(s, (e) => (expr(e, current), true), (c) => (stmts([c], current), true));
|
|
794
|
+
break;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
return current;
|
|
798
|
+
};
|
|
799
|
+
const writtenCounters = (list) => {
|
|
800
|
+
const out = new Set();
|
|
801
|
+
const visit = (s) => {
|
|
802
|
+
const step = counterStep(s);
|
|
803
|
+
if (step)
|
|
804
|
+
out.add(step.id);
|
|
805
|
+
return everyStmtChild(s, () => true, visit);
|
|
806
|
+
};
|
|
807
|
+
list.every(visit);
|
|
808
|
+
return out;
|
|
809
|
+
};
|
|
810
|
+
expr(loop.cond, new Map());
|
|
811
|
+
stmts(loop.body, withFacts(new Map(), loop.cond));
|
|
812
|
+
// Each counter's bounds: the loop's and those of nested while loops that
|
|
813
|
+
// advance it.
|
|
814
|
+
const counters = new Map();
|
|
815
|
+
const loops = [loop];
|
|
816
|
+
const collectLoops = (s) => {
|
|
817
|
+
if (s.kind === "while")
|
|
818
|
+
loops.push(s);
|
|
819
|
+
return everyStmtChild(s, () => true, collectLoops);
|
|
820
|
+
};
|
|
821
|
+
loop.body.every(collectLoops);
|
|
822
|
+
for (const [id, step] of steps) {
|
|
823
|
+
if (!counter(id))
|
|
824
|
+
continue;
|
|
825
|
+
let bounds = [];
|
|
826
|
+
for (const l of loops) {
|
|
827
|
+
if (l !== loop && !writtenCounters(l.body).has(id))
|
|
828
|
+
continue;
|
|
829
|
+
const fact = withFacts(new Map(), l.cond).get(id);
|
|
830
|
+
if (!fact) {
|
|
831
|
+
bounds = null;
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
bounds.push({ bound: fact.bound, adj: fact.adj });
|
|
835
|
+
}
|
|
836
|
+
counters.set(id, { ...step, bounds });
|
|
837
|
+
}
|
|
838
|
+
return { accesses, counters };
|
|
839
|
+
}
|
|
441
840
|
/** Branches to `fast` when every access the version proves is in bounds for
|
|
442
841
|
* every iteration and every view it proves thread-owned has no shared
|
|
443
842
|
* storage, and to `slow` otherwise (including a counted loop whose
|
|
@@ -463,8 +862,10 @@ export function emitBytesLoopVersionGuard(host, version, fast, slow) {
|
|
|
463
862
|
}
|
|
464
863
|
return value;
|
|
465
864
|
});
|
|
466
|
-
const lengths = receivers.map((receiver) => {
|
|
467
|
-
const len =
|
|
865
|
+
const lengths = receivers.map((receiver, index) => {
|
|
866
|
+
const len = version.receivers[index].string
|
|
867
|
+
? emitStringByteLength(host, receiver)
|
|
868
|
+
: emitBytesHeaderLength(host, receiver);
|
|
468
869
|
if (host.sizeType === "i64")
|
|
469
870
|
return len;
|
|
470
871
|
const wide = B.tmp();
|
|
@@ -472,6 +873,11 @@ export function emitBytesLoopVersionGuard(host, version, fast, slow) {
|
|
|
472
873
|
return wide;
|
|
473
874
|
});
|
|
474
875
|
const conditions = [];
|
|
876
|
+
// A string's byte length is its UTF-16 length when it is ASCII.
|
|
877
|
+
version.receivers.forEach(({ string }, index) => {
|
|
878
|
+
if (string)
|
|
879
|
+
conditions.push(emitStringAsciiFlag(host, receivers[index]));
|
|
880
|
+
});
|
|
475
881
|
for (const index of version.ownedReceivers) {
|
|
476
882
|
const owned = B.tmp();
|
|
477
883
|
B.line(`${owned} = icmp eq ptr ${emitBytesSharedStorage(host, receivers[index])}, null`);
|
|
@@ -482,6 +888,40 @@ export function emitBytesLoopVersionGuard(host, version, fast, slow) {
|
|
|
482
888
|
B.line(`${ok} = icmp ugt i64 ${lengths[check.receiver]}, ${check.end}`);
|
|
483
889
|
conditions.push(ok);
|
|
484
890
|
}
|
|
891
|
+
for (const counter of version.counters) {
|
|
892
|
+
const value = host.emitExpr(counter.ref);
|
|
893
|
+
// A counter held as an integer (an int32 slot) is exact already and
|
|
894
|
+
// needs at most its lower bound tested.
|
|
895
|
+
const integer = exactInteger(host, value, counter.ref);
|
|
896
|
+
if (integer && integer.range.max <= SAFE) {
|
|
897
|
+
if (integer.range.min < counter.min) {
|
|
898
|
+
const ok = B.tmp();
|
|
899
|
+
B.line(`${ok} = icmp sge i64 ${widenInteger(host, integer)}, ${counter.min}`);
|
|
900
|
+
conditions.push(ok);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
else
|
|
904
|
+
conditions.push(emitExactIntegerTest(host, value.name, counter.min, SAFE).ok);
|
|
905
|
+
for (const wrap of counter.wrapBounds) {
|
|
906
|
+
const bound = host.emitExpr(wrap.bound);
|
|
907
|
+
const boundInteger = exactInteger(host, bound, wrap.bound);
|
|
908
|
+
if (boundInteger && boundInteger.range.max <= wrap.limit)
|
|
909
|
+
continue;
|
|
910
|
+
const ok = B.tmp();
|
|
911
|
+
B.line(`${ok} = fcmp ole double ${bound.name}, ${f64Lit(wrap.limit)}`);
|
|
912
|
+
conditions.push(ok);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
for (const check of version.bounded) {
|
|
916
|
+
// `bound <= length - slack` in doubles: both sides are exact (a length
|
|
917
|
+
// is below 2^53 and a slack below 2^32), and NaN fails.
|
|
918
|
+
const bound = host.emitExpr(check.bound).name;
|
|
919
|
+
const length = B.tmp(), room = B.tmp(), ok = B.tmp();
|
|
920
|
+
B.line(`${length} = uitofp i64 ${lengths[check.receiver]} to double`);
|
|
921
|
+
B.line(`${room} = fsub double ${length}, ${f64Lit(check.slack)}`);
|
|
922
|
+
B.line(`${ok} = fcmp ole double ${bound}, ${room}`);
|
|
923
|
+
conditions.push(ok);
|
|
924
|
+
}
|
|
485
925
|
if (counted && version.affine.length > 0) {
|
|
486
926
|
// The first and last counter values, in ascending order. The last value
|
|
487
927
|
// of a non-unit step is exact: `start + ⌊(limit ∓ 1 - start) / step⌋ *
|
|
@@ -524,7 +964,7 @@ export function emitBytesLoopVersionGuard(host, version, fast, slow) {
|
|
|
524
964
|
for (const term of check.terms) {
|
|
525
965
|
const value = host.emitExpr(term.expr);
|
|
526
966
|
if (version.guarded.has(term.key)) {
|
|
527
|
-
const tested =
|
|
967
|
+
const tested = emitExactIntegerTest(host, value.name, GUARDED_TERM.min, GUARDED_TERM.max);
|
|
528
968
|
conditions.push(tested.ok);
|
|
529
969
|
const sum = B.tmp();
|
|
530
970
|
B.line(`${sum} = ${term.sign > 0 ? "add" : "sub"} i64 ${base}, ${tested.integer}`);
|
|
@@ -559,6 +999,25 @@ export function emitBytesLoopVersionGuard(host, version, fast, slow) {
|
|
|
559
999
|
conditions.push(both);
|
|
560
1000
|
}
|
|
561
1001
|
}
|
|
1002
|
+
if (version.paired !== null) {
|
|
1003
|
+
// Both counters stay within [lo, hi] (exact integers below 2^53): every
|
|
1004
|
+
// access at either one is in bounds when `lo >= 0` and `hi < length`.
|
|
1005
|
+
const { loop } = version.paired;
|
|
1006
|
+
const [low, high] = [loop.low.start, loop.high.start].map((expr) => {
|
|
1007
|
+
const tested = emitExactIntegerTest(host, host.emitExpr(expr).name, -SAFE, SAFE);
|
|
1008
|
+
conditions.push(tested.ok);
|
|
1009
|
+
return tested.integer;
|
|
1010
|
+
});
|
|
1011
|
+
const nonNegative = B.tmp();
|
|
1012
|
+
B.line(`${nonNegative} = icmp sge i64 ${low}, 0`);
|
|
1013
|
+
conditions.push(nonNegative);
|
|
1014
|
+
for (const receiver of version.paired.receivers) {
|
|
1015
|
+
// Lengths are at most 2^53 elements: a signed comparison is exact.
|
|
1016
|
+
const below = B.tmp();
|
|
1017
|
+
B.line(`${below} = icmp slt i64 ${high}, ${lengths[receiver]}`);
|
|
1018
|
+
conditions.push(below);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
562
1021
|
let valid = "true";
|
|
563
1022
|
for (const cond of conditions) {
|
|
564
1023
|
if (valid === "true")
|
|
@@ -574,24 +1033,6 @@ export function emitBytesLoopVersionGuard(host, version, fast, slow) {
|
|
|
574
1033
|
else
|
|
575
1034
|
B.condBr(valid, fast, slow);
|
|
576
1035
|
}
|
|
577
|
-
/** Tests that a guarded term is an exact integer within GUARDED_TERM (not
|
|
578
|
-
* -0; NaN fails the ordered comparisons) and gives its i64. The integer is
|
|
579
|
-
* frozen, so it is a fixed value even when the test fails. */
|
|
580
|
-
function emitGuardedTerm(host, value) {
|
|
581
|
-
const B = host.B;
|
|
582
|
-
const low = B.tmp(), high = B.tmp(), inRange = B.tmp(), raw = B.tmp(), integer = B.tmp(), back = B.tmp(), bits = B.tmp(), backBits = B.tmp(), exact = B.tmp(), ok = B.tmp();
|
|
583
|
-
B.line(`${low} = fcmp oge double ${value}, ${f64Lit(GUARDED_TERM.min)}`);
|
|
584
|
-
B.line(`${high} = fcmp ole double ${value}, ${f64Lit(GUARDED_TERM.max)}`);
|
|
585
|
-
B.line(`${inRange} = and i1 ${low}, ${high}`);
|
|
586
|
-
B.line(`${raw} = fptosi double ${value} to i64`);
|
|
587
|
-
B.line(`${integer} = freeze i64 ${raw}`);
|
|
588
|
-
B.line(`${back} = sitofp i64 ${integer} to double`);
|
|
589
|
-
B.line(`${bits} = bitcast double ${value} to i64`);
|
|
590
|
-
B.line(`${backBits} = bitcast double ${back} to i64`);
|
|
591
|
-
B.line(`${exact} = icmp eq i64 ${bits}, ${backBits}`);
|
|
592
|
-
B.line(`${ok} = and i1 ${inRange}, ${exact}`);
|
|
593
|
-
return { ok, integer };
|
|
594
|
-
}
|
|
595
1036
|
function scaleCounter(host, value, scale) {
|
|
596
1037
|
if (scale === 1)
|
|
597
1038
|
return value;
|