@scriptc/compiler 0.2.8 → 0.2.10
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 +1 -0
- package/dist/backend/cycle-analysis.d.ts +56 -0
- package/dist/backend/cycle-analysis.js +222 -28
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +232 -15
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/cycle-mutability.d.ts +27 -6
- package/dist/backend/cycle-mutability.js +110 -17
- package/dist/backend/cycle-mutability.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.d.ts +1 -0
- package/dist/backend/immutability.test.js +131 -0
- package/dist/backend/immutability.test.js.map +1 -0
- package/dist/backend/llvm/alloc.d.ts +13 -3
- package/dist/backend/llvm/alloc.js +24 -10
- package/dist/backend/llvm/alloc.js.map +1 -1
- package/dist/backend/llvm/alloc.test.js +5 -5
- package/dist/backend/llvm/alloc.test.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/byte-numbers.js +2 -3
- package/dist/backend/llvm/byte-numbers.js.map +1 -1
- package/dist/backend/llvm/classes.d.ts +28 -0
- package/dist/backend/llvm/classes.js +51 -10
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +129 -1
- package/dist/backend/llvm/classes.test.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +30 -0
- package/dist/backend/llvm/common.js +41 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.js +6 -5
- 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 +6 -4
- package/dist/backend/llvm/dyn.js +30 -14
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +109 -5
- package/dist/backend/llvm/emitter.js +716 -112
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +54 -3
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.js +35 -28
- package/dist/backend/llvm/expr-bytes.js.map +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 +31 -8
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-context.d.ts +2 -0
- package/dist/backend/llvm/expr-control.js +46 -5
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +3 -0
- 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 +53 -0
- package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.d.ts +3 -0
- package/dist/backend/llvm/expr-stream-bridges.js +76 -14
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +18 -2
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +1 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.d.ts +17 -6
- package/dist/backend/llvm/local-array-reads.js +157 -45
- package/dist/backend/llvm/local-array-reads.js.map +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 +7 -0
- package/dist/backend/llvm/map-number-lookup.js +18 -1
- 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 +14 -4
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +5 -0
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/reference-effects.js +34 -1
- package/dist/backend/llvm/reference-effects.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 +22 -8
- package/dist/backend/llvm/shapes.js +79 -23
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +5 -5
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/string-lifetimes.test.js +39 -10
- 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 +45 -11
- package/dist/backend/llvm/string-reads.js.map +1 -1
- package/dist/backend/llvm/string-slices.js +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 +28 -10
- package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
- package/dist/backend/llvm/trunc.d.ts +8 -0
- package/dist/backend/llvm/trunc.js +28 -0
- package/dist/backend/llvm/trunc.js.map +1 -0
- 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/loop-polls.d.ts +14 -0
- package/dist/backend/loop-polls.js +100 -0
- package/dist/backend/loop-polls.js.map +1 -0
- package/dist/backend/loop-polls.test.d.ts +1 -0
- package/dist/backend/loop-polls.test.js +86 -0
- package/dist/backend/loop-polls.test.js.map +1 -0
- package/dist/backend/may-throw.d.ts +36 -2
- package/dist/backend/may-throw.js +328 -13
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +169 -1
- package/dist/backend/may-throw.test.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +1 -3
- package/dist/backend/native-codegen.js +4 -32
- package/dist/backend/native-codegen.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/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-abi.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +1 -1
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/cli/command.js +8 -1
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/output-options.d.ts +1 -0
- package/dist/cli/output-options.js +3 -0
- package/dist/cli/output-options.js.map +1 -1
- package/dist/cli/usage.d.ts +5 -1
- package/dist/cli/usage.js +6 -0
- package/dist/cli/usage.js.map +1 -1
- package/dist/compile-types.d.ts +5 -0
- package/dist/contracts/check.d.ts +8 -0
- package/dist/contracts/check.js +1577 -0
- package/dist/contracts/check.js.map +1 -0
- package/dist/executable/executable-cache.d.ts +2 -0
- package/dist/executable/executable-cache.js +3 -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/executable/prepare.js +9 -0
- package/dist/executable/prepare.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/lowering/array-values.js +37 -1
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/builtins/strings.js +4 -1
- package/dist/frontend/lowering/builtins/strings.js.map +1 -1
- package/dist/frontend/lowering/call-arguments.js +96 -4
- package/dist/frontend/lowering/call-arguments.js.map +1 -1
- package/dist/frontend/lowering/class-method-mutations.js +88 -0
- package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
- package/dist/frontend/lowering/coercions/unions.d.ts +12 -0
- package/dist/frontend/lowering/coercions/unions.js +63 -0
- package/dist/frontend/lowering/coercions/unions.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +15 -4
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.js +4 -1
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/expressions/union-fields.d.ts +19 -0
- package/dist/frontend/lowering/expressions/union-fields.js +236 -0
- package/dist/frontend/lowering/expressions/union-fields.js.map +1 -0
- package/dist/frontend/lowering/lower-calls.js +21 -4
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +6 -0
- package/dist/frontend/lowering/lower-exprs.js +245 -4
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +5 -19
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +11 -1
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +14 -0
- package/dist/frontend/lowering/lowerer.js +221 -8
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/nan-coded-reads.d.ts +161 -0
- package/dist/frontend/lowering/nan-coded-reads.js +1342 -0
- package/dist/frontend/lowering/nan-coded-reads.js.map +1 -0
- 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.d.ts +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/runtime-optional-bounds.d.ts +14 -2
- package/dist/frontend/lowering/runtime-optional-bounds.js +17 -11
- package/dist/frontend/lowering/runtime-optional-bounds.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-bounds.test.js +28 -0
- package/dist/frontend/lowering/runtime-optional-bounds.test.js.map +1 -1
- package/dist/frontend/lowering/surfaces.js +8 -0
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/program.js +1 -1
- package/dist/frontend/type-mapper.js +43 -0
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +20 -8
- package/dist/index.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +2 -0
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/constant-globals.d.ts +14 -0
- package/dist/ir/constant-globals.js +81 -0
- package/dist/ir/constant-globals.js.map +1 -0
- package/dist/ir/constant-globals.test.d.ts +1 -0
- package/dist/ir/constant-globals.test.js +97 -0
- package/dist/ir/constant-globals.test.js.map +1 -0
- package/dist/ir/final-fields.d.ts +35 -0
- package/dist/ir/final-fields.js +187 -0
- package/dist/ir/final-fields.js.map +1 -0
- package/dist/ir/final-fields.test.d.ts +1 -0
- package/dist/ir/final-fields.test.js +106 -0
- package/dist/ir/final-fields.test.js.map +1 -0
- package/dist/ir/int32-slots.d.ts +35 -0
- package/dist/ir/int32-slots.js +217 -104
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +27 -0
- package/dist/ir/int32-slots.test.js.map +1 -1
- package/dist/ir/integer-loops.d.ts +5 -0
- package/dist/ir/integer-loops.js +23 -4
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-loops.test.js +43 -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 +38 -1
- package/dist/ir/ir.js +4 -0
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/serialize.d.ts +17 -3
- package/dist/ir/serialize.js +198 -39
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +65 -1
- package/dist/ir/serialize.test.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.d.ts +1 -0
- package/dist/ir/unshare.test.js +115 -0
- package/dist/ir/unshare.test.js.map +1 -0
- package/dist/library/prepare.js +9 -0
- package/dist/library/prepare.js.map +1 -1
- package/dist/native/cache.d.ts +8 -1
- package/dist/native/cache.js +38 -1
- package/dist/native/cache.js.map +1 -1
- package/dist/native/cache.test.js +11 -0
- package/dist/native/cache.test.js.map +1 -1
- package/dist/native/compiler.js +4 -3
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/prepare.d.ts +3 -1
- package/dist/native/prepare.js +63 -28
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/prepare.test.js +23 -1
- package/dist/native/prepare.test.js.map +1 -1
- package/dist/native/text-file.d.ts +10 -0
- package/dist/native/text-file.js +41 -0
- package/dist/native/text-file.js.map +1 -0
- package/dist/text-parts.d.ts +5 -0
- package/dist/text-parts.js +36 -0
- package/dist/text-parts.js.map +1 -0
- package/package.json +20 -20
- package/surface-manifest.json +7 -1
- package/dist/frontend/lowering/expressions/union-field-write.d.ts +0 -8
- package/dist/frontend/lowering/expressions/union-field-write.js +0 -108
- package/dist/frontend/lowering/expressions/union-field-write.js.map +0 -1
|
@@ -15,6 +15,11 @@ export interface WalkBorrowHost {
|
|
|
15
15
|
/** Parameters that may become candidates; once calling conventions are
|
|
16
16
|
* fixed, only borrowed parameters qualify. Defaults to every parameter. */
|
|
17
17
|
parameterAllowed?(localId: string): boolean;
|
|
18
|
+
/** For bodies that may write the heap: whether a walk only reads
|
|
19
|
+
* locations the whole body never writes, given the current candidates
|
|
20
|
+
* (whose own rebinding releases nothing). Absent: the body preserves
|
|
21
|
+
* every edge. */
|
|
22
|
+
unwritten?(value: IrExpr, candidates: ReadonlySet<string>): boolean;
|
|
18
23
|
}
|
|
19
24
|
export interface WalkFacts {
|
|
20
25
|
locals: ReadonlySet<string>;
|
|
@@ -30,7 +35,9 @@ export interface WalkFacts {
|
|
|
30
35
|
* calling convention.
|
|
31
36
|
*
|
|
32
37
|
* Soundness rests on the whole body preserving heap edges (the caller
|
|
33
|
-
* passes only functions in ReferenceEffects.functions
|
|
38
|
+
* passes only functions in ReferenceEffects.functions, or supplies
|
|
39
|
+
* `unwritten` to admit only walks over locations the body never writes;
|
|
40
|
+
* the argument below then applies to those locations): neither the body
|
|
34
41
|
* nor anything it calls removes a field, element or global reference, so
|
|
35
42
|
* every object reachable from a parameter at entry stays reachable (and
|
|
36
43
|
* alive) until the function returns. Such a local therefore needs no
|
|
@@ -8,7 +8,9 @@ import { everyStmtList } from "../../ir/traverse.js";
|
|
|
8
8
|
* calling convention.
|
|
9
9
|
*
|
|
10
10
|
* Soundness rests on the whole body preserving heap edges (the caller
|
|
11
|
-
* passes only functions in ReferenceEffects.functions
|
|
11
|
+
* passes only functions in ReferenceEffects.functions, or supplies
|
|
12
|
+
* `unwritten` to admit only walks over locations the body never writes;
|
|
13
|
+
* the argument below then applies to those locations): neither the body
|
|
12
14
|
* nor anything it calls removes a field, element or global reference, so
|
|
13
15
|
* every object reachable from a parameter at entry stays reachable (and
|
|
14
16
|
* alive) until the function returns. Such a local therefore needs no
|
|
@@ -109,6 +111,10 @@ export function analyzeWalks(fn, host) {
|
|
|
109
111
|
case "fieldGet":
|
|
110
112
|
case "recordGet":
|
|
111
113
|
return host.borrowsWithoutOwning(e) && walk(e.obj);
|
|
114
|
+
// A required element of a walked array (the read still traps when the
|
|
115
|
+
// element is missing).
|
|
116
|
+
case "arrayGet":
|
|
117
|
+
return host.borrowsWithoutOwning(e) && walk(e.arr);
|
|
112
118
|
case "unionNarrow":
|
|
113
119
|
case "downcast":
|
|
114
120
|
case "upcast":
|
|
@@ -130,11 +136,14 @@ export function analyzeWalks(fn, host) {
|
|
|
130
136
|
return false;
|
|
131
137
|
}
|
|
132
138
|
};
|
|
133
|
-
const
|
|
139
|
+
const isThrow = (e) => e.kind === "libCall" && e.fn === "error.nodeThrow";
|
|
140
|
+
const walkOrThrow = (e) => isThrow(e) || walk(e);
|
|
134
141
|
for (let changed = true; changed;) {
|
|
135
142
|
changed = false;
|
|
136
143
|
for (const id of candidates) {
|
|
137
|
-
if (definitions
|
|
144
|
+
if (definitions
|
|
145
|
+
.get(id)
|
|
146
|
+
.every((value) => value === null || (walk(value) && host.unwritten?.(value, candidates) !== false)))
|
|
138
147
|
continue;
|
|
139
148
|
candidates.delete(id);
|
|
140
149
|
changed = true;
|
|
@@ -144,7 +153,9 @@ export function analyzeWalks(fn, host) {
|
|
|
144
153
|
result.add(id);
|
|
145
154
|
const returnsWalk = !guarded &&
|
|
146
155
|
returns.length > 0 &&
|
|
147
|
-
returns.every((value) => value !== null &&
|
|
156
|
+
returns.every((value) => value !== null &&
|
|
157
|
+
walkOrThrow(value) &&
|
|
158
|
+
(isThrow(value) || host.unwritten?.(value, candidates) !== false));
|
|
148
159
|
return { locals: result, returnsWalk };
|
|
149
160
|
}
|
|
150
161
|
//# sourceMappingURL=walk-borrows.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"walk-borrows.js","sourceRoot":"","sources":["../../../src/backend/llvm/walk-borrows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAA8C,MAAM,gBAAgB,CAAC;AAC1F,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"walk-borrows.js","sourceRoot":"","sources":["../../../src/backend/llvm/walk-borrows.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { IrExpr, IrStmt } from "../ir/ir.js";
|
|
2
|
+
type Loop = Extract<IrStmt, {
|
|
3
|
+
kind: "while" | "doWhile" | "for" | "forOf";
|
|
4
|
+
}>;
|
|
5
|
+
/** True when every iteration of `loop` evaluates a call that the emitter
|
|
6
|
+
* follows with a pending test (`tested`). Worker loops poll for termination
|
|
7
|
+
* every 64 iterations (emitWorkerLoopCheck) so that a loop whose body calls
|
|
8
|
+
* nothing that tests still observes a terminate request; a pending test reads
|
|
9
|
+
* the same alert word, so a loop that always runs one needs no extra poll.
|
|
10
|
+
* The tested call must be unconditional: in the condition (while, for), in
|
|
11
|
+
* the update or the do-while condition (both run after `continue` too), or
|
|
12
|
+
* in the body before any statement that can `continue` this loop. */
|
|
13
|
+
export declare function loopTestsEveryIteration(loop: Loop, tested: (call: IrExpr) => boolean): boolean;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { everyExprChild, everyStmtChild } from "../ir/traverse.js";
|
|
2
|
+
/** Expression kinds whose operands all evaluate whenever the expression does
|
|
3
|
+
* (no short-circuit, deferred or conditional operand). */
|
|
4
|
+
const EAGER_EXPRS = new Set([
|
|
5
|
+
"call",
|
|
6
|
+
"new",
|
|
7
|
+
"virtualCall",
|
|
8
|
+
"callValue",
|
|
9
|
+
"bin",
|
|
10
|
+
"unary",
|
|
11
|
+
"toBool",
|
|
12
|
+
"strConcat",
|
|
13
|
+
"strEq",
|
|
14
|
+
"strCmp",
|
|
15
|
+
"assignExpr",
|
|
16
|
+
"fieldGet",
|
|
17
|
+
"fieldIncDec",
|
|
18
|
+
"arrayGet",
|
|
19
|
+
"recordGet",
|
|
20
|
+
"upcast",
|
|
21
|
+
"downcast",
|
|
22
|
+
"unionWrap",
|
|
23
|
+
"dynFrom",
|
|
24
|
+
]);
|
|
25
|
+
/** Statement kinds whose expressions all evaluate whenever the statement
|
|
26
|
+
* does. */
|
|
27
|
+
const EAGER_STMTS = new Set([
|
|
28
|
+
"varDecl",
|
|
29
|
+
"assign",
|
|
30
|
+
"exprStmt",
|
|
31
|
+
"arraySet",
|
|
32
|
+
"bytesSet",
|
|
33
|
+
"fieldSet",
|
|
34
|
+
"recordSet",
|
|
35
|
+
"return",
|
|
36
|
+
"throw",
|
|
37
|
+
]);
|
|
38
|
+
/** True when every iteration of `loop` evaluates a call that the emitter
|
|
39
|
+
* follows with a pending test (`tested`). Worker loops poll for termination
|
|
40
|
+
* every 64 iterations (emitWorkerLoopCheck) so that a loop whose body calls
|
|
41
|
+
* nothing that tests still observes a terminate request; a pending test reads
|
|
42
|
+
* the same alert word, so a loop that always runs one needs no extra poll.
|
|
43
|
+
* The tested call must be unconditional: in the condition (while, for), in
|
|
44
|
+
* the update or the do-while condition (both run after `continue` too), or
|
|
45
|
+
* in the body before any statement that can `continue` this loop. */
|
|
46
|
+
export function loopTestsEveryIteration(loop, tested) {
|
|
47
|
+
const evaluates = (e) => {
|
|
48
|
+
if (tested(e))
|
|
49
|
+
return true;
|
|
50
|
+
if (!EAGER_EXPRS.has(e.kind))
|
|
51
|
+
return false;
|
|
52
|
+
let found = false;
|
|
53
|
+
everyExprChild(e, (child) => !(found = evaluates(child)), () => true);
|
|
54
|
+
return found;
|
|
55
|
+
};
|
|
56
|
+
const statementEvaluates = (s) => {
|
|
57
|
+
if (s.kind === "if")
|
|
58
|
+
return evaluates(s.cond);
|
|
59
|
+
if (s.kind === "block")
|
|
60
|
+
return s.body.some(statementEvaluates);
|
|
61
|
+
if (!EAGER_STMTS.has(s.kind))
|
|
62
|
+
return false;
|
|
63
|
+
let found = false;
|
|
64
|
+
everyStmtChild(s, (child) => !(found = evaluates(child)), () => true);
|
|
65
|
+
return found;
|
|
66
|
+
};
|
|
67
|
+
const labels = new Set(loop.labels ?? []);
|
|
68
|
+
// Can `s` jump to this loop's next iteration? Unlabeled continues bind to
|
|
69
|
+
// the innermost enclosing loop; labeled ones may skip out of nested loops.
|
|
70
|
+
const continues = (s, nested) => {
|
|
71
|
+
if (s.kind === "continue")
|
|
72
|
+
return s.label === undefined ? !nested : labels.has(s.label);
|
|
73
|
+
const inner = nested ||
|
|
74
|
+
s.kind === "while" ||
|
|
75
|
+
s.kind === "doWhile" ||
|
|
76
|
+
s.kind === "for" ||
|
|
77
|
+
s.kind === "forOf";
|
|
78
|
+
let found = false;
|
|
79
|
+
everyStmtChild(s, () => true, (child) => !(found = continues(child, inner)));
|
|
80
|
+
return found;
|
|
81
|
+
};
|
|
82
|
+
if (loop.kind === "while" && evaluates(loop.cond))
|
|
83
|
+
return true;
|
|
84
|
+
if (loop.kind === "doWhile" && evaluates(loop.cond))
|
|
85
|
+
return true;
|
|
86
|
+
if (loop.kind === "for") {
|
|
87
|
+
if (loop.cond !== null && evaluates(loop.cond))
|
|
88
|
+
return true;
|
|
89
|
+
if (loop.update !== null && statementEvaluates(loop.update))
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
for (const s of loop.body) {
|
|
93
|
+
if (continues(s, false))
|
|
94
|
+
return false;
|
|
95
|
+
if (statementEvaluates(s))
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=loop-polls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-polls.js","sourceRoot":"","sources":["../../src/backend/loop-polls.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAInE;0DAC0D;AAC1D,MAAM,WAAW,GAAwB,IAAI,GAAG,CAAC;IAC/C,MAAM;IACN,KAAK;IACL,aAAa;IACb,WAAW;IACX,KAAK;IACL,OAAO;IACP,QAAQ;IACR,WAAW;IACX,OAAO;IACP,QAAQ;IACR,YAAY;IACZ,UAAU;IACV,aAAa;IACb,UAAU;IACV,WAAW;IACX,QAAQ;IACR,UAAU;IACV,WAAW;IACX,SAAS;CACV,CAAC,CAAC;AAEH;WACW;AACX,MAAM,WAAW,GAAwB,IAAI,GAAG,CAAC;IAC/C,SAAS;IACT,QAAQ;IACR,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,WAAW;IACX,QAAQ;IACR,OAAO;CACR,CAAC,CAAC;AAEH;;;;;;;qEAOqE;AACrE,MAAM,UAAU,uBAAuB,CAAC,IAAU,EAAE,MAAiC;IACnF,MAAM,SAAS,GAAG,CAAC,CAAS,EAAW,EAAE;QACvC,IAAI,MAAM,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC3B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAC3C,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,cAAc,CACZ,CAAC,EACD,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EACtC,GAAG,EAAE,CAAC,IAAI,CACX,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,MAAM,kBAAkB,GAAG,CAAC,CAAS,EAAW,EAAE;QAChD,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/D,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAC3C,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,cAAc,CACZ,CAAC,EACD,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EACtC,GAAG,EAAE,CAAC,IAAI,CACX,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC1C,0EAA0E;IAC1E,2EAA2E;IAC3E,MAAM,SAAS,GAAG,CAAC,CAAS,EAAE,MAAe,EAAW,EAAE;QACxD,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU;YAAE,OAAO,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxF,MAAM,KAAK,GACT,MAAM;YACN,CAAC,CAAC,IAAI,KAAK,OAAO;YAClB,CAAC,CAAC,IAAI,KAAK,SAAS;YACpB,CAAC,CAAC,IAAI,KAAK,KAAK;YAChB,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC;QACrB,IAAI,KAAK,GAAG,KAAK,CAAC;QAClB,cAAc,CACZ,CAAC,EACD,GAAG,EAAE,CAAC,IAAI,EACV,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAC9C,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/D,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACjE,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACxB,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QAC5D,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,IAAI,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;IAC3E,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QAC1B,IAAI,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QACtC,IAAI,kBAAkB,CAAC,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;IACzC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import { BOOL, F64, VOID } from "../ir/ir.js";
|
|
3
|
+
import { loopTestsEveryIteration } from "./loop-polls.js";
|
|
4
|
+
const loc = { file: "loops.ts", start: 0, end: 1 };
|
|
5
|
+
const call = (callee) => ({ kind: "call", callee, args: [], type: F64, loc });
|
|
6
|
+
const stmt = (expr) => ({ kind: "exprStmt", expr, loc });
|
|
7
|
+
const yes = { kind: "boolLit", value: true, type: BOOL, loc };
|
|
8
|
+
const tested = (e) => e.kind === "call" && e.callee === "throws";
|
|
9
|
+
const whileLoop = (body, cond = yes, labels) => ({
|
|
10
|
+
kind: "while",
|
|
11
|
+
cond,
|
|
12
|
+
body,
|
|
13
|
+
loc,
|
|
14
|
+
...(labels ? { labels } : {}),
|
|
15
|
+
});
|
|
16
|
+
const answer = (loop) => loopTestsEveryIteration(loop, tested);
|
|
17
|
+
const ifThen = (body) => ({
|
|
18
|
+
kind: "if",
|
|
19
|
+
cond: yes,
|
|
20
|
+
then: body,
|
|
21
|
+
else_: null,
|
|
22
|
+
loc,
|
|
23
|
+
});
|
|
24
|
+
const sum = (left, right) => ({
|
|
25
|
+
kind: "bin",
|
|
26
|
+
op: "+",
|
|
27
|
+
left,
|
|
28
|
+
right,
|
|
29
|
+
type: F64,
|
|
30
|
+
loc,
|
|
31
|
+
});
|
|
32
|
+
test("an unconditional tested call in the body or condition replaces the poll", () => {
|
|
33
|
+
expect(answer(whileLoop([stmt(call("throws"))]))).toBe(true);
|
|
34
|
+
expect(answer(whileLoop([stmt(sum(call("pure"), call("throws")))]))).toBe(true);
|
|
35
|
+
expect(answer(whileLoop([], { kind: "toBool", operand: call("throws"), type: BOOL, loc }))).toBe(true);
|
|
36
|
+
// Untested calls and calls behind a condition or short circuit do not.
|
|
37
|
+
expect(answer(whileLoop([stmt(call("pure"))]))).toBe(false);
|
|
38
|
+
expect(answer(whileLoop([ifThen([stmt(call("throws"))])]))).toBe(false);
|
|
39
|
+
const shortCircuit = {
|
|
40
|
+
kind: "logical",
|
|
41
|
+
op: "&&",
|
|
42
|
+
left: yes,
|
|
43
|
+
right: call("throws"),
|
|
44
|
+
type: BOOL,
|
|
45
|
+
loc,
|
|
46
|
+
};
|
|
47
|
+
expect(answer(whileLoop([stmt(shortCircuit)]))).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
test("a continue before the tested call keeps the poll", () => {
|
|
50
|
+
const skip = { kind: "continue", loc };
|
|
51
|
+
expect(answer(whileLoop([ifThen([skip]), stmt(call("throws"))]))).toBe(false);
|
|
52
|
+
// After the call, or bound to a nested loop, a continue is harmless.
|
|
53
|
+
expect(answer(whileLoop([stmt(call("throws")), ifThen([skip])]))).toBe(true);
|
|
54
|
+
expect(answer(whileLoop([whileLoop([skip]), stmt(call("throws"))]))).toBe(true);
|
|
55
|
+
// A labeled continue out of a nested loop still skips this iteration.
|
|
56
|
+
const labeled = { kind: "continue", label: "outer", loc };
|
|
57
|
+
expect(answer(whileLoop([whileLoop([labeled]), stmt(call("throws"))], yes, ["outer"]))).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
test("for updates and do-while conditions run after every continue", () => {
|
|
60
|
+
const skip = { kind: "continue", loc };
|
|
61
|
+
const forLoop = {
|
|
62
|
+
kind: "for",
|
|
63
|
+
init: null,
|
|
64
|
+
cond: null,
|
|
65
|
+
update: stmt(call("throws")),
|
|
66
|
+
body: [ifThen([skip])],
|
|
67
|
+
loc,
|
|
68
|
+
};
|
|
69
|
+
expect(answer(forLoop)).toBe(true);
|
|
70
|
+
const doWhile = {
|
|
71
|
+
kind: "doWhile",
|
|
72
|
+
body: [ifThen([skip])],
|
|
73
|
+
cond: { kind: "toBool", operand: call("throws"), type: BOOL, loc },
|
|
74
|
+
loc,
|
|
75
|
+
};
|
|
76
|
+
expect(answer(doWhile)).toBe(true);
|
|
77
|
+
const forOf = {
|
|
78
|
+
kind: "forOf",
|
|
79
|
+
localId: "x",
|
|
80
|
+
iterable: { kind: "varRef", localId: "xs", type: { kind: "array", elem: F64 }, loc },
|
|
81
|
+
body: [stmt({ kind: "call", callee: "throws", args: [], type: VOID, loc })],
|
|
82
|
+
loc,
|
|
83
|
+
};
|
|
84
|
+
expect(answer(forOf)).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=loop-polls.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop-polls.test.js","sourceRoot":"","sources":["../../src/backend/loop-polls.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,19 @@
|
|
|
1
|
-
import type { IrModule } from "../ir/ir.js";
|
|
1
|
+
import type { IrStmt, IrModule, SrcLoc } from "../ir/ir.js";
|
|
2
|
+
/** Why a function may throw (computeMayThrow's `explain` option): its own
|
|
3
|
+
* throwing operation, or the first call edge to a function that may throw. */
|
|
4
|
+
export type MayThrowReason = {
|
|
5
|
+
kind: "seed";
|
|
6
|
+
what: string;
|
|
7
|
+
loc: SrcLoc | null;
|
|
8
|
+
} | {
|
|
9
|
+
kind: "call";
|
|
10
|
+
callee: string;
|
|
11
|
+
loc: SrcLoc | null;
|
|
12
|
+
} | {
|
|
13
|
+
kind: "indirect";
|
|
14
|
+
target: string;
|
|
15
|
+
loc: SrcLoc | null;
|
|
16
|
+
};
|
|
2
17
|
/** Cheap may-throw analysis (cost discipline: functions that transitively
|
|
3
18
|
* CANNOT throw pay for no pending-exception checks). A function may throw
|
|
4
19
|
* iff it contains a `throw`, calls a may-throw function (direct `call` or
|
|
@@ -8,11 +23,23 @@ import type { IrModule } from "../ir/ir.js";
|
|
|
8
23
|
* Fixpoint over the call graph; runtime traps (array OOB etc.) are aborts,
|
|
9
24
|
* not exceptions, so most intrinsics never contribute. The module evaluator's
|
|
10
25
|
* internal await and throwing library calls are the exceptions: both can
|
|
11
|
-
* surface a catchable rejection/error and seed the fixpoint like a `throw`.
|
|
26
|
+
* surface a catchable rejection/error and seed the fixpoint like a `throw`.
|
|
27
|
+
*
|
|
28
|
+
* Handlers discharge what they handle: a throwing operation or call inside
|
|
29
|
+
* a `try` with a `catch`, or inside a `try`/`catch` whose `finally` never
|
|
30
|
+
* completes normally (it returns, breaks or continues, which discards the
|
|
31
|
+
* pending exception), cannot propagate out of that statement, so it adds no
|
|
32
|
+
* seed and no call edge. The `catch` and `finally` bodies themselves are
|
|
33
|
+
* analyzed like any other code, which keeps rethrows exact. Worker programs
|
|
34
|
+
* and generator bodies keep the conservative answer: a termination request
|
|
35
|
+
* and a generator's `.return()` unwind through `catch`. */
|
|
12
36
|
export declare function computeMayThrow(mod: IrModule, options?: {
|
|
13
37
|
stackChecks?: boolean;
|
|
38
|
+
explain?: boolean;
|
|
14
39
|
}): {
|
|
15
40
|
fns: Set<string>;
|
|
41
|
+
/** With `explain`: the reason each may-throw function was marked. */
|
|
42
|
+
why?: Map<string, MayThrowReason>;
|
|
16
43
|
indirect: boolean;
|
|
17
44
|
/** Worker programs: the functions that poll for termination on entry. */
|
|
18
45
|
workerEntryPolls?: Set<string>;
|
|
@@ -20,6 +47,13 @@ export declare function computeMayThrow(mod: IrModule, options?: {
|
|
|
20
47
|
* entry (and may therefore throw the stack-overflow RangeError). */
|
|
21
48
|
stackChecks?: Set<string>;
|
|
22
49
|
};
|
|
50
|
+
/** Whether control can reach the end of a statement list. Conservative:
|
|
51
|
+
* false only when some statement certainly completes abruptly: `return`,
|
|
52
|
+
* `throw`, `break` or `continue` (which leave the list), an `if` whose
|
|
53
|
+
* branches both do, a `try` whose body and `catch` (or `finally`) do, a
|
|
54
|
+
* `switch` with a `default` whose last case does and that no `break`
|
|
55
|
+
* leaves, or a `while (true)`/`for (;;)` loop that no `break` leaves. */
|
|
56
|
+
export declare function completesNormally(stmts: readonly IrStmt[]): boolean;
|
|
23
57
|
/** Where a worker program must poll for termination so that every unbounded
|
|
24
58
|
* execution observes it promptly: every loop polls on entry and then in
|
|
25
59
|
* bounded batches, and a function polls on entry unless it is bounded. A
|