@scriptc/compiler 0.3.1 → 0.3.2
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 +342 -16
- package/dist/backend/executable-features.js +1 -0
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/literals.d.ts +7 -0
- package/dist/backend/literals.js +32 -0
- package/dist/backend/literals.js.map +1 -1
- package/dist/backend/literals.test.js +17 -1
- package/dist/backend/literals.test.js.map +1 -1
- package/dist/backend/llvm/alloc.d.ts +15 -4
- package/dist/backend/llvm/alloc.js +39 -15
- package/dist/backend/llvm/alloc.js.map +1 -1
- package/dist/backend/llvm/alloc.test.js +15 -1
- package/dist/backend/llvm/alloc.test.js.map +1 -1
- package/dist/backend/llvm/appended-array-literals.d.ts +2 -0
- package/dist/backend/llvm/appended-array-literals.js +109 -0
- package/dist/backend/llvm/appended-array-literals.js.map +1 -0
- package/dist/backend/llvm/appended-array-literals.test.d.ts +1 -0
- package/dist/backend/llvm/appended-array-literals.test.js +90 -0
- package/dist/backend/llvm/appended-array-literals.test.js.map +1 -0
- package/dist/backend/llvm/call-lifetimes.d.ts +4 -1
- package/dist/backend/llvm/call-lifetimes.js +51 -3
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/classes.js +10 -2
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +2 -2
- package/dist/backend/llvm/dense-array-access.js +17 -12
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.test.js +15 -2
- package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +2 -0
- package/dist/backend/llvm/dyn.js +11 -2
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +43 -2
- package/dist/backend/llvm/emitter.js +306 -32
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +122 -6
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-callbacks.d.ts +8 -0
- package/dist/backend/llvm/expr-callbacks.js +81 -1
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-calls.d.ts +12 -1
- package/dist/backend/llvm/expr-calls.js +126 -54
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.d.ts +7 -0
- package/dist/backend/llvm/expr-containers.js +38 -7
- 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.d.ts +8 -0
- package/dist/backend/llvm/expr-control.js +103 -69
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +2 -2
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +7 -0
- package/dist/backend/llvm/expr-primitives.js +30 -26
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-records.js +11 -1
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.d.ts +8 -0
- package/dist/backend/llvm/expr-stream-bridges.js +77 -8
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.test.js +49 -1
- package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -1
- package/dist/backend/llvm/int32-abi.d.ts +18 -2
- package/dist/backend/llvm/int32-abi.js +23 -2
- package/dist/backend/llvm/int32-abi.js.map +1 -1
- package/dist/backend/llvm/int32-abi.test.js +75 -1
- package/dist/backend/llvm/int32-abi.test.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +7 -0
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +58 -0
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +76 -9
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +5 -3
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.d.ts +24 -2
- package/dist/backend/llvm/local-union-storage.js +127 -12
- package/dist/backend/llvm/local-union-storage.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.test.js +106 -1
- package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
- package/dist/backend/llvm/record-results.d.ts +26 -0
- package/dist/backend/llvm/record-results.js +252 -0
- package/dist/backend/llvm/record-results.js.map +1 -0
- package/dist/backend/llvm/reference-effects.js +2 -0
- package/dist/backend/llvm/reference-effects.js.map +1 -1
- package/dist/backend/llvm/reference-writes.js +15 -9
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/regions.d.ts +67 -0
- package/dist/backend/llvm/regions.js +309 -0
- package/dist/backend/llvm/regions.js.map +1 -0
- package/dist/backend/llvm/regions.test.d.ts +1 -0
- package/dist/backend/llvm/regions.test.js +173 -0
- package/dist/backend/llvm/regions.test.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +34 -7
- package/dist/backend/llvm/shapes.js +31 -16
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +7 -6
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/split-loops.js +1 -1
- package/dist/backend/llvm/split-loops.js.map +1 -1
- package/dist/backend/llvm/stack-objects.d.ts +29 -0
- package/dist/backend/llvm/stack-objects.js +130 -0
- package/dist/backend/llvm/stack-objects.js.map +1 -0
- package/dist/backend/llvm/stack-objects.test.d.ts +1 -0
- package/dist/backend/llvm/stack-objects.test.js +252 -0
- package/dist/backend/llvm/stack-objects.test.js.map +1 -0
- package/dist/backend/llvm/string-reads.d.ts +4 -1
- package/dist/backend/llvm/string-reads.js +89 -9
- package/dist/backend/llvm/string-reads.js.map +1 -1
- package/dist/backend/llvm/switch-dispatch.js +5 -4
- package/dist/backend/llvm/switch-dispatch.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +2 -0
- package/dist/backend/llvm/walkers.js +4 -2
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/may-throw.js +1 -0
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +5 -0
- package/dist/backend/native/executable.js +16 -1
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/library.js +1 -1
- package/dist/backend/native/library.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +2 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +1 -0
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-core.d.ts +1 -0
- package/dist/backend/runtime-pack-core.js +1 -0
- package/dist/backend/runtime-pack-core.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack.test.js +1 -1
- package/dist/backend/target-diagnostics.js +14 -0
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/target-diagnostics.test.js +13 -0
- package/dist/backend/target-diagnostics.test.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +1 -0
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/frontend/experimental-import.d.ts +12 -0
- package/dist/frontend/experimental-import.js +63 -0
- package/dist/frontend/experimental-import.js.map +1 -0
- package/dist/frontend/lowering/builtin-calls.d.ts +6 -1
- package/dist/frontend/lowering/builtin-calls.js +36 -0
- package/dist/frontend/lowering/builtin-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/console.d.ts +16 -6
- package/dist/frontend/lowering/builtins/console.js +33 -9
- package/dist/frontend/lowering/builtins/console.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.js +20 -0
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/json.d.ts +2 -2
- package/dist/frontend/lowering/builtins/json.js +13 -4
- package/dist/frontend/lowering/builtins/json.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-calls.js +16 -1
- package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/numbers.d.ts +1 -0
- package/dist/frontend/lowering/builtins/numbers.js +17 -0
- package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
- package/dist/frontend/lowering/builtins/operating-system.d.ts +18 -0
- package/dist/frontend/lowering/builtins/operating-system.js +361 -1
- package/dist/frontend/lowering/builtins/operating-system.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.js +15 -3
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/promises.js +109 -2
- package/dist/frontend/lowering/builtins/promises.js.map +1 -1
- package/dist/frontend/lowering/builtins/text-codecs.d.ts +3 -4
- package/dist/frontend/lowering/builtins/text-codecs.js +3 -4
- package/dist/frontend/lowering/builtins/text-codecs.js.map +1 -1
- package/dist/frontend/lowering/checked-promise-all.d.ts +10 -3
- package/dist/frontend/lowering/checked-promise-all.js +52 -6
- package/dist/frontend/lowering/checked-promise-all.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +6 -3
- package/dist/frontend/lowering/class-dynamic-dispatch.js +54 -31
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/containers/array-callbacks.js +34 -4
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-construction.js +8 -4
- package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
- package/dist/frontend/lowering/containers/array-pipelines.js +1 -1
- package/dist/frontend/lowering/containers/array-pipelines.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +91 -0
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/cycle-initialization.d.ts +18 -2
- package/dist/frontend/lowering/cycle-initialization.js +166 -12
- package/dist/frontend/lowering/cycle-initialization.js.map +1 -1
- package/dist/frontend/lowering/deferred-module-initializers.js +7 -2
- package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -1
- package/dist/frontend/lowering/deferred-module-initializers.test.js +28 -0
- package/dist/frontend/lowering/deferred-module-initializers.test.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +5 -56
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/generator-delegation.d.ts +8 -0
- package/dist/frontend/lowering/generator-delegation.js +231 -10
- package/dist/frontend/lowering/generator-delegation.js.map +1 -1
- package/dist/frontend/lowering/lifetime-regions.d.ts +11 -0
- package/dist/frontend/lowering/lifetime-regions.js +216 -0
- package/dist/frontend/lowering/lifetime-regions.js.map +1 -0
- package/dist/frontend/lowering/lower-array-sort.d.ts +28 -2
- package/dist/frontend/lowering/lower-array-sort.js +100 -3
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
- package/dist/frontend/lowering/lower-array-sort.test.js +99 -2
- package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +72 -102
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +4 -3
- package/dist/frontend/lowering/lower-classes.js +116 -2
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-console.d.ts +13 -0
- package/dist/frontend/lowering/lower-console.js +460 -4
- package/dist/frontend/lowering/lower-console.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.d.ts +6 -0
- package/dist/frontend/lowering/lower-event-emitter.js +124 -38
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +137 -22
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.d.ts +15 -7
- package/dist/frontend/lowering/lower-generators.js +183 -99
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.d.ts +8 -1
- package/dist/frontend/lowering/lower-inspect.js +119 -18
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +20 -14
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stdlib.d.ts +4 -0
- package/dist/frontend/lowering/lower-stdlib.js +35 -1
- package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +66 -11
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +22 -1
- package/dist/frontend/lowering/lowerer.js +116 -8
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/regex-span-reads.d.ts +12 -0
- package/dist/frontend/lowering/regex-span-reads.js +164 -0
- package/dist/frontend/lowering/regex-span-reads.js.map +1 -0
- package/dist/frontend/lowering/surfaces.js +112 -10
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/var-hoisting.d.ts +3 -0
- package/dist/frontend/lowering/var-hoisting.js +261 -0
- package/dist/frontend/lowering/var-hoisting.js.map +1 -0
- package/dist/frontend/pipeline.js +5 -3
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/program.d.ts +3 -2
- package/dist/frontend/program.js +23 -5
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +13 -0
- package/dist/frontend/program.test.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +13 -1
- package/dist/frontend/type-mapper.js +146 -13
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/ir/builtin-effects.js +29 -2
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +145 -15
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/function-references.test.js +1 -0
- package/dist/ir/function-references.test.js.map +1 -1
- package/dist/ir/int32-slots.js +1 -0
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/intrinsic-signatures.js +2 -0
- package/dist/ir/intrinsic-signatures.js.map +1 -1
- package/dist/ir/ir.d.ts +65 -20
- package/dist/ir/ir.js +5 -0
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/runtime-features.d.ts +1 -0
- package/dist/ir/runtime-features.js +35 -1
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/scalar-records.js +1 -2
- package/dist/ir/scalar-records.js.map +1 -1
- package/dist/ir/validate.js +150 -25
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +65 -0
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/ir-policy.js +1 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/dist/native/sanitizer.test.js +1 -0
- package/dist/native/sanitizer.test.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +159 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { emitLlvmLayouts } from "./layouts.js";
|
|
2
2
|
import { compileRegexMatcher } from "./regex-matchers.js";
|
|
3
|
-
import { FIRST_EMITTED_CYC_KIND, inlineAllocSupported } from "./alloc.js";
|
|
4
|
-
import { llvmBytes as llBytes } from "../literals.js";
|
|
3
|
+
import { CYC_BUF, CYC_HDR, FIRST_EMITTED_CYC_KIND, inlineAllocSupported } from "./alloc.js";
|
|
4
|
+
import { hasLoneSurrogate, llvmBytes as llBytes, wtf8Bytes } from "../literals.js";
|
|
5
5
|
import { InternalCompilerError } from "../../errors.js";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
7
|
import { endsWithJump, matchStringSelfConcat, streamTypedRefEligible, undefinedArmTag, } from "../../ir/analysis.js";
|
|
@@ -16,6 +16,7 @@ import { findBytesBounds } from "./bytes-bounds.js";
|
|
|
16
16
|
import { emitByteWindowGuard, findInitializedByteLoopBindings, matchByteWindow, } from "./byte-windows.js";
|
|
17
17
|
import { canDeferSplitPiece, emitSplitSpanNext, materializeSplitPiece, emitSplitCursor, emitSplitNext, emitSplitScratch, emitSplitSnapshot, findPrivateSplitLocals, loadSplitSnapshot, storeSplitSnapshot, stringSplit, } from "./split-loops.js";
|
|
18
18
|
import { scalarizeNumericRecords } from "../../ir/scalar-records.js";
|
|
19
|
+
import { addRecordResultEntries } from "./record-results.js";
|
|
19
20
|
import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js";
|
|
20
21
|
import { everyExpr, everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse.js";
|
|
21
22
|
import { analyzeIntegerRanges, INT32_RANGE } from "../../ir/integer-ranges.js";
|
|
@@ -24,7 +25,7 @@ import { analyzeInt32Slots } from "../../ir/int32-slots.js";
|
|
|
24
25
|
import { analyzeFinalFields, constructorClass } from "../../ir/final-fields.js";
|
|
25
26
|
import { foldConstantGlobals } from "../../ir/constant-globals.js";
|
|
26
27
|
import { findIntegerViews } from "./integer-views.js";
|
|
27
|
-
import { findInt32Abis, INT32_ABI_SUFFIX } from "./int32-abi.js";
|
|
28
|
+
import { findInt32Abis, INT32_ABI_SUFFIX, SCALAR_UNION_DUMMY, SCALAR_UNION_RESULT, } from "./int32-abi.js";
|
|
28
29
|
import { findInt32Locals } from "./int32-locals.js";
|
|
29
30
|
import { exactInteger, narrowInteger } from "./integer-values.js";
|
|
30
31
|
import { findInitializerBindings, withInitializerBindings } from "../../ir/initializer-bindings.js";
|
|
@@ -35,7 +36,8 @@ import { computeMayThrow } from "../may-throw.js";
|
|
|
35
36
|
import { mangleArgPack, mangleAsyncAdoptCall, mangleAsyncAwaitCall, mangleAsyncSpawn, mangleBorrowedFunction, mangleClassObj, mangleClassStruct, mangleFnClosure, mangleFunction, mangleGenDrop, mangleGenSpawn, mangleGlobal, mangleLocal, mangleRecordStruct, mangleTrampoline, mangleWrapper, mangleBorrowingWrapper, mangleVtInstance, } from "../mangle.js";
|
|
36
37
|
import { analyzeCallLifetimes } from "./call-lifetimes.js";
|
|
37
38
|
import { canStackUnion, emitStackUnion, findLocalStackUnions } from "./stack-unions.js";
|
|
38
|
-
import {
|
|
39
|
+
import { emitStackObject, findLocalStackObjects, findReassignedStackObjects, stackObjectStruct, } from "./stack-objects.js";
|
|
40
|
+
import { allocateLocalUnion, emitScalarOptional, findLocalUnionStorage, isScalarOptionalSource, storeLocalUnion, } from "./local-union-storage.js";
|
|
39
41
|
import { BlockBuilder } from "./blocks.js";
|
|
40
42
|
import { NullableRefFields } from "./nullable-fields.js";
|
|
41
43
|
import { emitLocalArrayRead, emitProjectedArrayRead, emitBorrowedArrayRead, findLocalArrayReads, findCallArrayReads, OptionalArrayReads, } from "./local-array-reads.js";
|
|
@@ -51,6 +53,7 @@ import { ReferenceWrites } from "./reference-writes.js";
|
|
|
51
53
|
import { LlvmDebugInfo } from "./debug-info.js";
|
|
52
54
|
import { StackCallbacks } from "./stack-callbacks.js";
|
|
53
55
|
import { findLoopArrayBorrows } from "./loop-array-borrows.js";
|
|
56
|
+
import { findAppendedArrayLiterals } from "./appended-array-literals.js";
|
|
54
57
|
import { AmbientReceiverReaders, findConstantCallbacks } from "./constant-callbacks.js";
|
|
55
58
|
import { findScalarStringSlices, emitStringSliceSnapshot, } from "./string-slices.js";
|
|
56
59
|
import { LazyCaptures } from "./lazy-captures.js";
|
|
@@ -77,7 +80,8 @@ import { emitChildProcessLibCall, emitAsyncContextLibCall, emitProcessLibCall, e
|
|
|
77
80
|
import { emitStreamLibCall } from "./lib-stream.js";
|
|
78
81
|
import { emitNetworkHttpLibCall } from "./lib-network.js";
|
|
79
82
|
import { emitAssertInspectLibCall, emitIoLibCall, emitGenericLibCall, emitLibCall, } from "./lib-dispatch.js";
|
|
80
|
-
import { buildClassGraph, classMembershipIntervals, emitClassMembershipHelper, classEnvironmentIndex, classFieldIndex, classStructSym, } from "./classes.js";
|
|
83
|
+
import { buildClassGraph, classMembershipIntervals, emitClassMembershipHelper, classEnvironmentIndex, classFieldIndex, classStructSym, programLifetimeClass, } from "./classes.js";
|
|
84
|
+
import { LifetimeRegions, REGION_TYPES } from "./regions.js";
|
|
81
85
|
import { LlDyn } from "./dyn.js";
|
|
82
86
|
import { VirtualBorrows } from "./virtual-borrows.js";
|
|
83
87
|
import { LlvmUnsupportedError } from "./unsupported.js";
|
|
@@ -86,7 +90,7 @@ import { isObjectArm, NULLABLE_ABSENT, NULLABLE_NULL, NullableUnions } from "./n
|
|
|
86
90
|
import { emitNullablePresent, emitUnionPeek, emitUnionTag } from "./union-repr.js";
|
|
87
91
|
import { literalCapWord, literalCapWord32 } from "./string-key-hash.js";
|
|
88
92
|
import { NUMBER_MAP_ENTRY_DECL, STRING_MAP_ENTRY_DECL } from "./map-number-lookup.js";
|
|
89
|
-
import { STRING_READ_HELPERS } from "./string-reads.js";
|
|
93
|
+
import { STRING_READ_HELPERS, stringScanDecl } from "./string-reads.js";
|
|
90
94
|
import { emitConcatInputs, emitMixedConcat, numberPart, stringParts, } from "./string-construction.js";
|
|
91
95
|
import { arrNewCall, boxAccess, boxNewCall, boxReleaseSym, computeTraced, elemAccess, emitInlineRcHelpers, emitNullableRetainWrappers, FN_ATTRS, inlineRcDecls, llFieldType, releaseSym, retainSym, traceArg, typedRefConstructor, vAdapters, } from "./shapes.js";
|
|
92
96
|
import { INLINE_LITERAL_BYTES, literalEqualityDefinition } from "./string-literal-equality.js";
|
|
@@ -122,14 +126,14 @@ export function emitLlvmModule(input, options = {}) {
|
|
|
122
126
|
const mod = unshareNodes(input);
|
|
123
127
|
// Keep source storage intact for debugger inspection in dev builds.
|
|
124
128
|
return new LlEmitter(options.debugSources === undefined
|
|
125
|
-
? scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction))
|
|
129
|
+
? addRecordResultEntries(scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction)))
|
|
126
130
|
: mod, options).emit();
|
|
127
131
|
}
|
|
128
132
|
/** Keep large translation units below the host's single-string limit. */
|
|
129
133
|
export function emitLlvmModuleSource(input, options = {}) {
|
|
130
134
|
const mod = unshareNodes(input);
|
|
131
135
|
const parts = new LlEmitter(options.debugSources === undefined
|
|
132
|
-
? scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction))
|
|
136
|
+
? addRecordResultEntries(scalarizeNumericRecords(specializeNumericCalls(foldConstantGlobals(mod), mangleFunction)))
|
|
133
137
|
: mod, options).emitParts();
|
|
134
138
|
const length = parts.reduce((total, part) => total + part.length, Math.max(0, parts.length - 1));
|
|
135
139
|
if (length <= 256 * 1024 * 1024)
|
|
@@ -137,7 +141,7 @@ export function emitLlvmModuleSource(input, options = {}) {
|
|
|
137
141
|
return parts.flatMap((part, index) => (index === 0 ? [part] : ["\n", part]));
|
|
138
142
|
}
|
|
139
143
|
function llStrBytes(text) {
|
|
140
|
-
return llBytes(
|
|
144
|
+
return llBytes(wtf8Bytes(text));
|
|
141
145
|
}
|
|
142
146
|
const NO_BORROWED = new Set();
|
|
143
147
|
/** Whether any node of `e` names the local (reads, writes, declarations,
|
|
@@ -181,6 +185,10 @@ export class LlEmitter {
|
|
|
181
185
|
scalarStringSlices = new Map();
|
|
182
186
|
stringSlices = new Map();
|
|
183
187
|
localStackUnions = new Map();
|
|
188
|
+
localStackObjects = new Map();
|
|
189
|
+
reassignedStackObjects = new Set();
|
|
190
|
+
/** The binding slot of each reassigned stack-object local. */
|
|
191
|
+
stackObjectSlots = new Map();
|
|
184
192
|
localUnionStorageProofs = new Map();
|
|
185
193
|
localUnionStorage = new Map();
|
|
186
194
|
integerArrayBindings = new Set();
|
|
@@ -203,6 +211,18 @@ export class LlEmitter {
|
|
|
203
211
|
}
|
|
204
212
|
this.fieldPointerTags.set(ptr, tag);
|
|
205
213
|
}
|
|
214
|
+
/** The alias tag of a runtime word that emitted code reads and writes
|
|
215
|
+
* outside every field (the lifetime-region count, owner and cursors). */
|
|
216
|
+
memoryAliasAttachment(category) {
|
|
217
|
+
if (this.debug !== null)
|
|
218
|
+
return "";
|
|
219
|
+
let tag = this.fieldAliasTags.get(category);
|
|
220
|
+
if (tag === undefined) {
|
|
221
|
+
tag = 2 + this.fieldAliasTags.size * 2;
|
|
222
|
+
this.fieldAliasTags.set(category, tag);
|
|
223
|
+
}
|
|
224
|
+
return `, !tbaa !${tag}`;
|
|
225
|
+
}
|
|
206
226
|
fieldAliasAttachment(ptr) {
|
|
207
227
|
const tag = this.fieldPointerTags.get(ptr);
|
|
208
228
|
return tag === undefined ? "" : `, !tbaa !${tag}`;
|
|
@@ -217,10 +237,12 @@ export class LlEmitter {
|
|
|
217
237
|
return lines;
|
|
218
238
|
}
|
|
219
239
|
debug;
|
|
240
|
+
/** Projection-only scalar objects may live in frame storage (stack-objects.ts). */
|
|
241
|
+
stackObjects;
|
|
220
242
|
debugScope = null;
|
|
221
243
|
sizeType;
|
|
222
244
|
ffiExtendNarrowIntegers;
|
|
223
|
-
|
|
245
|
+
cycleBufOffset;
|
|
224
246
|
/** Emitted ScrCycType descriptors so far (their collector statistics
|
|
225
247
|
* indices; see ShapeHost.nextCycKind). */
|
|
226
248
|
cycKinds = 0;
|
|
@@ -307,6 +329,8 @@ export class LlEmitter {
|
|
|
307
329
|
* when inline RC is off. */
|
|
308
330
|
rcHelpers;
|
|
309
331
|
fnByName = new Map();
|
|
332
|
+
/** Empty literals that construct with inline slots (appended-array-literals.ts). */
|
|
333
|
+
appendedArrayLiterals = new Set();
|
|
310
334
|
/** Emitted LLVM text of every IR function body, by function name: the
|
|
311
335
|
* fiberless-async analysis scans it for suspension entry points. */
|
|
312
336
|
fnDefText = new Map();
|
|
@@ -318,6 +342,8 @@ export class LlEmitter {
|
|
|
318
342
|
* whose bindings end with the list (emitBlock and function bodies). */
|
|
319
343
|
stmtCursor = null;
|
|
320
344
|
optionalArrayReads;
|
|
345
|
+
/** Union sources a binding or projection can hold in a stack box. */
|
|
346
|
+
unionSources;
|
|
321
347
|
checkedNarrows;
|
|
322
348
|
callArrayReads = new Map();
|
|
323
349
|
mapReadLifetimes = { locals: new Map(), arguments: new Map() };
|
|
@@ -413,6 +439,8 @@ export class LlEmitter {
|
|
|
413
439
|
* typeKey → thunk symbol. */
|
|
414
440
|
resolveThunks = new Map();
|
|
415
441
|
resolveThunkDefs = [];
|
|
442
|
+
/** Typed-ref recipe constants by type key (lazy receivers). */
|
|
443
|
+
typedRefRecipes = new Map();
|
|
416
444
|
/** ReadableStream.from adapters keep typed arrays by reference and box
|
|
417
445
|
* one current element per pull. */
|
|
418
446
|
streamFromArrayAdapters = new Map();
|
|
@@ -530,6 +558,9 @@ export class LlEmitter {
|
|
|
530
558
|
currentReturnType = VOID;
|
|
531
559
|
/** The current body returns its number result as i32. */
|
|
532
560
|
currentInt32Result = false;
|
|
561
|
+
/** The function's i32 entry returns its scalar union result as tag and
|
|
562
|
+
* payload bits (Int32Abi.union). */
|
|
563
|
+
currentUnionResult = false;
|
|
533
564
|
/** Active only while emitting a body lowered with LLVM's
|
|
534
565
|
* switched-coroutine intrinsics (wasm32 async bodies and generators,
|
|
535
566
|
* native synchronous generators; see coroLowered). */
|
|
@@ -538,6 +569,8 @@ export class LlEmitter {
|
|
|
538
569
|
* generator bodies): yieldExpr emission reads them, and emitTryCatch's
|
|
539
570
|
* catch prologue emits the GENRET sentinel re-unwind exactly here. */
|
|
540
571
|
currentGenerator = null;
|
|
572
|
+
/** The function being emitted is an async generator body. */
|
|
573
|
+
currentAsyncGenerator = false;
|
|
541
574
|
/** Active optional-chain bind slots, by chain id (chainRecv reads). */
|
|
542
575
|
chainSlots = new Map();
|
|
543
576
|
logArgSlots = 0;
|
|
@@ -565,6 +598,7 @@ export class LlEmitter {
|
|
|
565
598
|
options.wasi === true || ffiExtendsNarrowIntegers(options.targetTriple);
|
|
566
599
|
this.wasi = options.wasi === true;
|
|
567
600
|
this.stacklessGenerators = !this.wasi && mod.workers !== true && this.debug === null;
|
|
601
|
+
this.stackObjects = this.debug === null;
|
|
568
602
|
// An empty triple targets the host, as for executableTls below: the
|
|
569
603
|
// Node-hosted CLI passes none, the native CLI passes its toolchain's, and
|
|
570
604
|
// both must emit the same module for the same target.
|
|
@@ -591,15 +625,14 @@ export class LlEmitter {
|
|
|
591
625
|
this.runtimeAbiMarker = options.runtimeAbiMarker === true;
|
|
592
626
|
this.detachedExit = options.detachedExit === true;
|
|
593
627
|
this.rcHelpers = options.inlineRc === true ? new Set() : null;
|
|
594
|
-
// ScrCycHdr.
|
|
595
|
-
|
|
596
|
-
// double-aligned without changing this ABI offset.
|
|
597
|
-
this.cycleBufferedOffset = 6;
|
|
628
|
+
// ScrCycHdr.buf sits 4 bytes behind every object on every target.
|
|
629
|
+
this.cycleBufOffset = CYC_HDR - CYC_BUF;
|
|
598
630
|
this.ffiCallbackAdapters = allocateFfiCallbackAdapters(mod.ffiImports ?? []);
|
|
599
631
|
this.ffiHasRetainedCallback = hasRetainedFfiCallback(mod.ffiImports ?? []);
|
|
600
632
|
this.ffiHasForeignCallback = hasForeignFfiCallback(mod.ffiImports ?? []);
|
|
601
633
|
for (const fn of mod.functions)
|
|
602
634
|
this.fnByName.set(fn.name, fn);
|
|
635
|
+
this.appendedArrayLiterals = findAppendedArrayLiterals(mod);
|
|
603
636
|
for (const entry of mod.ffiImports ?? []) {
|
|
604
637
|
this.ffiByName.set(entry.name, entry);
|
|
605
638
|
}
|
|
@@ -633,6 +666,13 @@ export class LlEmitter {
|
|
|
633
666
|
// then yields the (borrowed or owned) element pointer, not a stack box.
|
|
634
667
|
// Arrays of such a union are read the same way.
|
|
635
668
|
this.optionalArrayReads = new OptionalArrayReads(this.fnByName, this.unionsById, (id) => this.nullableUnions.has(id));
|
|
669
|
+
this.unionSources = {
|
|
670
|
+
unions: this.boxedUnionsById,
|
|
671
|
+
receiverUnions: this.unionsById,
|
|
672
|
+
nullableField: (e) => this.nullableFieldGet(e) !== null,
|
|
673
|
+
arrayRead: (e) => this.optionalArrayReads.get(e) !== null,
|
|
674
|
+
scalarCall: (e) => this.scalarResultCall(e),
|
|
675
|
+
};
|
|
636
676
|
this.checkedNarrows = new CheckedNarrows(this.fnByName);
|
|
637
677
|
this.referenceEffects = new ReferenceEffects(this.fnByName, (call) => this.optionalArrayReads.get(call) !== null, mod.classes ?? []);
|
|
638
678
|
if (this.debug === null)
|
|
@@ -678,7 +718,7 @@ export class LlEmitter {
|
|
|
678
718
|
walkParameters.set(fn.name, indexes);
|
|
679
719
|
}
|
|
680
720
|
}
|
|
681
|
-
this.callLifetimes = analyzeCallLifetimes(this.fnByName, (className, field) => this.nullableFields.get(className, field) !== null, walkParameters);
|
|
721
|
+
this.callLifetimes = analyzeCallLifetimes(this.fnByName, (className, field) => this.nullableFields.get(className, field) !== null, walkParameters, new Set([...this.int32Abis].filter(([, abi]) => abi.union).map(([name]) => name)));
|
|
682
722
|
this.constantCallbacks = findConstantCallbacks(mod, this.callLifetimes);
|
|
683
723
|
this.stackCallbacks = new StackCallbacks(this.fnByName);
|
|
684
724
|
this.receiverReaders = new AmbientReceiverReaders(this.fnByName);
|
|
@@ -691,7 +731,7 @@ export class LlEmitter {
|
|
|
691
731
|
this.tracedUnions = traced.unions;
|
|
692
732
|
this.shapeHost = {
|
|
693
733
|
sizeType: this.sizeType,
|
|
694
|
-
|
|
734
|
+
cycleBufOffset: this.cycleBufOffset,
|
|
695
735
|
tracedShapes: this.tracedShapes,
|
|
696
736
|
tracedUnions: this.tracedUnions,
|
|
697
737
|
nullableUnions: this.nullableUnions,
|
|
@@ -733,6 +773,7 @@ export class LlEmitter {
|
|
|
733
773
|
pendingTestLines: (dest) => this.pendingTestLines(dest),
|
|
734
774
|
virtualEntry: (implFn) => this.virtualEntry(implFn),
|
|
735
775
|
programLifetime: this.programLifetime,
|
|
776
|
+
regionAliasTag: (word) => this.memoryAliasAttachment(`region.${word}`),
|
|
736
777
|
};
|
|
737
778
|
this.walkers = new LlWalkers(this.shapeHost);
|
|
738
779
|
this.dyn = new LlDyn(this.shapeHost);
|
|
@@ -770,6 +811,17 @@ export class LlEmitter {
|
|
|
770
811
|
// whole-program preorder numbering for instanceof over runtime and
|
|
771
812
|
// compiled error objects, and the per-hierarchy virtual slot lists.
|
|
772
813
|
this.classMeta = buildClassGraph(mod, this.fnByName);
|
|
814
|
+
if (mod.lifetimeRegions === true) {
|
|
815
|
+
this.regions = new LifetimeRegions(this.shapeHost, mod, this.classMeta, (meta) => programLifetimeClass(this.shapeHost, meta), this.nullableFields);
|
|
816
|
+
const regions = this.regions;
|
|
817
|
+
// Member names differ from LifetimeRegions' own, which keeps the
|
|
818
|
+
// record from reading as that class's protocol.
|
|
819
|
+
this.shapeHost.regions = {
|
|
820
|
+
rcBody: (fnName, ret, comment) => regions.countBody(fnName, ret, comment),
|
|
821
|
+
newAlloc: (className, sizeOf) => regions.allocLines(className, sizeOf),
|
|
822
|
+
classDefinitions: (cls, sizeOf) => regions.classDefs(cls, sizeOf),
|
|
823
|
+
};
|
|
824
|
+
}
|
|
773
825
|
for (const [name, rec] of RUNTIME_ERROR_CLASSES) {
|
|
774
826
|
const meta = this.classMeta.get(name);
|
|
775
827
|
if (!meta)
|
|
@@ -1402,6 +1454,7 @@ export class LlEmitter {
|
|
|
1402
1454
|
...emitClassMembershipHelper(this.classMeta, this.sizeType),
|
|
1403
1455
|
...(this.publishWalkersCache?.defs() ?? []),
|
|
1404
1456
|
...this.publishedClassNamesDefs(),
|
|
1457
|
+
...(this.regions?.moduleDefs() ?? []),
|
|
1405
1458
|
];
|
|
1406
1459
|
if (this.constantNumericTables.size > 0)
|
|
1407
1460
|
this.declare(`declare double @scr_arr_get_number(ptr, double)`);
|
|
@@ -1529,8 +1582,8 @@ export class LlEmitter {
|
|
|
1529
1582
|
// half carries the precomputed Map key hash (SCR_STR_HASH_CACHE).
|
|
1530
1583
|
// Bit 31 marks all-ASCII literals (SCR_STR_ASCII_BIT) on every target.
|
|
1531
1584
|
const capWord = this.sizeType === "i64"
|
|
1532
|
-
? literalCapWord(
|
|
1533
|
-
: literalCapWord32(
|
|
1585
|
+
? literalCapWord(wtf8Bytes(text))
|
|
1586
|
+
: literalCapWord32(wtf8Bytes(text));
|
|
1534
1587
|
out.push(`@${lit.sym} = internal global { ${this.sizeType}, ${this.sizeType}, ${this.sizeType}, [${lit.len + 1} x i8] } ` +
|
|
1535
1588
|
`{ ${this.sizeType} -1, ${this.sizeType} ${lit.len}, ${this.sizeType} ${capWord}, [${lit.len + 1} x i8] c"${llStrBytes(text)}" }`);
|
|
1536
1589
|
}
|
|
@@ -1693,6 +1746,12 @@ export class LlEmitter {
|
|
|
1693
1746
|
}
|
|
1694
1747
|
if (this.streamIntervals.length > 0)
|
|
1695
1748
|
out.push(``);
|
|
1749
|
+
if ([...this.literals.keys(), ...this.cstrs.keys()].some(hasLoneSurrogate)) {
|
|
1750
|
+
// The runtime skips surrogate work until a lone surrogate may exist
|
|
1751
|
+
// (scr_wtf8_any); its own producers note one, and literals do here.
|
|
1752
|
+
out.push(`declare void @scr_wtf8_note()`, ``);
|
|
1753
|
+
stamps.push(` call void @scr_wtf8_note()`);
|
|
1754
|
+
}
|
|
1696
1755
|
if (this.errorIntervals.length > 0 && this.tracedShapes.has("object:%Error")) {
|
|
1697
1756
|
// The cycle fixpoint marked the Error hierarchy (a user subclass
|
|
1698
1757
|
// holds cycle-capable fields — capability is hierarchy-uniform), so
|
|
@@ -2140,16 +2199,24 @@ export class LlEmitter {
|
|
|
2140
2199
|
defs.push(`define internal zeroext i1 @sc_str_eq(ptr %a, ptr %b) ${FN_ATTRS} {`, `entry:`, ` %same = icmp eq ptr %a, %b`, ` br i1 %same, label %yes, label %lengths`, `lengths:`, ` %alen.p = getelementptr inbounds %ScrStr, ptr %a, i32 0, i32 1`, ` %blen.p = getelementptr inbounds %ScrStr, ptr %b, i32 0, i32 1`, ` %alen = load ${this.sizeType}, ptr %alen.p`, ` %blen = load ${this.sizeType}, ptr %blen.p`, ` %samelen = icmp eq ${this.sizeType} %alen, %blen`, ` br i1 %samelen, label %bytes, label %no`, `bytes:`, ` %eq = call zeroext i1 @scr_str_eq(ptr %a, ptr %b)`, ` ret i1 %eq`, `yes:`, ` ret i1 true`, `no:`, ` ret i1 false`, `}`, ``);
|
|
2141
2200
|
}
|
|
2142
2201
|
for (const [text, name] of this.literalEqualities) {
|
|
2143
|
-
defs.push(...literalEqualityDefinition(name,
|
|
2202
|
+
defs.push(...literalEqualityDefinition(name, wtf8Bytes(text), this.internLiteral(text), this.sizeType, FN_ATTRS), ``);
|
|
2144
2203
|
}
|
|
2145
2204
|
// String length and charCodeAt read proven-ASCII strings inline: bit 31
|
|
2146
2205
|
// of the capacity word (SCR_STR_ASCII_BIT, the low half's sign bit on
|
|
2147
2206
|
// little-endian targets) makes UTF-16 units bytes. Unproven strings and
|
|
2148
2207
|
// anything but an in-range index take the runtime's UTF-16 mapping.
|
|
2208
|
+
// A scan's receiver reads inline too where runtime state is ordinary
|
|
2209
|
+
// global storage (ScrStrScan; SCR_TL makes it thread-local otherwise).
|
|
2210
|
+
const scanInline = this.mod.workers !== true && this.mod.lib?.threadInstances !== true;
|
|
2211
|
+
let scanDeclared = false;
|
|
2149
2212
|
for (const helper of STRING_READ_HELPERS) {
|
|
2150
2213
|
if (!this.decls.has(helper.decl))
|
|
2151
2214
|
continue;
|
|
2152
|
-
|
|
2215
|
+
if (scanInline && !scanDeclared) {
|
|
2216
|
+
defs.push(stringScanDecl(this.sizeType), ``);
|
|
2217
|
+
scanDeclared = true;
|
|
2218
|
+
}
|
|
2219
|
+
defs.push(...helper.define(this.sizeType, FN_ATTRS, scanInline), ``);
|
|
2153
2220
|
}
|
|
2154
2221
|
// Ordering also decides inline when the first bytes differ: byte order
|
|
2155
2222
|
// is the plain comparison's order, and the UTF-16 order whenever both
|
|
@@ -3197,11 +3264,13 @@ export class LlEmitter {
|
|
|
3197
3264
|
? "ret void"
|
|
3198
3265
|
: this.currentInt32Result
|
|
3199
3266
|
? "ret i32 0"
|
|
3200
|
-
:
|
|
3201
|
-
? `ret
|
|
3202
|
-
: t === "
|
|
3203
|
-
?
|
|
3204
|
-
:
|
|
3267
|
+
: this.currentUnionResult
|
|
3268
|
+
? `ret ${SCALAR_UNION_DUMMY}`
|
|
3269
|
+
: t === "double"
|
|
3270
|
+
? `ret double ${f64Lit(0)}`
|
|
3271
|
+
: t === "i1"
|
|
3272
|
+
? "ret i1 false"
|
|
3273
|
+
: "ret ptr null";
|
|
3205
3274
|
}
|
|
3206
3275
|
// Copy the entries now: later declarations extend these lexical scopes.
|
|
3207
3276
|
// Release order and the handler are part of the shared block's identity.
|
|
@@ -4397,7 +4466,14 @@ export class LlEmitter {
|
|
|
4397
4466
|
this.debug === null ? findScalarStringSlices(fn, this.callLifetimes) : new Map();
|
|
4398
4467
|
this.mapReadLifetimes = findMapReadLifetimes(fn, this.boxedUnionsById, this.callLifetimes);
|
|
4399
4468
|
this.localStackUnions = findLocalStackUnions(fn, this.callLifetimes, this.boxedUnionsById);
|
|
4400
|
-
this.
|
|
4469
|
+
this.localStackObjects = this.stackObjects
|
|
4470
|
+
? findLocalStackObjects(this, fn, this.callLifetimes)
|
|
4471
|
+
: new Map();
|
|
4472
|
+
this.reassignedStackObjects = this.stackObjects
|
|
4473
|
+
? findReassignedStackObjects(this, fn, this.callLifetimes)
|
|
4474
|
+
: new Set();
|
|
4475
|
+
this.stackObjectSlots = new Map();
|
|
4476
|
+
this.localUnionStorageProofs = findLocalUnionStorage(fn, this.callLifetimes, this.unionSources);
|
|
4401
4477
|
this.localUnionStorage = new Map();
|
|
4402
4478
|
this.walkBorrows = this.walkBorrowsByFunction.get(fn.name) ?? new Set();
|
|
4403
4479
|
this.integerRanges = analyzeIntegerRanges(numericFn, this.int32Slots.facts(fn.name));
|
|
@@ -4417,7 +4493,9 @@ export class LlEmitter {
|
|
|
4417
4493
|
this.currentReturnType = fn.returnType;
|
|
4418
4494
|
const int32Abi = this.int32Abis.get(fn.name);
|
|
4419
4495
|
this.currentInt32Result = int32Abi?.result === true;
|
|
4496
|
+
this.currentUnionResult = int32Abi?.union === true;
|
|
4420
4497
|
this.currentGenerator = fn.generator ?? null;
|
|
4498
|
+
this.currentAsyncGenerator = fn.async === true && fn.generator !== undefined;
|
|
4421
4499
|
this.currentBorrowedReturn = this.borrowedReturns.has(fn.name);
|
|
4422
4500
|
this.inConstructor = this.constructorFunctions.has(fn.name);
|
|
4423
4501
|
this.currentCoro = null;
|
|
@@ -4604,6 +4682,9 @@ export class LlEmitter {
|
|
|
4604
4682
|
// whose unwind released everything down to depth 0).
|
|
4605
4683
|
if (fn.returnType.kind === "void" && !B.isTerminated()) {
|
|
4606
4684
|
this.releaseScope(this.scopes[0]);
|
|
4685
|
+
// Completing by falling off the end has nothing to await.
|
|
4686
|
+
if (this.currentAsyncGenerator)
|
|
4687
|
+
this.emitAsyncGenSettled();
|
|
4607
4688
|
if (this.currentCoro !== null) {
|
|
4608
4689
|
this.emitWasiFulfill(null);
|
|
4609
4690
|
B.terminate(`br label %${this.currentCoro.finalLabel}`);
|
|
@@ -4681,7 +4762,11 @@ export class LlEmitter {
|
|
|
4681
4762
|
// Lifted functions receive their closure first (the callValue ABI).
|
|
4682
4763
|
if (fn.captures !== undefined)
|
|
4683
4764
|
params.unshift("ptr %sc_env");
|
|
4684
|
-
const ret = int32Abi?.result
|
|
4765
|
+
const ret = int32Abi?.result
|
|
4766
|
+
? "i32"
|
|
4767
|
+
: int32Abi?.union
|
|
4768
|
+
? SCALAR_UNION_RESULT
|
|
4769
|
+
: this.llType(fn.returnType);
|
|
4685
4770
|
let attrs = coro !== null ? "#1" : FN_ATTRS;
|
|
4686
4771
|
// The shared indexed-read helper (lowerSafeIndexRead) is a dense bounds
|
|
4687
4772
|
// test, a state test and a load behind cold runtime fallbacks, called
|
|
@@ -4721,7 +4806,19 @@ export class LlEmitter {
|
|
|
4721
4806
|
args.push(`${type} %p${index}`);
|
|
4722
4807
|
});
|
|
4723
4808
|
const ret = this.llType(fn.returnType);
|
|
4724
|
-
const
|
|
4809
|
+
const entry = `@${symbol}${INT32_ABI_SUFFIX}(${args.join(", ")})`;
|
|
4810
|
+
if (abi.union) {
|
|
4811
|
+
// Box the register pair for every caller of the ordinary ABI.
|
|
4812
|
+
const B = new BlockBuilder();
|
|
4813
|
+
this.B = B;
|
|
4814
|
+
for (const line of lines)
|
|
4815
|
+
B.line(line.trim());
|
|
4816
|
+
const pair = B.tmp();
|
|
4817
|
+
B.line(`${pair} = call ${SCALAR_UNION_RESULT} ${entry}`);
|
|
4818
|
+
B.terminate(`ret ptr ${this.boxScalarUnion(pair, fn.returnType)}`);
|
|
4819
|
+
return `define internal ptr @${symbol}(${params.join(", ")}) ${FN_ATTRS} {\n${B.render()}\n}`;
|
|
4820
|
+
}
|
|
4821
|
+
const call = `call ${abi.result ? "i32" : ret} ${entry}`;
|
|
4725
4822
|
if (ret === "void")
|
|
4726
4823
|
lines.push(` ${call}`, " ret void");
|
|
4727
4824
|
else if (abi.result)
|
|
@@ -4730,6 +4827,73 @@ export class LlEmitter {
|
|
|
4730
4827
|
lines.push(` %r = ${call}`, ` ret ${ret} %r`);
|
|
4731
4828
|
return `define internal ${ret} @${symbol}(${params.join(", ")}) ${FN_ATTRS} {\nentry:\n${lines.join("\n")}\n}`;
|
|
4732
4829
|
}
|
|
4830
|
+
/** The SCALAR_UNION_RESULT pair of a `%ScrUnion` box of `type`. */
|
|
4831
|
+
scalarUnionPair(box, type) {
|
|
4832
|
+
const B = this.B;
|
|
4833
|
+
const unionId = type.kind === "union" ? type.unionId : "";
|
|
4834
|
+
const tag = this.unionTag(box, unionId);
|
|
4835
|
+
const payload = B.tmp(), bits = B.tmp(), partial = B.tmp(), pair = B.tmp();
|
|
4836
|
+
B.line(`${payload} = getelementptr inbounds %ScrUnion, ptr ${box}, i32 0, i32 5`);
|
|
4837
|
+
B.line(`${bits} = load i64, ptr ${payload}`);
|
|
4838
|
+
B.line(`${partial} = insertvalue ${SCALAR_UNION_RESULT} poison, i32 ${tag}, 0`);
|
|
4839
|
+
B.line(`${pair} = insertvalue ${SCALAR_UNION_RESULT} ${partial}, i64 ${bits}, 1`);
|
|
4840
|
+
return pair;
|
|
4841
|
+
}
|
|
4842
|
+
/** A private stack box holding a SCALAR_UNION_RESULT pair of `type`. */
|
|
4843
|
+
stackScalarUnion(pair, type) {
|
|
4844
|
+
const B = this.B;
|
|
4845
|
+
const box = B.slot(), tagSlot = B.slot(), payloadSlot = B.slot();
|
|
4846
|
+
B.entryAllocas.push(`${box} = alloca %ScrUnion`);
|
|
4847
|
+
B.entryAllocas.push(`${tagSlot} = getelementptr inbounds %ScrUnion, ptr ${box}, i32 0, i32 1`);
|
|
4848
|
+
B.entryAllocas.push(`${payloadSlot} = getelementptr inbounds %ScrUnion, ptr ${box}, i32 0, i32 5`);
|
|
4849
|
+
const tag = B.tmp(), bits = B.tmp();
|
|
4850
|
+
B.line(`${tag} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 0`);
|
|
4851
|
+
B.line(`${bits} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 1`);
|
|
4852
|
+
B.line(`store i32 ${tag}, ptr ${tagSlot}`);
|
|
4853
|
+
B.line(`store i64 ${bits}, ptr ${payloadSlot}`);
|
|
4854
|
+
return { name: box, type };
|
|
4855
|
+
}
|
|
4856
|
+
/** A direct call whose i32 entry returns its scalar union in registers. */
|
|
4857
|
+
scalarResultCall(e) {
|
|
4858
|
+
return e.kind === "call" && this.int32Abis.get(e.callee)?.union === true;
|
|
4859
|
+
}
|
|
4860
|
+
/** A fresh heap box (+1) for a SCALAR_UNION_RESULT pair of `type`; the
|
|
4861
|
+
* exception dummy (tag -1) answers NULL. */
|
|
4862
|
+
boxScalarUnion(pair, type) {
|
|
4863
|
+
const B = this.B;
|
|
4864
|
+
const unionId = type.kind === "union" ? type.unionId : "";
|
|
4865
|
+
const arms = this.unionsById.get(unionId).arms;
|
|
4866
|
+
const tag = B.tmp(), bits = B.tmp();
|
|
4867
|
+
B.line(`${tag} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 0`);
|
|
4868
|
+
B.line(`${bits} = extractvalue ${SCALAR_UNION_RESULT} ${pair}, 1`);
|
|
4869
|
+
const join = B.newLabel("union.box.join"), none = B.newLabel("union.box.none");
|
|
4870
|
+
const labels = arms.map(() => B.newLabel("union.box.arm"));
|
|
4871
|
+
B.terminate(`switch i32 ${tag}, label %${none} [ ${labels.map((label, armTag) => `i32 ${armTag}, label %${label}`).join(" ")} ]`);
|
|
4872
|
+
const incoming = [];
|
|
4873
|
+
arms.forEach((arm, armTag) => {
|
|
4874
|
+
B.startBlock(labels[armTag]);
|
|
4875
|
+
let value;
|
|
4876
|
+
if (isUnitType(arm))
|
|
4877
|
+
value = this.unitInstanceRef(unionId, armTag);
|
|
4878
|
+
else {
|
|
4879
|
+
const payload = B.tmp();
|
|
4880
|
+
if (arm.kind === "bool")
|
|
4881
|
+
B.line(`${payload} = trunc i64 ${bits} to i1`);
|
|
4882
|
+
else
|
|
4883
|
+
B.line(`${payload} = bitcast i64 ${bits} to double`);
|
|
4884
|
+
value = this.unionNewOwned(unionId, armTag, { name: payload, type: arm });
|
|
4885
|
+
}
|
|
4886
|
+
incoming.push(`[ ${value}, %${B.currentLabel()} ]`);
|
|
4887
|
+
B.br(join);
|
|
4888
|
+
});
|
|
4889
|
+
B.startBlock(none);
|
|
4890
|
+
incoming.push(`[ null, %${none} ]`);
|
|
4891
|
+
B.br(join);
|
|
4892
|
+
B.startBlock(join);
|
|
4893
|
+
const box = B.tmp();
|
|
4894
|
+
B.line(`${box} = phi ptr ${incoming.join(", ")}`);
|
|
4895
|
+
return box;
|
|
4896
|
+
}
|
|
4733
4897
|
/** The i32 bits of a number proven an int32 (a direct call's i32
|
|
4734
4898
|
* argument or an i32 result): its exact integer when the value carries
|
|
4735
4899
|
* one, else the conversion the proof makes exact. */
|
|
@@ -5000,6 +5164,12 @@ export class LlEmitter {
|
|
|
5000
5164
|
this.finallyStack = savedFinally;
|
|
5001
5165
|
this.tryStack = savedTry;
|
|
5002
5166
|
}
|
|
5167
|
+
/** An async generator completing without a further turn: its request
|
|
5168
|
+
* settles as the body returns (scr_async_gen_hop_done). */
|
|
5169
|
+
emitAsyncGenSettled() {
|
|
5170
|
+
this.declare(`declare void @scr_async_gen_hop_done()`);
|
|
5171
|
+
this.B.line(`call void @scr_async_gen_hop_done()`);
|
|
5172
|
+
}
|
|
5003
5173
|
/** `return x` of a local whose slot is an owned scope entry of the same
|
|
5004
5174
|
* type: the return can take over the local's reference. */
|
|
5005
5175
|
movableReturn(value) {
|
|
@@ -5200,6 +5370,17 @@ export class LlEmitter {
|
|
|
5200
5370
|
this.scopes[this.scopes.length - 1].push({ slot: snapshot.sourceSlot, type: STRING }, { slot: snapshot.separatorSlot, type: STRING });
|
|
5201
5371
|
break;
|
|
5202
5372
|
}
|
|
5373
|
+
const stackObject = this.localStackObjects.get(s.localId);
|
|
5374
|
+
if (stackObject) {
|
|
5375
|
+
B.line(`store ptr ${emitStackObject(this, stackObject).name}, ptr ${b.slot}`);
|
|
5376
|
+
break;
|
|
5377
|
+
}
|
|
5378
|
+
if (s.init && this.reassignedStackObjects.has(s.localId)) {
|
|
5379
|
+
const slot = this.stackObjectSlot(s.localId, s.init.type);
|
|
5380
|
+
emitStackObject(this, s.init, slot);
|
|
5381
|
+
B.line(`store ptr ${slot}, ptr ${b.slot}`);
|
|
5382
|
+
break;
|
|
5383
|
+
}
|
|
5203
5384
|
const localUnion = this.localStackUnions.get(s.localId);
|
|
5204
5385
|
if (localUnion) {
|
|
5205
5386
|
const union = emitStackUnion(this, localUnion);
|
|
@@ -5347,6 +5528,15 @@ export class LlEmitter {
|
|
|
5347
5528
|
B.line(`store ptr ${v.name}, ptr ${owner}`);
|
|
5348
5529
|
break;
|
|
5349
5530
|
}
|
|
5531
|
+
if (this.reassignedStackObjects.has(s.localId)) {
|
|
5532
|
+
// The new value may read the old one: build it apart, then copy.
|
|
5533
|
+
const struct = stackObjectStruct(s.value.type);
|
|
5534
|
+
const value = emitStackObject(this, s.value);
|
|
5535
|
+
const bits = B.tmp();
|
|
5536
|
+
B.line(`${bits} = load ${struct}, ptr ${value.name}`);
|
|
5537
|
+
B.line(`store ${struct} ${bits}, ptr ${this.stackObjectSlot(s.localId, s.value.type)}`);
|
|
5538
|
+
break;
|
|
5539
|
+
}
|
|
5350
5540
|
const localStorage = this.localUnionStorage.get(s.localId);
|
|
5351
5541
|
if (localStorage) {
|
|
5352
5542
|
storeLocalUnion(this, localStorage, s.value);
|
|
@@ -6199,8 +6389,16 @@ export class LlEmitter {
|
|
|
6199
6389
|
break;
|
|
6200
6390
|
}
|
|
6201
6391
|
let v = null;
|
|
6202
|
-
const moved = this.finallyStack.length === 0
|
|
6203
|
-
|
|
6392
|
+
const moved = this.finallyStack.length === 0 && !this.currentUnionResult
|
|
6393
|
+
? this.movableReturn(s.value)
|
|
6394
|
+
: null;
|
|
6395
|
+
if (s.value !== null && this.currentUnionResult) {
|
|
6396
|
+
// The tag and payload bits leave in registers; a heap box the
|
|
6397
|
+
// value needed is released with its frame below.
|
|
6398
|
+
const box = this.emitUnionProjection(s.value);
|
|
6399
|
+
v = { name: this.scalarUnionPair(box.name, s.value.type), type: s.value.type };
|
|
6400
|
+
}
|
|
6401
|
+
else if (moved !== null) {
|
|
6204
6402
|
// Returning an owned local hands its reference to the caller: no
|
|
6205
6403
|
// retain now and no release of the local below.
|
|
6206
6404
|
const t = B.tmp();
|
|
@@ -6230,9 +6428,22 @@ export class LlEmitter {
|
|
|
6230
6428
|
v = this.emitExpr(s.value);
|
|
6231
6429
|
this.moveTemp(v);
|
|
6232
6430
|
}
|
|
6431
|
+
// An async generator's `return v` awaits v before any crossed
|
|
6432
|
+
// finally runs. Past finally regions that turn is taken here and
|
|
6433
|
+
// the request settles at completion; otherwise the completion's
|
|
6434
|
+
// own turn is the await (nothing runs in between).
|
|
6435
|
+
const genSettles = this.currentAsyncGenerator && (s.awaited === true || this.finallyStack.length > 0);
|
|
6436
|
+
if (this.currentAsyncGenerator && s.awaited !== true && this.finallyStack.length > 0) {
|
|
6437
|
+
if (this.wasi)
|
|
6438
|
+
this.emitWasiSuspend(null);
|
|
6439
|
+
else {
|
|
6440
|
+
this.declare(`declare void @scr_await_hop()`);
|
|
6441
|
+
B.line(`call void @scr_await_hop()`);
|
|
6442
|
+
}
|
|
6443
|
+
}
|
|
6233
6444
|
if (this.finallyStack.length > 0) {
|
|
6234
6445
|
let pretSlot = null;
|
|
6235
|
-
if (v !== null && isRefCounted(v.type)) {
|
|
6446
|
+
if (v !== null && isRefCounted(v.type) && !this.currentUnionResult) {
|
|
6236
6447
|
pretSlot = B.slot();
|
|
6237
6448
|
B.entryAllocas.push(`${pretSlot} = alloca ptr ; pending return (through finally)`);
|
|
6238
6449
|
B.line(`store ptr ${v.name}, ptr ${pretSlot}`);
|
|
@@ -6265,6 +6476,8 @@ export class LlEmitter {
|
|
|
6265
6476
|
this.releaseForJump(0, 0);
|
|
6266
6477
|
}
|
|
6267
6478
|
if (!B.isTerminated()) {
|
|
6479
|
+
if (genSettles)
|
|
6480
|
+
this.emitAsyncGenSettled();
|
|
6268
6481
|
if (this.currentCoro !== null) {
|
|
6269
6482
|
this.emitWasiFulfill(v);
|
|
6270
6483
|
B.terminate(`br label %${this.currentCoro.finalLabel}`);
|
|
@@ -6273,6 +6486,8 @@ export class LlEmitter {
|
|
|
6273
6486
|
B.terminate("ret void");
|
|
6274
6487
|
else if (this.currentInt32Result)
|
|
6275
6488
|
B.terminate(`ret i32 ${this.int32Argument(v, s.value)}`);
|
|
6489
|
+
else if (this.currentUnionResult)
|
|
6490
|
+
B.terminate(`ret ${SCALAR_UNION_RESULT} ${v.name}`);
|
|
6276
6491
|
else
|
|
6277
6492
|
B.terminate(`ret ${this.llType(s.value.type)} ${v.name}`);
|
|
6278
6493
|
}
|
|
@@ -6787,8 +7002,45 @@ export class LlEmitter {
|
|
|
6787
7002
|
emitIntrinsicExpr(e) {
|
|
6788
7003
|
if (e.name === "threads.publish")
|
|
6789
7004
|
return this.emitPublish(e);
|
|
7005
|
+
if (e.name === "region.create" ||
|
|
7006
|
+
e.name === "region.enter" ||
|
|
7007
|
+
e.name === "region.leave" ||
|
|
7008
|
+
e.name === "region.release")
|
|
7009
|
+
return this.emitRegionIntrinsic(e);
|
|
6790
7010
|
return emitIntrinsicExpr(this, e);
|
|
6791
7011
|
}
|
|
7012
|
+
/** Lifetime regions in modules with lifetimeRegions (llvm/regions.ts).
|
|
7013
|
+
* Created with the class graph; null elsewhere. */
|
|
7014
|
+
regions = null;
|
|
7015
|
+
/** LifetimeRegion's runtime calls: create answers the region id, enter
|
|
7016
|
+
* and leave bracket run(), release condemns. */
|
|
7017
|
+
emitRegionIntrinsic(e) {
|
|
7018
|
+
if (this.regions === null)
|
|
7019
|
+
throw new InternalCompilerError(`llvm emitter bug: ${e.name} without lifetimeRegions`);
|
|
7020
|
+
const args = e.args.map((a) => this.emitExpr(a));
|
|
7021
|
+
if (this.B.isTerminated())
|
|
7022
|
+
return { name: "", type: e.type };
|
|
7023
|
+
switch (e.name) {
|
|
7024
|
+
case "region.create": {
|
|
7025
|
+
this.declare(`declare double @scr_region_create(ptr)`);
|
|
7026
|
+
const id = this.B.tmp();
|
|
7027
|
+
this.B.line(`${id} = call double @scr_region_create(ptr ${REGION_TYPES})`);
|
|
7028
|
+
return { name: id, type: e.type };
|
|
7029
|
+
}
|
|
7030
|
+
case "region.enter":
|
|
7031
|
+
this.declare(`declare void @scr_region_enter(double)`);
|
|
7032
|
+
this.B.line(`call void @scr_region_enter(double ${args[0].name})`);
|
|
7033
|
+
break;
|
|
7034
|
+
case "region.leave":
|
|
7035
|
+
this.declare(`declare void @scr_region_leave()`);
|
|
7036
|
+
this.B.line(`call void @scr_region_leave()`);
|
|
7037
|
+
break;
|
|
7038
|
+
default:
|
|
7039
|
+
this.declare(`declare void @scr_region_release(double)`);
|
|
7040
|
+
this.B.line(`call void @scr_region_release(double ${args[0].name})`);
|
|
7041
|
+
}
|
|
7042
|
+
return { name: "", type: e.type };
|
|
7043
|
+
}
|
|
6792
7044
|
publishWalkersCache = null;
|
|
6793
7045
|
/** Per-type publication walkers, created on the first publish. */
|
|
6794
7046
|
get publishWalkers() {
|
|
@@ -7075,10 +7327,30 @@ export class LlEmitter {
|
|
|
7075
7327
|
B.line(`${value} = load ptr, ptr ${slot}`);
|
|
7076
7328
|
return { name: value, type: e.type };
|
|
7077
7329
|
}
|
|
7330
|
+
// Scalar optional values and register results answer a private stack
|
|
7331
|
+
// box. A ternary of borrowable arms above keeps lending its arm.
|
|
7332
|
+
if ((e.kind === "optChain" ||
|
|
7333
|
+
e.kind === "nullish" ||
|
|
7334
|
+
e.kind === "ternary" ||
|
|
7335
|
+
e.kind === "arrIntrinsic") &&
|
|
7336
|
+
isScalarOptionalSource(e, this.unionSources))
|
|
7337
|
+
return emitScalarOptional(this, e);
|
|
7338
|
+
if (e.kind === "call" && this.scalarResultCall(e))
|
|
7339
|
+
return emitCallExpr(this, e, false, true);
|
|
7078
7340
|
if (e.kind === "call" && this.canBorrowReceiver(e))
|
|
7079
7341
|
return emitBorrowedResultCall(this, e);
|
|
7080
7342
|
return this.emitExpr(e);
|
|
7081
7343
|
}
|
|
7344
|
+
/** The frame slot a reassigned stack-object local keeps for its value. */
|
|
7345
|
+
stackObjectSlot(localId, type) {
|
|
7346
|
+
let slot = this.stackObjectSlots.get(localId);
|
|
7347
|
+
if (slot === undefined) {
|
|
7348
|
+
slot = this.B.slot();
|
|
7349
|
+
this.B.entryAllocas.push(`${slot} = alloca ${stackObjectStruct(type)}, align 8`);
|
|
7350
|
+
this.stackObjectSlots.set(localId, slot);
|
|
7351
|
+
}
|
|
7352
|
+
return slot;
|
|
7353
|
+
}
|
|
7082
7354
|
/** A private stack union source with an independently owned payload. */
|
|
7083
7355
|
canStackReceiver(e) {
|
|
7084
7356
|
return this.isStackUnionSource(e);
|
|
@@ -7090,7 +7362,9 @@ export class LlEmitter {
|
|
|
7090
7362
|
return false;
|
|
7091
7363
|
return (canStackUnion(e, this.boxedUnionsById) ||
|
|
7092
7364
|
matchMapRead(e, this.boxedUnionsById) !== null ||
|
|
7093
|
-
this.optionalArrayReads.get(e) !== null
|
|
7365
|
+
this.optionalArrayReads.get(e) !== null ||
|
|
7366
|
+
isScalarOptionalSource(e, this.unionSources) ||
|
|
7367
|
+
this.scalarResultCall(e));
|
|
7094
7368
|
}
|
|
7095
7369
|
/** The nullable-pointer representation behind a union-typed class field
|
|
7096
7370
|
* read, or null for every other expression. */
|