@scriptc/compiler 0.2.1 → 0.2.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 +158 -31
- package/dist/backend/cycle-analysis.js +63 -50
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +51 -0
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/llvm/borrowed-receivers.d.ts +9 -0
- package/dist/backend/llvm/borrowed-receivers.js +58 -0
- package/dist/backend/llvm/borrowed-receivers.js.map +1 -0
- package/dist/backend/llvm/call-lifetimes.d.ts +20 -0
- package/dist/backend/llvm/call-lifetimes.js +179 -0
- package/dist/backend/llvm/call-lifetimes.js.map +1 -0
- package/dist/backend/llvm/call-lifetimes.test.d.ts +1 -0
- package/dist/backend/llvm/call-lifetimes.test.js +205 -0
- package/dist/backend/llvm/call-lifetimes.test.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +5 -2
- package/dist/backend/llvm/dyn.js +163 -47
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +37 -1
- package/dist/backend/llvm/emitter.js +209 -21
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +29 -2
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +1 -1
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-calls.js +42 -5
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +75 -13
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +31 -6
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +6 -5
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-records.js +1 -1
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +75 -19
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-callbacks.d.ts +2 -2
- package/dist/backend/llvm/expr-stream-callbacks.js +7 -57
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +41 -3
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +12 -9
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +70 -2
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.d.ts +44 -0
- package/dist/backend/llvm/local-array-reads.js +313 -0
- package/dist/backend/llvm/local-array-reads.js.map +1 -0
- package/dist/backend/llvm/local-array-reads.test.d.ts +1 -0
- package/dist/backend/llvm/local-array-reads.test.js +446 -0
- package/dist/backend/llvm/local-array-reads.test.js.map +1 -0
- package/dist/backend/llvm/map-read-lifetimes.d.ts +36 -0
- package/dist/backend/llvm/map-read-lifetimes.js +128 -0
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -0
- package/dist/backend/llvm/map-read-lifetimes.test.d.ts +1 -0
- package/dist/backend/llvm/map-read-lifetimes.test.js +123 -0
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -0
- package/dist/backend/llvm/shapes.js +1 -0
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/split.js +15 -5
- package/dist/backend/llvm/split.js.map +1 -1
- package/dist/backend/llvm/split.test.js +17 -0
- package/dist/backend/llvm/split.test.js.map +1 -1
- package/dist/backend/llvm/stack-unions.d.ts +20 -0
- package/dist/backend/llvm/stack-unions.js +61 -0
- package/dist/backend/llvm/stack-unions.js.map +1 -0
- package/dist/backend/llvm/stack-unions.test.d.ts +1 -0
- package/dist/backend/llvm/stack-unions.test.js +241 -0
- package/dist/backend/llvm/stack-unions.test.js.map +1 -0
- package/dist/backend/llvm/string-lifetimes.d.ts +12 -0
- package/dist/backend/llvm/string-lifetimes.js +70 -0
- package/dist/backend/llvm/string-lifetimes.js.map +1 -0
- package/dist/backend/llvm/string-lifetimes.test.d.ts +1 -0
- package/dist/backend/llvm/string-lifetimes.test.js +230 -0
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -0
- package/dist/backend/mangle.d.ts +2 -0
- package/dist/backend/mangle.js +4 -0
- package/dist/backend/mangle.js.map +1 -1
- package/dist/backend/may-throw.js +71 -29
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +104 -1
- package/dist/backend/may-throw.test.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +1 -1
- package/dist/backend/native-codegen.js +4 -3
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +11 -0
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-toolchain.d.ts +2 -2
- package/dist/backend/native-toolchain.js +2 -0
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/target-diagnostics.d.ts +5 -0
- package/dist/backend/target-diagnostics.js +72 -1
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/target-diagnostics.test.d.ts +1 -0
- package/dist/backend/target-diagnostics.test.js +68 -0
- package/dist/backend/target-diagnostics.test.js.map +1 -0
- package/dist/coverage/surface-manifest.js +5 -3
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +7 -3
- package/dist/executable/executable-cache.js +47 -11
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +109 -2
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/executable/prepare.js +2 -1
- package/dist/executable/prepare.js.map +1 -1
- package/dist/frontend/builtin-modules.d.ts +1 -1
- package/dist/frontend/builtin-modules.js +1 -1
- package/dist/frontend/builtin-modules.js.map +1 -1
- package/dist/frontend/function-completion.d.ts +6 -0
- package/dist/frontend/function-completion.js +50 -0
- package/dist/frontend/function-completion.js.map +1 -0
- package/dist/frontend/input-tracker.js +3 -3
- package/dist/frontend/input-tracker.js.map +1 -1
- package/dist/frontend/input-tracker.test.js +38 -2
- package/dist/frontend/input-tracker.test.js.map +1 -1
- package/dist/frontend/lowering/abstract-equality.js +5 -1
- package/dist/frontend/lowering/abstract-equality.js.map +1 -1
- package/dist/frontend/lowering/checked-iterable-spread.d.ts +4 -0
- package/dist/frontend/lowering/checked-iterable-spread.js +30 -0
- package/dist/frontend/lowering/checked-iterable-spread.js.map +1 -0
- package/dist/frontend/lowering/checked-promise-all.d.ts +5 -0
- package/dist/frontend/lowering/checked-promise-all.js +31 -0
- package/dist/frontend/lowering/checked-promise-all.js.map +1 -0
- package/dist/frontend/lowering/class-callbacks.d.ts +1 -1
- package/dist/frontend/lowering/class-callbacks.js +7 -6
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-construction.d.ts +2 -0
- package/dist/frontend/lowering/class-construction.js +34 -5
- package/dist/frontend/lowering/class-construction.js.map +1 -1
- package/dist/frontend/lowering/class-descriptors.d.ts +1 -1
- package/dist/frontend/lowering/class-descriptors.js +12 -5
- package/dist/frontend/lowering/class-descriptors.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +25 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.js +597 -78
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +64 -2
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -1
- package/dist/frontend/lowering/class-instance-constructor.d.ts +1 -1
- package/dist/frontend/lowering/class-instance-constructor.js +11 -41
- package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
- package/dist/frontend/lowering/class-method-values.d.ts +16 -0
- package/dist/frontend/lowering/class-method-values.js +60 -29
- package/dist/frontend/lowering/class-method-values.js.map +1 -1
- package/dist/frontend/lowering/class-prototypes.d.ts +5 -1
- package/dist/frontend/lowering/class-prototypes.js +69 -10
- package/dist/frontend/lowering/class-prototypes.js.map +1 -1
- package/dist/frontend/lowering/class-runtime-statics.d.ts +4 -4
- package/dist/frontend/lowering/class-runtime-statics.js +26 -8
- package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
- package/dist/frontend/lowering/class-static-data.d.ts +1 -0
- package/dist/frontend/lowering/class-static-data.js +4 -2
- package/dist/frontend/lowering/class-static-data.js.map +1 -1
- package/dist/frontend/lowering/collection-ingestion.d.ts +31 -0
- package/dist/frontend/lowering/collection-ingestion.js +215 -0
- package/dist/frontend/lowering/collection-ingestion.js.map +1 -0
- package/dist/frontend/lowering/containers/bytes.js +19 -4
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +6 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/deferred-module-initializers.d.ts +13 -0
- package/dist/frontend/lowering/deferred-module-initializers.js +410 -0
- package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.d.ts +1 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.js +92 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -0
- package/dist/frontend/lowering/expressions/object-literals.js +31 -1
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.js +3 -3
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/import-meta.d.ts +10 -0
- package/dist/frontend/lowering/import-meta.js +52 -0
- package/dist/frontend/lowering/import-meta.js.map +1 -0
- package/dist/frontend/lowering/lower-assert.js +105 -41
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.d.ts +2 -0
- package/dist/frontend/lowering/lower-builtin-values.js +22 -1
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +7 -22
- package/dist/frontend/lowering/lower-builtins.js +439 -95
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +289 -76
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +5 -0
- package/dist/frontend/lowering/lower-classes.js +443 -29
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +6 -2
- package/dist/frontend/lowering/lower-containers.js +79 -20
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +10 -6
- package/dist/frontend/lowering/lower-exprs.js +329 -170
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.js +5 -1
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +58 -1
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +4 -0
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-island.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-island.test.js +51 -0
- package/dist/frontend/lowering/lower-island.test.js.map +1 -0
- package/dist/frontend/lowering/lower-modules.d.ts +1 -3
- package/dist/frontend/lowering/lower-modules.js +186 -82
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.test.js +69 -1
- package/dist/frontend/lowering/lower-modules.test.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +172 -103
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-stmts.test.js +77 -0
- package/dist/frontend/lowering/lower-stmts.test.js.map +1 -0
- package/dist/frontend/lowering/lower-stream.js +2 -0
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-system-errors.d.ts +6 -0
- package/dist/frontend/lowering/lower-system-errors.js +29 -0
- package/dist/frontend/lowering/lower-system-errors.js.map +1 -0
- package/dist/frontend/lowering/lower-url.d.ts +2 -1
- package/dist/frontend/lowering/lower-url.js +32 -9
- package/dist/frontend/lowering/lower-url.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +30 -12
- package/dist/frontend/lowering/lowerer.js +268 -49
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.js +38 -0
- package/dist/frontend/lowering/lowerer.test.js.map +1 -1
- package/dist/frontend/lowering/module-namespace-elements.d.ts +7 -0
- package/dist/frontend/lowering/module-namespace-elements.js +54 -0
- package/dist/frontend/lowering/module-namespace-elements.js.map +1 -0
- package/dist/frontend/lowering/object-factory-new.d.ts +4 -3
- package/dist/frontend/lowering/object-factory-new.js +27 -14
- package/dist/frontend/lowering/object-factory-new.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +3 -2
- package/dist/frontend/lowering/surfaces.js +93 -33
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/text-decoder-encoding.js +3 -0
- package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -1
- package/dist/frontend/lowering/text-decoder-encoding.test.js +2 -1
- package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -1
- package/dist/frontend/module-syntax.d.ts +1 -1
- package/dist/frontend/module-syntax.js +8 -1
- package/dist/frontend/module-syntax.js.map +1 -1
- package/dist/frontend/module-syntax.test.js +10 -0
- package/dist/frontend/module-syntax.test.js.map +1 -1
- package/dist/frontend/npm.d.ts +4 -0
- package/dist/frontend/npm.js +86 -33
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/npm.test.js +103 -0
- package/dist/frontend/npm.test.js.map +1 -1
- package/dist/frontend/pipeline-native.js +2 -1
- package/dist/frontend/pipeline-native.js.map +1 -1
- package/dist/frontend/program.js +4 -2
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/services-node.js +3 -2
- package/dist/frontend/services-node.js.map +1 -1
- package/dist/frontend/services.d.ts +5 -1
- package/dist/frontend/services.js +9 -1
- package/dist/frontend/services.js.map +1 -1
- package/dist/frontend/services.test.js +21 -0
- package/dist/frontend/services.test.js.map +1 -1
- package/dist/frontend/ts7/ast-node.d.ts +2 -0
- package/dist/frontend/ts7/ast-node.js +30 -4
- package/dist/frontend/ts7/ast-node.js.map +1 -1
- package/dist/frontend/ts7/ast-node.test.js +60 -1
- package/dist/frontend/ts7/ast-node.test.js.map +1 -1
- package/dist/frontend/type-mapper.js +89 -14
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/union-discriminants.js +22 -7
- package/dist/frontend/union-discriminants.js.map +1 -1
- package/dist/index.js +19 -12
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.js +1 -0
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/integer-loops.d.ts +7 -0
- package/dist/ir/integer-loops.js +23 -0
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-loops.test.d.ts +1 -0
- package/dist/ir/integer-loops.test.js +41 -0
- package/dist/ir/integer-loops.test.js.map +1 -0
- package/dist/ir/ir.d.ts +44 -26
- package/dist/ir/ir.js +69 -11
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +18 -0
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/serialize.js +21 -1
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +21 -0
- package/dist/ir/serialize.test.js.map +1 -1
- package/dist/ir/traverse.d.ts +0 -3
- package/dist/ir/traverse.js +33 -20
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +216 -80
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +244 -1
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/compiler-self-identity.js +1 -1
- package/dist/library/compiler-self-identity.test.js +2 -2
- package/dist/library/compiler-self-identity.test.js.map +1 -1
- package/dist/library/fence-eval.js +9 -2
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/fence-eval.test.d.ts +1 -0
- package/dist/library/fence-eval.test.js +21 -0
- package/dist/library/fence-eval.test.js.map +1 -0
- package/dist/library/int-infer.d.ts +2 -2
- package/dist/library/int-infer.js +10 -7
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +44 -0
- package/dist/library/int-infer.test.js.map +1 -1
- package/dist/library/prepare.js +2 -1
- package/dist/library/prepare.js.map +1 -1
- package/dist/native/runtime-typescript.d.ts +4 -0
- package/dist/native/runtime-typescript.js +61 -0
- package/dist/native/runtime-typescript.js.map +1 -0
- package/dist/native/runtime-typescript.test.d.ts +1 -0
- package/dist/native/runtime-typescript.test.js +41 -0
- package/dist/native/runtime-typescript.test.js.map +1 -0
- package/package.json +20 -20
- package/surface-manifest.json +385 -29
|
@@ -2,7 +2,10 @@ import type { IrBytesElem, IrExpr, IrFfiImport, IrFunction, IrLocal, IrModule, I
|
|
|
2
2
|
import { type IntegerRanges } from "../../ir/integer-ranges.js";
|
|
3
3
|
import { type ConstantNumericTable } from "../../ir/constant-tables.js";
|
|
4
4
|
import { type FfiCallbackAdapter } from "../ffi-callbacks.js";
|
|
5
|
+
import { type CallLifetimes } from "./call-lifetimes.js";
|
|
5
6
|
import { BlockBuilder } from "./blocks.js";
|
|
7
|
+
import { type LocalArrayRead } from "./local-array-reads.js";
|
|
8
|
+
import { type MapReadLifetimes } from "./map-read-lifetimes.js";
|
|
6
9
|
import { type LlClassMeta } from "./classes.js";
|
|
7
10
|
import { LlDyn, type DynHost } from "./dyn.js";
|
|
8
11
|
import { LlWalkers } from "./walkers.js";
|
|
@@ -25,8 +28,23 @@ export interface LlvmTargetOptions {
|
|
|
25
28
|
runtimeAbiMarker?: boolean;
|
|
26
29
|
}
|
|
27
30
|
export declare function emitLlvmModule(mod: IrModule, options?: LlvmTargetOptions): string;
|
|
31
|
+
/** Keep large translation units below the host's single-string limit. */
|
|
32
|
+
export declare function emitLlvmModuleSource(mod: IrModule, options?: LlvmTargetOptions): string | readonly string[];
|
|
28
33
|
export declare class LlEmitter {
|
|
29
34
|
readonly mod: IrModule;
|
|
35
|
+
localArrayReads: Map<string, LocalArrayRead>;
|
|
36
|
+
private localStackUnions;
|
|
37
|
+
integerArrayBindings: Set<string>;
|
|
38
|
+
private readonly fieldAliasTags;
|
|
39
|
+
private readonly fieldPointerTags;
|
|
40
|
+
/** Native class fields with different property names cannot occupy the
|
|
41
|
+
* same slot of one object. Inherited views of the same property share a
|
|
42
|
+
* tag. Array storage has its own disjoint categories; untagged runtime
|
|
43
|
+
* operations and record views conservatively alias all of them. */
|
|
44
|
+
private markFieldPointer;
|
|
45
|
+
markMemoryPointer(ptr: string, field: string): void;
|
|
46
|
+
fieldAliasAttachment(ptr: string): string;
|
|
47
|
+
private fieldAliasMetadata;
|
|
30
48
|
private readonly debug;
|
|
31
49
|
private debugScope;
|
|
32
50
|
readonly sizeType: "i32" | "i64";
|
|
@@ -82,6 +100,12 @@ export declare class LlEmitter {
|
|
|
82
100
|
needsBadKey: boolean;
|
|
83
101
|
private needsRetainBox;
|
|
84
102
|
readonly fnByName: Map<string, IrFunction>;
|
|
103
|
+
private readonly arrayPreservingFunctions;
|
|
104
|
+
private readonly optionalArrayReads;
|
|
105
|
+
callArrayReads: Map<IrExpr, LocalArrayRead>;
|
|
106
|
+
mapReadLifetimes: MapReadLifetimes;
|
|
107
|
+
readonly callLifetimes: CallLifetimes;
|
|
108
|
+
private borrowedParameters;
|
|
85
109
|
/** Manifest-bound native imports, used by ffiCall emission. */
|
|
86
110
|
readonly ffiByName: Map<string, IrFfiImport>;
|
|
87
111
|
/** C-ABI callback trampolines and (for raw/no-userdata callbacks) their
|
|
@@ -216,6 +240,7 @@ export declare class LlEmitter {
|
|
|
216
240
|
* outer native call. */
|
|
217
241
|
private emitFfiCallbackDefs;
|
|
218
242
|
emit(): string;
|
|
243
|
+
emitParts(): string[];
|
|
219
244
|
/** LIBRARY mode: the profile-declared external definitions — the
|
|
220
245
|
* export-map wrappers plus init / sink-registration / reset / collect.
|
|
221
246
|
* Plain `define` (not `define internal`) — the exact linkage distinction
|
|
@@ -409,6 +434,16 @@ export declare class LlEmitter {
|
|
|
409
434
|
/** Move a clean async return value into the current fiber's promise. */
|
|
410
435
|
private emitWasiFulfill;
|
|
411
436
|
private emitFunction;
|
|
437
|
+
/** Keep the ordinary owned ABI for closures, virtual dispatch, generated
|
|
438
|
+
* runtime adapters and library exports. Only direct IR calls select the
|
|
439
|
+
* borrowing body. Ownership of other parameters moves into that body;
|
|
440
|
+
* borrowed parameters are released here on normal and exceptional exits.
|
|
441
|
+
* The pending exception remains for the adapter's caller to handle. */
|
|
442
|
+
private emitOwnedCallAdapter;
|
|
443
|
+
/** A local immutable binding keeps its value alive while later arguments
|
|
444
|
+
* and the callee execute. Global, captured, TDZ and mutable bindings need
|
|
445
|
+
* an owned snapshot, even when the callee only inspects the value. */
|
|
446
|
+
canBorrowCallArgument(value: IrExpr): boolean;
|
|
412
447
|
private emitStmts;
|
|
413
448
|
/** Emits a block in its own lexical scope (refcounted locals released at
|
|
414
449
|
* end). `setup` runs after the
|
|
@@ -484,6 +519,7 @@ export declare class LlEmitter {
|
|
|
484
519
|
* their ordinary statement-frame ownership. The caller must retain any
|
|
485
520
|
* reference result before evaluating another expression. */
|
|
486
521
|
emitReadReceiver(e: IrExpr): LlValue;
|
|
522
|
+
canBorrowReceiver(e: IrExpr): boolean;
|
|
487
523
|
emitExpr(e: IrExpr): LlValue;
|
|
488
524
|
emitJsMarshal(e: IrExpr & {
|
|
489
525
|
kind: "jsMarshal";
|
|
@@ -538,7 +574,7 @@ export declare class LlEmitter {
|
|
|
538
574
|
}): string;
|
|
539
575
|
cryptoBytesThunkFor(cbT: IrType & {
|
|
540
576
|
kind: "func";
|
|
541
|
-
}): string;
|
|
577
|
+
}, arrayBuffer?: boolean): string;
|
|
542
578
|
zlibBytesThunkFor(cbT: IrType & {
|
|
543
579
|
kind: "func";
|
|
544
580
|
}): string;
|
|
@@ -22,7 +22,7 @@ import { deflateRawSync } from "node:zlib";
|
|
|
22
22
|
import { endsWithJump, matchStringSelfConcat, streamTypedRefEligible } from "../../ir/analysis.js";
|
|
23
23
|
import { emitLibraryIdentityLines } from "../library-identity-markers.js";
|
|
24
24
|
import { CAUGHT, ffiCallbackType, isDynTypedRefType, isFfiContextParam, isRefCounted, isUnitType, moduleRuntimeFeatures, moduleEmbedsBuiltin, moduleEmbedsCompressedNpm, NPM_COMPRESS_MIN, POINTER_KINDS, RUNTIME_EMITTER_CLASS, RUNTIME_ERROR_CLASSES, RUNTIME_STREAM_CLASSES, typeKey, VOID } from "../../ir/ir.js";
|
|
25
|
-
import { matchIntegerBytesForLoop } from "../../ir/integer-loops.js";
|
|
25
|
+
import { matchIntegerArrayForLoop, matchIntegerBytesForLoop } from "../../ir/integer-loops.js";
|
|
26
26
|
import { scalarizeNumericRecords } from "../../ir/scalar-records.js";
|
|
27
27
|
import { everyStmtList } from "../../ir/traverse.js";
|
|
28
28
|
import { analyzeIntegerRanges } from "../../ir/integer-ranges.js";
|
|
@@ -30,8 +30,13 @@ import { findConstantNumericTables } from "../../ir/constant-tables.js";
|
|
|
30
30
|
import { allocateFfiCallbackAdapters, hasForeignFfiCallback, hasRetainedFfiCallback } from "../ffi-callbacks.js";
|
|
31
31
|
import { RUNTIME_ABI_MARKER } from "../runtime-abi.js";
|
|
32
32
|
import { computeMayThrow } from "../may-throw.js";
|
|
33
|
-
import { mangleArgPack, mangleAsyncSpawn, mangleClassObj, mangleClassStruct, mangleFnClosure, mangleFunction, mangleGenDrop, mangleGenSpawn, mangleGlobal, mangleLocal, mangleRecordStruct, mangleTrampoline, mangleWrapper, mangleVtInstance } from "../mangle.js";
|
|
33
|
+
import { mangleArgPack, mangleAsyncSpawn, mangleBorrowedFunction, mangleClassObj, mangleClassStruct, mangleFnClosure, mangleFunction, mangleGenDrop, mangleGenSpawn, mangleGlobal, mangleLocal, mangleRecordStruct, mangleTrampoline, mangleWrapper, mangleVtInstance } from "../mangle.js";
|
|
34
|
+
import { analyzeCallLifetimes } from "./call-lifetimes.js";
|
|
35
|
+
import { emitStackUnion, findLocalStackUnions } from "./stack-unions.js";
|
|
34
36
|
import { BlockBuilder } from "./blocks.js";
|
|
37
|
+
import { emitLocalArrayRead, findArrayPreservingFunctions, findLocalArrayReads, findCallArrayReads, OptionalArrayReads } from "./local-array-reads.js";
|
|
38
|
+
import { emitStackMapRead, findMapReadLifetimes } from "./map-read-lifetimes.js";
|
|
39
|
+
import { emitBorrowedFieldSequence } from "./borrowed-receivers.js";
|
|
35
40
|
import { LlvmDebugInfo } from "./debug-info.js";
|
|
36
41
|
import { f64Lit, ffiNativeTypeLl, ffiNativeParamLl, ffiNativeReturnLl, llvmCommentText } from "./common.js";
|
|
37
42
|
import { ffiExtendsNarrowIntegers } from "../targets.js";
|
|
@@ -88,11 +93,54 @@ export function emitLlvmModule(mod, options = {}) {
|
|
|
88
93
|
// Keep source storage intact for debugger inspection in dev builds.
|
|
89
94
|
return new LlEmitter(options.debugSources === undefined ? scalarizeNumericRecords(mod) : mod, options).emit();
|
|
90
95
|
}
|
|
96
|
+
/** Keep large translation units below the host's single-string limit. */
|
|
97
|
+
export function emitLlvmModuleSource(mod, options = {}) {
|
|
98
|
+
const parts = new LlEmitter(options.debugSources === undefined ? scalarizeNumericRecords(mod) : mod, options).emitParts();
|
|
99
|
+
const length = parts.reduce((total, part) => total + part.length, Math.max(0, parts.length - 1));
|
|
100
|
+
if (length <= 256 * 1024 * 1024)
|
|
101
|
+
return parts.join("\n");
|
|
102
|
+
return parts.flatMap((part, index) => index === 0 ? [part] : ["\n", part]);
|
|
103
|
+
}
|
|
91
104
|
function llStrBytes(text) {
|
|
92
105
|
return llBytes(Buffer.from(text, "utf8"));
|
|
93
106
|
}
|
|
94
107
|
export class LlEmitter {
|
|
95
108
|
mod;
|
|
109
|
+
localArrayReads = new Map();
|
|
110
|
+
localStackUnions = new Map();
|
|
111
|
+
integerArrayBindings = new Set();
|
|
112
|
+
fieldAliasTags = new Map();
|
|
113
|
+
fieldPointerTags = new Map();
|
|
114
|
+
/** Native class fields with different property names cannot occupy the
|
|
115
|
+
* same slot of one object. Inherited views of the same property share a
|
|
116
|
+
* tag. Array storage has its own disjoint categories; untagged runtime
|
|
117
|
+
* operations and record views conservatively alias all of them. */
|
|
118
|
+
markFieldPointer(ptr, field) {
|
|
119
|
+
this.markMemoryPointer(ptr, `field:${field}`);
|
|
120
|
+
}
|
|
121
|
+
markMemoryPointer(ptr, field) {
|
|
122
|
+
if (this.debug !== null)
|
|
123
|
+
return;
|
|
124
|
+
let tag = this.fieldAliasTags.get(field);
|
|
125
|
+
if (tag === undefined) {
|
|
126
|
+
tag = 2 + this.fieldAliasTags.size * 2;
|
|
127
|
+
this.fieldAliasTags.set(field, tag);
|
|
128
|
+
}
|
|
129
|
+
this.fieldPointerTags.set(ptr, tag);
|
|
130
|
+
}
|
|
131
|
+
fieldAliasAttachment(ptr) {
|
|
132
|
+
const tag = this.fieldPointerTags.get(ptr);
|
|
133
|
+
return tag === undefined ? "" : `, !tbaa !${tag}`;
|
|
134
|
+
}
|
|
135
|
+
fieldAliasMetadata() {
|
|
136
|
+
if (this.fieldAliasTags.size === 0)
|
|
137
|
+
return [];
|
|
138
|
+
const lines = ['!0 = !{!"scriptc native fields"}'];
|
|
139
|
+
for (const tag of this.fieldAliasTags.values()) {
|
|
140
|
+
lines.push(`!${tag - 1} = !{!"field.${tag}", !0, i64 0}`, `!${tag} = !{!${tag - 1}, !${tag - 1}, i64 0}`);
|
|
141
|
+
}
|
|
142
|
+
return lines;
|
|
143
|
+
}
|
|
96
144
|
debug;
|
|
97
145
|
debugScope = null;
|
|
98
146
|
sizeType;
|
|
@@ -141,6 +189,12 @@ export class LlEmitter {
|
|
|
141
189
|
needsBadKey = false;
|
|
142
190
|
needsRetainBox = false;
|
|
143
191
|
fnByName = new Map();
|
|
192
|
+
arrayPreservingFunctions;
|
|
193
|
+
optionalArrayReads;
|
|
194
|
+
callArrayReads = new Map();
|
|
195
|
+
mapReadLifetimes = { locals: new Map(), arguments: new Map() };
|
|
196
|
+
callLifetimes;
|
|
197
|
+
borrowedParameters = new Set();
|
|
144
198
|
/** Manifest-bound native imports, used by ffiCall emission. */
|
|
145
199
|
ffiByName = new Map();
|
|
146
200
|
/** C-ABI callback trampolines and (for raw/no-userdata callbacks) their
|
|
@@ -290,6 +344,9 @@ export class LlEmitter {
|
|
|
290
344
|
}
|
|
291
345
|
for (const u of mod.unions ?? [])
|
|
292
346
|
this.unionsById.set(u.id, u);
|
|
347
|
+
this.optionalArrayReads = new OptionalArrayReads(this.fnByName, this.unionsById);
|
|
348
|
+
this.arrayPreservingFunctions = findArrayPreservingFunctions(this.fnByName, this.unionsById, this.optionalArrayReads);
|
|
349
|
+
this.callLifetimes = analyzeCallLifetimes(this.fnByName);
|
|
293
350
|
for (const r of mod.records ?? [])
|
|
294
351
|
this.recordsById.set(r.id, r);
|
|
295
352
|
const traced = computeTraced(mod);
|
|
@@ -310,6 +367,7 @@ export class LlEmitter {
|
|
|
310
367
|
cstr: (text) => this.cstr(text),
|
|
311
368
|
unitInstanceRef: (unionId, tag) => this.unitInstanceRef(unionId, tag),
|
|
312
369
|
liveDynRefAdapter: (type) => this.liveDynRefAdapter(type),
|
|
370
|
+
liveDynUnionRefAdapter: (type) => this.liveDynUnionRefAdapter(type),
|
|
313
371
|
dynPromiseAdapter: (type) => this.dynPromiseAdapter(type),
|
|
314
372
|
isErrorClass: (name) => this.classMeta.get(name)?.root.def.name === "%Error",
|
|
315
373
|
classSubtypes: (name) => {
|
|
@@ -671,6 +729,9 @@ export class LlEmitter {
|
|
|
671
729
|
return { globals, defs };
|
|
672
730
|
}
|
|
673
731
|
emit() {
|
|
732
|
+
return this.emitParts().join("\n");
|
|
733
|
+
}
|
|
734
|
+
emitParts() {
|
|
674
735
|
// Function bodies first (the literal/unit/fn-value tables fill as they
|
|
675
736
|
// emit), then the file assembles around them — the runtime ABI’s order.
|
|
676
737
|
const fnDefs = [];
|
|
@@ -837,6 +898,7 @@ export class LlEmitter {
|
|
|
837
898
|
this.declare(`declare void @scr_net_island_install()`);
|
|
838
899
|
if (usesIsland) {
|
|
839
900
|
this.declare(`declare void @scr_island_modules(ptr, ${this.sizeType}, ptr, ${this.sizeType})`);
|
|
901
|
+
this.declare(`declare void @scr_island_entry_module(ptr)`);
|
|
840
902
|
this.declare(`declare i32 @scr_island_exit_code()`);
|
|
841
903
|
if (moduleEmbedsCompressedNpm(this.mod)) {
|
|
842
904
|
this.declare(`declare void @scr_island_set_inflate(ptr)`);
|
|
@@ -1104,6 +1166,7 @@ export class LlEmitter {
|
|
|
1104
1166
|
}
|
|
1105
1167
|
if (this.templateStringsInstances.size > 0)
|
|
1106
1168
|
out.push(``);
|
|
1169
|
+
const islandEntryPath = usesIsland ? this.cstr(this.mod.sourceFile) : null;
|
|
1107
1170
|
for (const [text, c] of this.cstrs) {
|
|
1108
1171
|
// NUL-terminated byte-array constants for scr_jb_puts and indentation.
|
|
1109
1172
|
out.push(`@${c.sym} = internal constant [${c.len + 1} x i8] c"${llStrBytes(text)}"`);
|
|
@@ -1177,7 +1240,10 @@ export class LlEmitter {
|
|
|
1177
1240
|
out.push(line);
|
|
1178
1241
|
for (const line of this.resolveThunkDefs)
|
|
1179
1242
|
out.push(line);
|
|
1180
|
-
out.push(fnDefs
|
|
1243
|
+
out.push(fnDefs[0] ?? "");
|
|
1244
|
+
for (let i = 1; i < fnDefs.length; i++)
|
|
1245
|
+
out.push("", fnDefs[i]);
|
|
1246
|
+
out.push("");
|
|
1181
1247
|
// main(): scr_init, the program-dependent error-vt interval stamps,
|
|
1182
1248
|
// scr_lib_init(argc, argv), then the entry function. An uncaught
|
|
1183
1249
|
// exception escaping top-level code prints and exits 1 (Node).
|
|
@@ -1232,9 +1298,10 @@ export class LlEmitter {
|
|
|
1232
1298
|
if (hasNoInlineRecordClone)
|
|
1233
1299
|
out.push(`attributes #2 = { noinline sanitize_address }`);
|
|
1234
1300
|
out.push(``);
|
|
1301
|
+
out.push(...this.fieldAliasMetadata());
|
|
1235
1302
|
if (this.debug !== null)
|
|
1236
1303
|
out.push(this.debug.render());
|
|
1237
|
-
return out
|
|
1304
|
+
return out;
|
|
1238
1305
|
}
|
|
1239
1306
|
out.push(`define i32 @${this.wasi ? "__main_argc_argv" : "main"}(i32 %argc, ptr %argv) ${FN_ATTRS} {`, `entry:`, ...(this.runtimeAbiMarker ? [` call void @${RUNTIME_ABI_MARKER}()`] : []), ` call void @scr_init()`, ...stamps,
|
|
1240
1307
|
// Event-surface programs (signal/exit listeners) fill the loop's
|
|
@@ -1245,6 +1312,7 @@ export class LlEmitter {
|
|
|
1245
1312
|
// scr_watch.c links only when this line is emitted.
|
|
1246
1313
|
...(usesFsWatch ? [` call void @scr_watch_install()`] : []), ...(this.ffiHasForeignCallback ? [` call void @scr_ffi_install()`] : []), ...(snapshotsTlsCa ? [` call void @scr_tls_ca_install()`] : []), ...(usesFetch ? [` call void @scr_fetch_install()`] : []), ...(embedsZlib ? [` call void @scr_zlib_island_install()`] : []), ...(embedsNet ? [` call void @scr_net_island_install()`] : []), ...(usesNet ? [` call void @scr_net_install()`, ` call void @scr_net_dyn_install()`] : []), ...(usesHttp ? [` call void @scr_http_dyn_install()`] : []), ...(usesDgram ? [` call void @scr_dgram_install()`] : []), ...(usesHttp2 ? [` call void @scr_http2_dyn_install()`] : []), ...(usesStream ? [` call void @scr_stream_install()`] : []), ` call void @scr_lib_init(i32 %argc, ptr %argv)`, ...(usesIsland
|
|
1247
1314
|
? [
|
|
1315
|
+
` call void @scr_island_entry_module(ptr ${islandEntryPath})`,
|
|
1248
1316
|
...(moduleEmbedsCompressedNpm(this.mod)
|
|
1249
1317
|
? [` call void @scr_island_set_inflate(ptr @scr_zlib_inflate_exact)`]
|
|
1250
1318
|
: []),
|
|
@@ -1344,9 +1412,10 @@ export class LlEmitter {
|
|
|
1344
1412
|
// lane's -fsanitize=address link activates instrumentation over the
|
|
1345
1413
|
// emitted functions too (the runtime TUs get theirs from clang).
|
|
1346
1414
|
`attributes #0 = { sanitize_address }`, ...(this.wasi ? [`attributes #1 = { sanitize_address presplitcoroutine }`] : []), ...(hasNoInlineRecordClone ? [`attributes #2 = { noinline sanitize_address }`] : []), ``);
|
|
1415
|
+
out.push(...this.fieldAliasMetadata());
|
|
1347
1416
|
if (this.debug !== null)
|
|
1348
1417
|
out.push(this.debug.render());
|
|
1349
|
-
return out
|
|
1418
|
+
return out;
|
|
1350
1419
|
}
|
|
1351
1420
|
/** LIBRARY mode: the profile-declared external definitions — the
|
|
1352
1421
|
* export-map wrappers plus init / sink-registration / reset / collect.
|
|
@@ -2403,7 +2472,7 @@ export class LlEmitter {
|
|
|
2403
2472
|
* a retained peek. */
|
|
2404
2473
|
unionExtract(uName, arm) {
|
|
2405
2474
|
const B = this.B;
|
|
2406
|
-
if (arm.kind === "f64") {
|
|
2475
|
+
if (arm.kind === "f64" || arm.kind === "procStream") {
|
|
2407
2476
|
const t = B.tmp();
|
|
2408
2477
|
this.declare(`declare double @scr_union_get_f64(ptr)`);
|
|
2409
2478
|
B.line(`${t} = call double @scr_union_get_f64(ptr ${uName})`);
|
|
@@ -2423,7 +2492,7 @@ export class LlEmitter {
|
|
|
2423
2492
|
unionNewOwned(tag, v) {
|
|
2424
2493
|
const B = this.B;
|
|
2425
2494
|
const t = B.tmp();
|
|
2426
|
-
if (v.type.kind === "f64") {
|
|
2495
|
+
if (v.type.kind === "f64" || v.type.kind === "procStream") {
|
|
2427
2496
|
this.declare(`declare ptr @scr_union_new_f64(i32, double)`);
|
|
2428
2497
|
B.line(`${t} = call ptr @scr_union_new_f64(i32 ${tag}, double ${v.name})`);
|
|
2429
2498
|
return t;
|
|
@@ -2454,6 +2523,7 @@ export class LlEmitter {
|
|
|
2454
2523
|
const { index, type } = classFieldIndex(meta, field);
|
|
2455
2524
|
const p = this.B.tmp();
|
|
2456
2525
|
this.B.line(`${p} = getelementptr inbounds %${classStructSym(className)}, ptr ${objName}, i64 0, i32 ${index}`);
|
|
2526
|
+
this.markFieldPointer(p, field);
|
|
2457
2527
|
return { ptr: p, type };
|
|
2458
2528
|
}
|
|
2459
2529
|
/** `o->vt->pre` — the dynamic class's preorder number (borrowed object;
|
|
@@ -2544,7 +2614,7 @@ export class LlEmitter {
|
|
|
2544
2614
|
const B = this.B;
|
|
2545
2615
|
const fieldTy = llFieldType(t);
|
|
2546
2616
|
const raw = B.tmp();
|
|
2547
|
-
B.line(`${raw} = load ${fieldTy}, ptr ${ptr}`);
|
|
2617
|
+
B.line(`${raw} = load ${fieldTy}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
|
|
2548
2618
|
if (fieldTy !== "i8")
|
|
2549
2619
|
return raw;
|
|
2550
2620
|
const b = B.tmp();
|
|
@@ -2556,12 +2626,12 @@ export class LlEmitter {
|
|
|
2556
2626
|
const B = this.B;
|
|
2557
2627
|
const fieldTy = llFieldType(t);
|
|
2558
2628
|
if (fieldTy !== "i8") {
|
|
2559
|
-
B.line(`store ${fieldTy} ${value}, ptr ${ptr}`);
|
|
2629
|
+
B.line(`store ${fieldTy} ${value}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
|
|
2560
2630
|
return;
|
|
2561
2631
|
}
|
|
2562
2632
|
const z = B.tmp();
|
|
2563
2633
|
B.line(`${z} = zext i1 ${value} to i8`);
|
|
2564
|
-
B.line(`store i8 ${z}, ptr ${ptr}`);
|
|
2634
|
+
B.line(`store i8 ${z}, ptr ${ptr}${this.fieldAliasAttachment(ptr)}`);
|
|
2565
2635
|
}
|
|
2566
2636
|
// ── bindings ────────────────────────────────────────────────────────────
|
|
2567
2637
|
/** A binding's storage: a module global, a plain local slot, or a boxed
|
|
@@ -2841,8 +2911,20 @@ export class LlEmitter {
|
|
|
2841
2911
|
this.unwindCleanups.clear();
|
|
2842
2912
|
this.jumpTargets = [];
|
|
2843
2913
|
this.currentLocals = new Map(fn.locals.map((l) => [l.id, l]));
|
|
2914
|
+
this.borrowedParameters.clear();
|
|
2915
|
+
const borrowedParameterIndexes = this.callLifetimes.parameters.get(fn.name);
|
|
2916
|
+
if (borrowedParameterIndexes) {
|
|
2917
|
+
for (const index of borrowedParameterIndexes)
|
|
2918
|
+
this.borrowedParameters.add(fn.params[index].localId);
|
|
2919
|
+
}
|
|
2844
2920
|
this.captureIds = new Set([...(fn.captures ?? []), ...(fn.classCaptures ?? [])].map((c) => c.localId));
|
|
2845
2921
|
this.integerLoopBindings.clear();
|
|
2922
|
+
this.fieldPointerTags.clear();
|
|
2923
|
+
this.integerArrayBindings.clear();
|
|
2924
|
+
this.localArrayReads = findLocalArrayReads(fn, this.fnByName, this.unionsById, this.arrayPreservingFunctions, this.callLifetimes, this.optionalArrayReads);
|
|
2925
|
+
this.callArrayReads = findCallArrayReads(fn, this.optionalArrayReads, this.arrayPreservingFunctions, this.callLifetimes);
|
|
2926
|
+
this.mapReadLifetimes = findMapReadLifetimes(fn, this.unionsById, this.callLifetimes);
|
|
2927
|
+
this.localStackUnions = findLocalStackUnions(fn, this.callLifetimes, this.unionsById);
|
|
2846
2928
|
this.integerRanges = analyzeIntegerRanges(fn);
|
|
2847
2929
|
this.chainSlots.clear();
|
|
2848
2930
|
this.finallyStack = [];
|
|
@@ -2934,7 +3016,8 @@ export class LlEmitter {
|
|
|
2934
3016
|
// params (callees own their params — callers passed +1). Boxed params
|
|
2935
3017
|
// allocate the shared binding and move the raw value in.
|
|
2936
3018
|
const fnScope = [];
|
|
2937
|
-
|
|
3019
|
+
const borrowed = this.callLifetimes.parameters.get(fn.name);
|
|
3020
|
+
for (const [index, p] of fn.params.entries()) {
|
|
2938
3021
|
const local = this.currentLocals.get(p.localId);
|
|
2939
3022
|
const slot = `%${mangleLocal(p.localId)}`;
|
|
2940
3023
|
if (local.boxed) {
|
|
@@ -2946,7 +3029,7 @@ export class LlEmitter {
|
|
|
2946
3029
|
continue;
|
|
2947
3030
|
}
|
|
2948
3031
|
B.line(`store ${this.llType(p.type)} %p_${mangleLocal(p.localId)}, ptr ${slot}`);
|
|
2949
|
-
if (isRefCounted(p.type))
|
|
3032
|
+
if (isRefCounted(p.type) && !borrowed?.has(index))
|
|
2950
3033
|
fnScope.push({ slot, type: p.type });
|
|
2951
3034
|
}
|
|
2952
3035
|
this.scopes.push(fnScope);
|
|
@@ -3028,7 +3111,38 @@ export class LlEmitter {
|
|
|
3028
3111
|
const ret = this.llType(fn.returnType);
|
|
3029
3112
|
const attrs = coro !== null ? "#1" : FN_ATTRS;
|
|
3030
3113
|
const debug = this.debugScope === null ? "" : ` !dbg ${this.debugScope}`;
|
|
3031
|
-
|
|
3114
|
+
const symbol = borrowed ? mangleBorrowedFunction(fn.name) : mangleFunction(fn.name);
|
|
3115
|
+
const body = `define internal ${ret} @${symbol}(${params.join(", ")}) ${attrs}${debug} { ; ${fn.name}\n${B.render()}\n}`;
|
|
3116
|
+
return borrowed ? body + "\n" + this.emitOwnedCallAdapter(fn, borrowed) : body;
|
|
3117
|
+
}
|
|
3118
|
+
/** Keep the ordinary owned ABI for closures, virtual dispatch, generated
|
|
3119
|
+
* runtime adapters and library exports. Only direct IR calls select the
|
|
3120
|
+
* borrowing body. Ownership of other parameters moves into that body;
|
|
3121
|
+
* borrowed parameters are released here on normal and exceptional exits.
|
|
3122
|
+
* The pending exception remains for the adapter's caller to handle. */
|
|
3123
|
+
emitOwnedCallAdapter(fn, borrowed) {
|
|
3124
|
+
const B = new BlockBuilder();
|
|
3125
|
+
this.B = B;
|
|
3126
|
+
const params = fn.params.map((param, index) => `${this.llType(param.type)} %p${index}`);
|
|
3127
|
+
const ret = this.llType(fn.returnType);
|
|
3128
|
+
const call = `call ${ret} @${mangleBorrowedFunction(fn.name)}(${params.join(", ")})`;
|
|
3129
|
+
B.line(ret === "void" ? call : `%result = ${call}`);
|
|
3130
|
+
for (const index of borrowed)
|
|
3131
|
+
this.releaseValue(`%p${index}`, fn.params[index].type);
|
|
3132
|
+
B.terminate(ret === "void" ? "ret void" : `ret ${ret} %result`);
|
|
3133
|
+
return `define internal ${ret} @${mangleFunction(fn.name)}(${params.join(", ")}) ${FN_ATTRS} {\n${B.render()}\n}`;
|
|
3134
|
+
}
|
|
3135
|
+
/** A local immutable binding keeps its value alive while later arguments
|
|
3136
|
+
* and the callee execute. Global, captured, TDZ and mutable bindings need
|
|
3137
|
+
* an owned snapshot, even when the callee only inspects the value. */
|
|
3138
|
+
canBorrowCallArgument(value) {
|
|
3139
|
+
if (value.kind === "strLit")
|
|
3140
|
+
return true;
|
|
3141
|
+
if (value.kind !== "varRef")
|
|
3142
|
+
return false;
|
|
3143
|
+
const binding = this.binding(value.localId);
|
|
3144
|
+
return binding.kind === "local" && binding.local !== undefined &&
|
|
3145
|
+
(!binding.local.mutable || this.borrowedParameters.has(value.localId)) && !binding.local.boxed && !binding.local.tdz;
|
|
3032
3146
|
}
|
|
3033
3147
|
// ── statements ──────────────────────────────────────────────────────────
|
|
3034
3148
|
emitStmts(stmts) {
|
|
@@ -3072,6 +3186,31 @@ export class LlEmitter {
|
|
|
3072
3186
|
switch (s.kind) {
|
|
3073
3187
|
case "varDecl": {
|
|
3074
3188
|
const b = this.binding(s.localId);
|
|
3189
|
+
const localUnion = this.localStackUnions.get(s.localId);
|
|
3190
|
+
if (localUnion) {
|
|
3191
|
+
const union = emitStackUnion(this, localUnion);
|
|
3192
|
+
B.line(`store ptr ${union.value.name}, ptr ${b.slot}`);
|
|
3193
|
+
if (union.payload) {
|
|
3194
|
+
this.moveTemp(union.payload);
|
|
3195
|
+
this.scopes[this.scopes.length - 1].push({ slot: union.payloadSlot, type: union.payload.type });
|
|
3196
|
+
}
|
|
3197
|
+
break;
|
|
3198
|
+
}
|
|
3199
|
+
const localRead = this.localArrayReads.get(s.localId);
|
|
3200
|
+
if (localRead) {
|
|
3201
|
+
const owner = emitLocalArrayRead(this, localRead, b.slot);
|
|
3202
|
+
if (owner)
|
|
3203
|
+
this.scopes[this.scopes.length - 1].push(owner);
|
|
3204
|
+
break;
|
|
3205
|
+
}
|
|
3206
|
+
const mapRead = this.mapReadLifetimes.locals.get(s.localId);
|
|
3207
|
+
if (mapRead) {
|
|
3208
|
+
const result = emitStackMapRead(this, mapRead);
|
|
3209
|
+
B.line(`store ptr ${result.value.name}, ptr ${b.slot}`);
|
|
3210
|
+
if (result.owner)
|
|
3211
|
+
this.scopes[this.scopes.length - 1].push(result.owner);
|
|
3212
|
+
break;
|
|
3213
|
+
}
|
|
3075
3214
|
if (b.kind === "boxed") {
|
|
3076
3215
|
// Box FIRST, then evaluate the initializer: a named function
|
|
3077
3216
|
// expression's closure captures this box during init evaluation.
|
|
@@ -3210,7 +3349,7 @@ export class LlEmitter {
|
|
|
3210
3349
|
// release — a release can trigger a cycle collection, which must
|
|
3211
3350
|
// never see a heap edge whose count was already given up).
|
|
3212
3351
|
// Classes and records share the struct layout, so one emission.
|
|
3213
|
-
const obj = this.emitExpr(s.obj);
|
|
3352
|
+
const obj = isRefCounted(s.value.type) ? this.emitExpr(s.obj) : this.emitStableReceiver(s.obj, [s.value]);
|
|
3214
3353
|
const v = this.emitExpr(s.value);
|
|
3215
3354
|
const { ptr, type } = s.kind === "fieldSet"
|
|
3216
3355
|
? this.classFieldPtr(obj.name, s.className, s.field)
|
|
@@ -3471,13 +3610,21 @@ export class LlEmitter {
|
|
|
3471
3610
|
case "for": {
|
|
3472
3611
|
// The init's scope wraps the whole loop (break/continue must NOT
|
|
3473
3612
|
// release it — scopeDepth captured after the push, C parity).
|
|
3474
|
-
const
|
|
3613
|
+
const integerArrayLoop = this.debug === null ? matchIntegerArrayForLoop(s, this.currentLocals, this.integerArrayBindings) : null;
|
|
3614
|
+
const integerLoop = integerArrayLoop ?? (this.debug === null ? matchIntegerBytesForLoop(s, this.currentLocals) : null);
|
|
3475
3615
|
this.scopes.push([]);
|
|
3476
3616
|
let integerSlot = null;
|
|
3477
3617
|
if (integerLoop) {
|
|
3478
3618
|
integerSlot = B.slot();
|
|
3479
3619
|
B.entryAllocas.push(`${integerSlot} = alloca ${this.sizeType} ; integer induction ${this.currentLocals.get(integerLoop.localId).name}`);
|
|
3480
|
-
|
|
3620
|
+
let start = "0";
|
|
3621
|
+
if (integerArrayLoop && s.init?.kind === "varDecl" && s.init.init) {
|
|
3622
|
+
const value = this.emitExpr(s.init.init);
|
|
3623
|
+
start = B.tmp();
|
|
3624
|
+
B.line(`${start} = fptoui double ${value.name} to ${this.sizeType}`);
|
|
3625
|
+
this.integerArrayBindings.add(integerLoop.localId);
|
|
3626
|
+
}
|
|
3627
|
+
B.line(`store ${this.sizeType} ${start}, ptr ${integerSlot}`);
|
|
3481
3628
|
this.integerLoopBindings.set(integerLoop.localId, integerSlot);
|
|
3482
3629
|
}
|
|
3483
3630
|
else if (s.init) {
|
|
@@ -3525,8 +3672,10 @@ export class LlEmitter {
|
|
|
3525
3672
|
const len = B.tmp();
|
|
3526
3673
|
const index = B.tmp();
|
|
3527
3674
|
const inBounds = B.tmp();
|
|
3528
|
-
B.line(`${lenPtr} = getelementptr inbounds
|
|
3529
|
-
|
|
3675
|
+
B.line(`${lenPtr} = getelementptr inbounds %${integerArrayLoop ? "ScrArr" : "ScrBytes"}, ptr ${receiver.name}, i64 0, i32 1`);
|
|
3676
|
+
if (integerArrayLoop)
|
|
3677
|
+
this.markMemoryPointer(lenPtr, "array:header");
|
|
3678
|
+
B.line(`${len} = load ${this.sizeType}, ptr ${lenPtr}${this.fieldAliasAttachment(lenPtr)}`);
|
|
3530
3679
|
B.line(`${index} = load ${this.sizeType}, ptr ${integerSlot}`);
|
|
3531
3680
|
B.line(`${inBounds} = icmp ult ${this.sizeType} ${index}, ${len}`);
|
|
3532
3681
|
B.condBr(inBounds, lb, le);
|
|
@@ -3566,6 +3715,8 @@ export class LlEmitter {
|
|
|
3566
3715
|
this.releaseScope(this.scopes.pop());
|
|
3567
3716
|
if (integerLoop)
|
|
3568
3717
|
this.integerLoopBindings.delete(integerLoop.localId);
|
|
3718
|
+
if (integerArrayLoop)
|
|
3719
|
+
this.integerArrayBindings.delete(integerArrayLoop.localId);
|
|
3569
3720
|
break;
|
|
3570
3721
|
}
|
|
3571
3722
|
case "forOf": {
|
|
@@ -4068,7 +4219,7 @@ export class LlEmitter {
|
|
|
4068
4219
|
// to this expression's frame so they survive those reads and still
|
|
4069
4220
|
// die on the path that created them, including inside lazy branches.
|
|
4070
4221
|
this.scopes.push([]);
|
|
4071
|
-
const result = emitOperatorExpr(this, e);
|
|
4222
|
+
const result = emitBorrowedFieldSequence(this, e) ?? emitOperatorExpr(this, e);
|
|
4072
4223
|
for (const local of this.scopes.pop()) {
|
|
4073
4224
|
this.currentFrame().push({ name: local.slot, type: local.type, slot: true, ...(local.boxed ? { boxed: true } : {}) });
|
|
4074
4225
|
}
|
|
@@ -4155,6 +4306,8 @@ export class LlEmitter {
|
|
|
4155
4306
|
emitReadReceiver(e) {
|
|
4156
4307
|
if (!isRefCounted(e.type))
|
|
4157
4308
|
return this.emitExpr(e);
|
|
4309
|
+
if (e.kind === "strLit")
|
|
4310
|
+
return { name: this.internLiteral(e.value), type: e.type };
|
|
4158
4311
|
if (e.kind === "varRef") {
|
|
4159
4312
|
const binding = this.binding(e.localId);
|
|
4160
4313
|
// Capture boxes can carry TDZ and caught-value conversion semantics.
|
|
@@ -4177,8 +4330,43 @@ export class LlEmitter {
|
|
|
4177
4330
|
: this.classFieldPtr(receiver.name, e.className, e.field);
|
|
4178
4331
|
return { name: this.loadField(ptr, type), type: e.type };
|
|
4179
4332
|
}
|
|
4333
|
+
if (e.kind === "ternary" && this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_)) {
|
|
4334
|
+
// Checked projections lower to a ternary with an always-throwing
|
|
4335
|
+
// arm. Keep that check at the use, but borrow the successful arm.
|
|
4336
|
+
const B = this.B;
|
|
4337
|
+
const cond = this.emitExpr(e.cond);
|
|
4338
|
+
const slot = B.slot();
|
|
4339
|
+
B.entryAllocas.push(`${slot} = alloca ptr`);
|
|
4340
|
+
const yes = B.newLabel("read.then"), no = B.newLabel("read.else"), join = B.newLabel("read.join");
|
|
4341
|
+
B.condBr(cond.name, yes, no);
|
|
4342
|
+
for (const [label, value] of [[yes, e.then], [no, e.else_]]) {
|
|
4343
|
+
B.startBlock(label);
|
|
4344
|
+
this.frames.push([]);
|
|
4345
|
+
const result = this.emitReadReceiver(value);
|
|
4346
|
+
B.line(`store ptr ${result.name}, ptr ${slot}`);
|
|
4347
|
+
this.releaseFrame(this.frames.pop());
|
|
4348
|
+
B.br(join);
|
|
4349
|
+
}
|
|
4350
|
+
B.startBlock(join);
|
|
4351
|
+
const value = B.tmp();
|
|
4352
|
+
B.line(`${value} = load ptr, ptr ${slot}`);
|
|
4353
|
+
return { name: value, type: e.type };
|
|
4354
|
+
}
|
|
4180
4355
|
return this.emitExpr(e);
|
|
4181
4356
|
}
|
|
4357
|
+
canBorrowReceiver(e) {
|
|
4358
|
+
switch (e.kind) {
|
|
4359
|
+
case "varRef": return this.binding(e.localId).kind !== "boxed";
|
|
4360
|
+
case "unionNarrow": return this.canBorrowReceiver(e.value);
|
|
4361
|
+
case "fieldGet":
|
|
4362
|
+
case "recordGet": return this.canBorrowReceiver(e.obj);
|
|
4363
|
+
case "ternary": return this.canBorrowReceiver(e.then) && this.canBorrowReceiver(e.else_);
|
|
4364
|
+
// The runtime always sets a pending exception; its unreachable
|
|
4365
|
+
// typed dummy is null and owns no receiver.
|
|
4366
|
+
case "libCall": return e.fn === "error.nodeThrow";
|
|
4367
|
+
default: return false;
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4182
4370
|
emitExpr(e) {
|
|
4183
4371
|
return emitExpr(this, e);
|
|
4184
4372
|
}
|
|
@@ -4248,8 +4436,8 @@ export class LlEmitter {
|
|
|
4248
4436
|
fsRenameThunkFor(cbT) {
|
|
4249
4437
|
return fsRenameThunkFor(this, cbT);
|
|
4250
4438
|
}
|
|
4251
|
-
cryptoBytesThunkFor(cbT) {
|
|
4252
|
-
return cryptoBytesThunkFor(this, cbT);
|
|
4439
|
+
cryptoBytesThunkFor(cbT, arrayBuffer = false) {
|
|
4440
|
+
return cryptoBytesThunkFor(this, cbT, arrayBuffer);
|
|
4253
4441
|
}
|
|
4254
4442
|
zlibBytesThunkFor(cbT) {
|
|
4255
4443
|
return zlibBytesThunkFor(this, cbT);
|