@yabgu_gm/tensionscript 0.10.0 → 0.11.1
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/README.md +8 -10
- package/dist/asc.generated.d.ts +268 -17
- package/dist/asc.js +18 -1
- package/dist/asc.js.map +2 -2
- package/dist/assemblyscript.generated.d.ts +268 -17
- package/dist/assemblyscript.js +145 -145
- package/dist/assemblyscript.js.map +3 -3
- package/dist/importmap.json +2 -2
- package/dist/web.js +3 -3
- package/package.json +1 -1
- package/std/assembly/builtins.ts +15 -0
- package/std/assembly/index.d.ts +2 -0
|
@@ -614,7 +614,14 @@ declare module "types:tensionscript/src/diagnosticMessages.generated" {
|
|
|
614
614
|
A_spawn_produces_a_Task_this_one_is_never_awaited_so_the_task_s_result_is_discarded = 6401,
|
|
615
615
|
An_await_forces_an_immediate_read_of_lazy_so_the_deferral_is_nullified_drop_the_lazy_or_remove_the_await = 6402,
|
|
616
616
|
An_enum_underlying_type_must_be_one_of_i8_u8_i16_u16_i32_or_u32_not_0 = 6403,
|
|
617
|
-
Enum_member_0_does_not_fit_the_underlying_type_1 = 6404
|
|
617
|
+
Enum_member_0_does_not_fit_the_underlying_type_1 = 6404,
|
|
618
|
+
_abi_align_requires_a_single_integer_literal_argument_the_alignment_is_a_compile_time_constant_so_a_computed_value_cannot_be_read_where_the_layout_is_decided = 6405,
|
|
619
|
+
_abi_align_0_the_alignment_must_be_at_least_1 = 6406,
|
|
620
|
+
_abi_align_0_the_alignment_must_be_a_power_of_two = 6407,
|
|
621
|
+
_abi_align_0_is_less_than_the_field_type_s_natural_alignment_1_asking_for_less_is_a_lie_so_it_is_refused_rather_than_silently_ignored = 6408,
|
|
622
|
+
_abi_align_0_is_too_large_the_maximum_is_1 = 6409,
|
|
623
|
+
Alignment_is_a_property_of_the_field_not_its_type_Place_abi_align_N_on_the_field_declaration = 6410,
|
|
624
|
+
A_view_parameter_unmanaged_0_over_an_inline_type_cannot_appear_in_a_host_visible_signature_an_external_or_exported_parameter_is_supplied_by_the_host_and_a_view_is_an_address_this_compiler_did_not_materialise = 6411
|
|
618
625
|
}
|
|
619
626
|
/** Translates a diagnostic code to its respective string. */
|
|
620
627
|
export function diagnosticCodeToString(code: DiagnosticCode): string;
|
|
@@ -2681,8 +2688,9 @@ declare module "types:tensionscript/src/types" {
|
|
|
2681
2688
|
* own model is still on the `Type`
|
|
2682
2689
|
* (`type.classReference.hasDecorator(...)`). The boundary emitters want both —
|
|
2683
2690
|
* the override decides *how the parameter crosses*, the type decides what may
|
|
2684
|
-
* be done with it.
|
|
2685
|
-
*
|
|
2691
|
+
* be done with it. Rooting deliberately reads only the second: the override
|
|
2692
|
+
* says how the parameter crosses, while the type says what may be done with
|
|
2693
|
+
* it.
|
|
2686
2694
|
*/
|
|
2687
2695
|
memoryModelOf(sourceIndex: number): number;
|
|
2688
2696
|
/**
|
|
@@ -2699,6 +2707,21 @@ declare module "types:tensionscript/src/types" {
|
|
|
2699
2707
|
* all of them.
|
|
2700
2708
|
*/
|
|
2701
2709
|
static wasmParamCountOf(type: Type): number;
|
|
2710
|
+
/**
|
|
2711
|
+
* Appends the **leaf** types of an `@inline struct`, in declaration order,
|
|
2712
|
+
* depth first.
|
|
2713
|
+
*
|
|
2714
|
+
* A leaf is a field that occupies one WASM local: a scalar or a reference. A
|
|
2715
|
+
* field whose type is itself an `@inline struct` is not a leaf — it is several
|
|
2716
|
+
* locals behind a map — so the walk recurses into it. This is the type-level
|
|
2717
|
+
* twin of the `fieldLocals` tree the compiler builds
|
|
2718
|
+
* (`Compiler#fillSroaFieldLocals`), and the two must agree in **order** as
|
|
2719
|
+
* well as count: the callee binds WASM parameter *k* to the *k*th leaf, and
|
|
2720
|
+
* the caller pushes operands in the same walk.
|
|
2721
|
+
*/
|
|
2722
|
+
static leafTypesOf(type: Type, out: Type[]): void;
|
|
2723
|
+
/** The number of leaf locals an `@inline struct` occupies. */
|
|
2724
|
+
static leafCountOf(type: Type): number;
|
|
2702
2725
|
/**
|
|
2703
2726
|
* How many WASM operands **this signature** spends on source parameter
|
|
2704
2727
|
* `sourceIndex`.
|
|
@@ -2715,6 +2738,18 @@ declare module "types:tensionscript/src/types" {
|
|
|
2715
2738
|
* the same source parameter.
|
|
2716
2739
|
*/
|
|
2717
2740
|
wasmParamSlotCountOf(sourceIndex: number): number;
|
|
2741
|
+
/**
|
|
2742
|
+
* Whether source parameter `sourceIndex` is a **view**: `@unmanaged` at the
|
|
2743
|
+
* declaration over a type that is an `@inline struct`.
|
|
2744
|
+
*
|
|
2745
|
+
* The type still says *value* — every use of `MyStruct` shares one `Type`, and
|
|
2746
|
+
* that is what makes a member lookup work on the parameter — while the model
|
|
2747
|
+
* says this use is an address. One `i32` slot, no field locals, a load at the
|
|
2748
|
+
* field's offset: the same crossing an `@unmanaged struct` parameter already
|
|
2749
|
+
* takes, with the model recorded at the declaration instead of on a pointer
|
|
2750
|
+
* type.
|
|
2751
|
+
*/
|
|
2752
|
+
isViewParam(sourceIndex: number): boolean;
|
|
2718
2753
|
/**
|
|
2719
2754
|
* Whether source parameter `sourceIndex` **crosses by value** — one `i32`
|
|
2720
2755
|
* address instead of one WASM operand per field.
|
|
@@ -2728,8 +2763,12 @@ declare module "types:tensionscript/src/types" {
|
|
|
2728
2763
|
* address, and the override asks for a copy of what is there — the same
|
|
2729
2764
|
* copy, read from memory instead of from SROA locals.
|
|
2730
2765
|
*
|
|
2731
|
-
* The reverse is
|
|
2732
|
-
* declaration is
|
|
2766
|
+
* The reverse is partly a thing now. `@unmanaged` over an `@inline`
|
|
2767
|
+
* declaration is legal where the use supplies an address — a parameter (a
|
|
2768
|
+
* view parameter, `isViewParam`) or `changetype`'s type argument — and a view
|
|
2769
|
+
* parameter crosses as a pointer, so it is asked before this predicate. Every
|
|
2770
|
+
* other cell still refuses (`TS6395`), and `@managed` over `@inline` refuses
|
|
2771
|
+
* at every position: a value has no GC header and no address to lend.
|
|
2733
2772
|
*/
|
|
2734
2773
|
crossesByValueParam(sourceIndex: number): boolean;
|
|
2735
2774
|
/**
|
|
@@ -2752,9 +2791,17 @@ declare module "types:tensionscript/src/types" {
|
|
|
2752
2791
|
get byValPointerParams(): boolean;
|
|
2753
2792
|
/** Whether `type` is an `@inline struct`. */
|
|
2754
2793
|
static isInlineStructRef(type: Type): boolean;
|
|
2755
|
-
/**
|
|
2756
|
-
*
|
|
2757
|
-
*
|
|
2794
|
+
/**
|
|
2795
|
+
* How many **WASM slots** an `@inline struct` spends — its leaf count.
|
|
2796
|
+
*
|
|
2797
|
+
* Leaf count, not direct-field count: a nested inline field is several locals,
|
|
2798
|
+
* so `Outer1 { a: u32; inner: Inner{x,y} }` is 3, not 2. A record with no
|
|
2799
|
+
* members is 0.
|
|
2800
|
+
*
|
|
2801
|
+
* Callers that made sense of "direct fields" are listed in the Phase C audit
|
|
2802
|
+
* (`docs`); the one place that genuinely needs the direct count is layout, and
|
|
2803
|
+
* layout reads `members` itself rather than asking this.
|
|
2804
|
+
*/
|
|
2758
2805
|
static fieldCountOf(type: Type): number;
|
|
2759
2806
|
/**
|
|
2760
2807
|
* Whether a call to this signature passes a hidden destination pointer.
|
|
@@ -3088,6 +3135,60 @@ declare module "types:tensionscript/src/resolver" {
|
|
|
3088
3135
|
currentElementExpression: Expression | null;
|
|
3089
3136
|
/** Whether a new override has been discovered. */
|
|
3090
3137
|
discoveredOverride: boolean;
|
|
3138
|
+
/**
|
|
3139
|
+
* Whether a use-site `@unmanaged` over an `@inline` declaration is being
|
|
3140
|
+
* resolved as the **type argument of `changetype`**.
|
|
3141
|
+
*
|
|
3142
|
+
* That position is the one where the operand can supply the address the value
|
|
3143
|
+
* itself does not have, so the refusal's premise does not hold there (see
|
|
3144
|
+
* `checkMemoryModelOverride`). Every other position — a parameter, a local, a
|
|
3145
|
+
* field, a return type — still refuses with `TS6395`, which is what keeps the
|
|
3146
|
+
* function-parameter form (`Phase 2`) out of this change.
|
|
3147
|
+
*
|
|
3148
|
+
* The compiler sets this around the one `resolveTypeArguments` call it makes
|
|
3149
|
+
* for a `changetype` builtin (`Compiler#compileCallExpressionBuiltin`), and
|
|
3150
|
+
* resets it immediately: the flag is a scope, not a mode.
|
|
3151
|
+
*/
|
|
3152
|
+
allowInlineView: boolean;
|
|
3153
|
+
/**
|
|
3154
|
+
* Whether a use-site `@unmanaged` over an `@inline` declaration is being
|
|
3155
|
+
* resolved in a **parameter position** — the cell where the caller supplies
|
|
3156
|
+
* the address, so `f(a: @unmanaged T)` with an inline `T` is a view parameter.
|
|
3157
|
+
*
|
|
3158
|
+
* Distinct from {@link allowInlineView} (Phase 1, `changetype`'s type
|
|
3159
|
+
* argument, where the operand supplies the address at the point of use).
|
|
3160
|
+
*
|
|
3161
|
+
* **Saved and restored, never blindly cleared.** Resolving one parameter's
|
|
3162
|
+
* type can resolve another function (a default value's call, a nested
|
|
3163
|
+
* signature), and a nested window that reset the flag to `false` on the way
|
|
3164
|
+
* out closed the outer window — measured: the owner's pattern reported TS6395
|
|
3165
|
+
* with both flags reading `false` while inside `resolveFunction`'s own loop.
|
|
3166
|
+
*/
|
|
3167
|
+
allowInlineViewParam: boolean;
|
|
3168
|
+
/**
|
|
3169
|
+
* Call expressions that are **views of caller bytes**: an inline-typed
|
|
3170
|
+
* `changetype<@unmanaged T>(ptr)`.
|
|
3171
|
+
*
|
|
3172
|
+
* Marked here, at resolution, because the compiler asks this question while
|
|
3173
|
+
* compiling the *field access* — which happens before the `changetype` it
|
|
3174
|
+
* wraps is ever compiled. Recording it at codegen time (the first attempt)
|
|
3175
|
+
* produced a field read that never saw the mark and compiled to
|
|
3176
|
+
* `unreachable`.
|
|
3177
|
+
*
|
|
3178
|
+
* Keyed on the AST node rather than on the type, because the type is the
|
|
3179
|
+
* declaration's (`T` is still an `@inline struct`) and the model is the
|
|
3180
|
+
* *use's*: there is one `Type` per class, shared by every use.
|
|
3181
|
+
*/
|
|
3182
|
+
private viewCalls;
|
|
3183
|
+
/**
|
|
3184
|
+
* Records `node` as a view call. The resolver marks the ones it resolves;
|
|
3185
|
+
* `Compiler#compileCallExpressionBuiltin` marks the ones it resolves itself,
|
|
3186
|
+
* because a builtin's type arguments are resolved on the *codegen* path and
|
|
3187
|
+
* never pass through `maybeInferCall`.
|
|
3188
|
+
*/
|
|
3189
|
+
markViewCall(node: Expression): void;
|
|
3190
|
+
/** Whether `node` is an inline-typed `changetype<@unmanaged T>(...)`. */
|
|
3191
|
+
isViewCall(node: Expression): boolean;
|
|
3091
3192
|
/** Constructs the resolver for the specified program. */
|
|
3092
3193
|
constructor(
|
|
3093
3194
|
/** The program to construct a resolver for. */
|
|
@@ -3115,10 +3216,14 @@ declare module "types:tensionscript/src/resolver" {
|
|
|
3115
3216
|
* - **`@managed` over an `@unmanaged` declaration** — the collector traces a
|
|
3116
3217
|
* reference through a header the record does not have. No emitter can
|
|
3117
3218
|
* invent the header, so a use cannot confer provenance. (`TS6394`.)
|
|
3118
|
-
* - **`@
|
|
3119
|
-
*
|
|
3120
|
-
*
|
|
3121
|
-
* (
|
|
3219
|
+
* - **`@managed` over an `@inline` declaration** — a value has neither a
|
|
3220
|
+
* header nor an address, at any position. (`TS6395`.)
|
|
3221
|
+
* - **`@unmanaged` over an `@inline` declaration**, *except* where the use
|
|
3222
|
+
* supplies an address: `changetype`'s type argument (the operand supplies
|
|
3223
|
+
* it) and a parameter (the caller supplies it). Those two windows are
|
|
3224
|
+
* `allowInlineView` and `allowInlineViewParam`, and they are the whole
|
|
3225
|
+
* difference between a view and a claim. Every other position — a return
|
|
3226
|
+
* type, a local, a field — still has nothing to lend. (`TS6395`.)
|
|
3122
3227
|
*
|
|
3123
3228
|
* Everything else is left to the emitters: `@unmanaged` over `@managed` is
|
|
3124
3229
|
* the identity cell (10.0a), `@inline` over a pointer declaration is the
|
|
@@ -3756,6 +3861,14 @@ declare module "types:tensionscript/src/program" {
|
|
|
3756
3861
|
function fromUnaryPostfixToken(token: Token): OperatorKind;
|
|
3757
3862
|
}
|
|
3758
3863
|
/** Represents an AssemblyScript program. */
|
|
3864
|
+
/** How many WASM slots a parameter binding consumed — see
|
|
3865
|
+
* `Program#bindSroaParameterLeaves`. A one-field wrapper because this compiler
|
|
3866
|
+
* reports the count and the caller advances past it; a bare `i32` return would
|
|
3867
|
+
* be the same information with no name at the call site. */
|
|
3868
|
+
export class BindResult {
|
|
3869
|
+
leafCount: number;
|
|
3870
|
+
constructor(leafCount: number);
|
|
3871
|
+
}
|
|
3759
3872
|
export class Program extends DiagnosticEmitter {
|
|
3760
3873
|
/** Compiler options. */
|
|
3761
3874
|
options: Options;
|
|
@@ -4472,6 +4585,17 @@ declare module "types:tensionscript/src/program" {
|
|
|
4472
4585
|
* therefore cannot alias.
|
|
4473
4586
|
*/
|
|
4474
4587
|
fieldLocals: Map<string, Local> | null;
|
|
4588
|
+
/**
|
|
4589
|
+
* Whether this local is a **view parameter**: `a: @unmanaged T` where `T` is
|
|
4590
|
+
* an inline type.
|
|
4591
|
+
*
|
|
4592
|
+
* Its `type` is still the inline record, because that is what makes `a.field`
|
|
4593
|
+
* resolve — every use of `T` shares one `Type`. Its *storage* is the one `i32`
|
|
4594
|
+
* WASM parameter holding the caller's address, which is why a field read goes
|
|
4595
|
+
* through `load` at the field's offset rather than through `fieldLocals`
|
|
4596
|
+
* (there are none: a view has no per-field locals to copy into).
|
|
4597
|
+
*/
|
|
4598
|
+
isViewParam: boolean;
|
|
4475
4599
|
/** Constructs a new local variable. */
|
|
4476
4600
|
constructor(
|
|
4477
4601
|
/** Simple name. */
|
|
@@ -4583,6 +4707,20 @@ declare module "types:tensionscript/src/program" {
|
|
|
4583
4707
|
nextInlineId: number;
|
|
4584
4708
|
/** Counting id of anonymous inner functions. */
|
|
4585
4709
|
nextAnonymousId: number;
|
|
4710
|
+
/**
|
|
4711
|
+
* Binds an `@inline struct` parameter's **leaves** to the WASM parameters that
|
|
4712
|
+
* carry them, building the `fieldLocals` tree a read path walks.
|
|
4713
|
+
*
|
|
4714
|
+
* `localIndex` is the index of the parameter's first WASM slot; the walk
|
|
4715
|
+
* consumes one slot per leaf in the same depth-first order
|
|
4716
|
+
* `Signature.leafTypesOf` declares and the caller pushes operands in. Returns
|
|
4717
|
+
* how many slots were consumed, so the caller advances past them.
|
|
4718
|
+
*
|
|
4719
|
+
* A nested field gets a placeholder `Local` (index `-1`) carrying its own map,
|
|
4720
|
+
* exactly as `fillSroaFieldLocals` builds one for a local — the tree shape is
|
|
4721
|
+
* one structure regardless of where the leaves' storage came from.
|
|
4722
|
+
*/
|
|
4723
|
+
bindSroaParameterLeaves(type: Type, path: string, into: Map<string, Local>, localIndex: number, flow: Flow): BindResult;
|
|
4586
4724
|
/** Constructs a new concrete function. */
|
|
4587
4725
|
constructor(
|
|
4588
4726
|
/** Name incl. type parameters, i.e. `foo<i32>`. */
|
|
@@ -5277,7 +5415,7 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
5277
5415
|
import { Range, DiagnosticEmitter } from "types:tensionscript/src/diagnostics";
|
|
5278
5416
|
import { Module, MemorySegment, ExpressionRef, TypeRef, GlobalRef } from "types:tensionscript/src/module";
|
|
5279
5417
|
import { Feature, Target, Runtime } from "types:tensionscript/src/common";
|
|
5280
|
-
import { Program, Class, Element, DeclaredElement, Enum, Function, Global, Property, VariableLikeElement, File } from "types:tensionscript/src/program";
|
|
5418
|
+
import { Program, Class, Element, DeclaredElement, Enum, Function, Global, Local, Property, VariableLikeElement, File } from "types:tensionscript/src/program";
|
|
5281
5419
|
import { Flow, ConditionKind } from "types:tensionscript/src/flow";
|
|
5282
5420
|
import { Resolver } from "types:tensionscript/src/resolver";
|
|
5283
5421
|
import { Node, FunctionTypeNode, Statement, Expression } from "types:tensionscript/src/ast";
|
|
@@ -5940,11 +6078,27 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
5940
6078
|
/**
|
|
5941
6079
|
* The SROA local an expression names, or `null`.
|
|
5942
6080
|
*
|
|
5943
|
-
*
|
|
5944
|
-
*
|
|
5945
|
-
*
|
|
5946
|
-
*
|
|
6081
|
+
* The receiver is either an SROA local (base identifier) or a chain of field
|
|
6082
|
+
* accesses into one (`o.inner` in `o.inner.x`). The chain is walked from the
|
|
6083
|
+
* base outward, one hop per `fieldLocals` lookup: a nested inline field is
|
|
6084
|
+
* entered through the placeholder `Local` its creation installed
|
|
6085
|
+
* (`fillSroaFieldLocals`), so the walk and the tree are one structure rather
|
|
6086
|
+
* than two that could disagree.
|
|
6087
|
+
*
|
|
6088
|
+
* Returns the `Local` the final hop resolved to, or `null` when any step does
|
|
6089
|
+
* not hold — a non-local base, a field with no entry, or a leaf reached before
|
|
6090
|
+
* the chain ends. `null` is not an error here: the caller falls through to the
|
|
6091
|
+
* ordinary address paths, which refuse a value with no address.
|
|
6092
|
+
*/
|
|
6093
|
+
/**
|
|
6094
|
+
* Pushes one operand per **leaf** of a `fieldLocals` tree, depth first.
|
|
6095
|
+
*
|
|
6096
|
+
* Shared by the call site (`expandSroaArgument`) so the operand order is the
|
|
6097
|
+
* one `Signature.leafTypesOf` declares and the binder indexes into — three
|
|
6098
|
+
* walks, one order. A nested field's entry is a placeholder (index `-1`)
|
|
6099
|
+
* carrying its own map, so the walk descends through it.
|
|
5947
6100
|
*/
|
|
6101
|
+
private pushSroaLeafOperands;
|
|
5948
6102
|
private resolveSroaReceiver;
|
|
5949
6103
|
/** Size of the static call-temp region, in bytes. 4 KB is 256 slots at the
|
|
5950
6104
|
* 16-byte fixture record size. Overflow aborts (see `makeSretCallBlock`);
|
|
@@ -6034,6 +6188,15 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
6034
6188
|
/** `base + mark + extra`, freshly built. Callers must not share the node:
|
|
6035
6189
|
* Binaryen's passes assume a single parent per expression. */
|
|
6036
6190
|
private makeSretAddressPlus;
|
|
6191
|
+
/**
|
|
6192
|
+
* Stores a by-value argument's leaves into the static call-temp region.
|
|
6193
|
+
*
|
|
6194
|
+
* The same tree walk as `copyInto` (`emitSroaStores`) and `copySroaValue`:
|
|
6195
|
+
* leaves become stores at `tempAddress + field offset`, a nested field is
|
|
6196
|
+
* descended into. Keeping one recursion is what makes a nested value cross a
|
|
6197
|
+
* host boundary at the layout the C side expects.
|
|
6198
|
+
*/
|
|
6199
|
+
emitTempArgumentLeaves(type: Type, fieldLocals: Map<string, Local>, base: number, markLocal: Local, baseOffset: number, stmts: ExpressionRef[]): void;
|
|
6037
6200
|
/**
|
|
6038
6201
|
* Materialises one `@inline struct` argument of an `@external` call on the
|
|
6039
6202
|
* static call-temp stack and returns the address to pass.
|
|
@@ -6104,6 +6267,93 @@ declare module "types:tensionscript/src/compiler" {
|
|
|
6104
6267
|
* Returns true when the declaration was handled here (the caller must not fall
|
|
6105
6268
|
* through to the ordinary local path).
|
|
6106
6269
|
*/
|
|
6270
|
+
/**
|
|
6271
|
+
* Fills `into` with one entry per field of an `@inline struct` value.
|
|
6272
|
+
*
|
|
6273
|
+
* A **leaf** field (scalar, or a reference) gets one WASM local, named
|
|
6274
|
+
* `<path>$<field>` — a synthetic name keeps it out of user scope, so nothing
|
|
6275
|
+
* can look one up by accident.
|
|
6276
|
+
*
|
|
6277
|
+
* A field whose type is itself an `@inline struct` is **not a leaf**: it is
|
|
6278
|
+
* recursed into, and its entry is a placeholder `Local` (index `-1`) carrying
|
|
6279
|
+
* its own map. That makes `fieldLocals` a **tree** whose shape is the value's
|
|
6280
|
+
* nesting, which is what lets a read path walk `o.inner.x` a hop at a time
|
|
6281
|
+
* without a second representation. The placeholder is never `local.get`-ed:
|
|
6282
|
+
* the bare-read guard refuses a value read and the receiver walk descends to
|
|
6283
|
+
* a leaf before emitting anything.
|
|
6284
|
+
*
|
|
6285
|
+
* Returns `false` when a field was refused, having reported why. The refusal
|
|
6286
|
+
* is per **leaf**, so a nested value inherits exactly the rules the flat one
|
|
6287
|
+
* has — a `T[N]` field or a GC-reference field is refused at any depth.
|
|
6288
|
+
*/
|
|
6289
|
+
private fillSroaFieldLocals;
|
|
6290
|
+
/**
|
|
6291
|
+
* Copies one SROA value's leaves into another's, following the tree.
|
|
6292
|
+
*
|
|
6293
|
+
* `from` and `to` are the two `fieldLocals` maps — the same shape
|
|
6294
|
+
* `fillSroaFieldLocals` builds, so a nested field is a placeholder on both
|
|
6295
|
+
* sides and the recursion descends through it rather than trying to move a
|
|
6296
|
+
* value that has no single representation.
|
|
6297
|
+
*
|
|
6298
|
+
* This is what makes `let q = p` and `q = p` **copies** rather than aliases:
|
|
6299
|
+
* one `local.set` per leaf, so a later write to `q` cannot be seen through
|
|
6300
|
+
* `p`. Both sides come from this compiler's own maps, so there is no aliasing
|
|
6301
|
+
* question to answer — the leaves are distinct locals by construction.
|
|
6302
|
+
*/
|
|
6303
|
+
private copySroaValue;
|
|
6304
|
+
/**
|
|
6305
|
+
* Stores a `fieldLocals` tree's leaves into the hidden destination slot at
|
|
6306
|
+
* `destIndex`, one store per leaf.
|
|
6307
|
+
*
|
|
6308
|
+
* The third destination shape for the same recursion: `emitSroaStores` writes
|
|
6309
|
+
* to a compiled `usize`, `emitTempArgumentLeaves` to a call-temp address, and
|
|
6310
|
+
* this one to a **parameter** — the sret slot a `return p` fills. The address
|
|
6311
|
+
* is a fresh `local.get` per store, because Binaryen's passes assume one
|
|
6312
|
+
* parent per node.
|
|
6313
|
+
*/
|
|
6314
|
+
emitSroaStoresToLocal(type: Type, fieldLocals: Map<string, Local>, destIndex: number, baseOffset: number, stmts: ExpressionRef[]): void;
|
|
6315
|
+
/**
|
|
6316
|
+
* Zeroes every **leaf** of an `@inline struct` in the destination slot.
|
|
6317
|
+
*
|
|
6318
|
+
* `return new P()` has no local to copy from — the value is all zeroes — but
|
|
6319
|
+
* the slot is stack space that a previous sret call may have filled, so the
|
|
6320
|
+
* bytes still have to be written. Walking the type rather than the direct
|
|
6321
|
+
* fields is what zeroes a nested field's leaves: measured before this,
|
|
6322
|
+
* `return new Outer1()` with `Inner{x,y}` stored only offset 0 and left
|
|
6323
|
+
* offsets 4 and 8 holding whatever was there.
|
|
6324
|
+
*/
|
|
6325
|
+
emitSroaZerosToLocal(type: Type, destIndex: number, baseOffset: number, stmts: ExpressionRef[]): void;
|
|
6326
|
+
/**
|
|
6327
|
+
* Loads an `@inline struct`'s leaves out of the sret slot into a target's
|
|
6328
|
+
* field locals, one load per leaf.
|
|
6329
|
+
*
|
|
6330
|
+
* The mirror of {@link emitSroaStoresToLocal}: `let q = make()` reads the slot
|
|
6331
|
+
* back into the leaf locals a read path walks. A fresh slot address per load,
|
|
6332
|
+
* for the same one-parent-per-node reason.
|
|
6333
|
+
*/
|
|
6334
|
+
emitSretLoadsInto(type: Type, fieldLocals: Map<string, Local>, base: number, markLocal: Local, baseOffset: number, stmts: ExpressionRef[]): void;
|
|
6335
|
+
/**
|
|
6336
|
+
* The `fieldLocals` tree behind an SROA-tracked expression, or `null`.
|
|
6337
|
+
*
|
|
6338
|
+
* The public face of {@link resolveSroaReceiver} for code outside this class —
|
|
6339
|
+
* today only the `copyInto` builtin, which needs the *tree* (to store its
|
|
6340
|
+
* leaves) rather than a single receiver.
|
|
6341
|
+
*/
|
|
6342
|
+
sroaTreeOf(expression: Expression): Map<string, Local> | null;
|
|
6343
|
+
/**
|
|
6344
|
+
* Stores an inline value's leaves at `dest + offset`.
|
|
6345
|
+
*
|
|
6346
|
+
* The third leaf consumer, beside `copySroaValue` (local-to-local) and the
|
|
6347
|
+
* read path (local-to-stack): same tree, same recursion, an expression
|
|
6348
|
+
* reference instead of a destination map. The offsets come from the **type**
|
|
6349
|
+
* (`property.memoryOffset`, the layout the C side sees), so what lands in
|
|
6350
|
+
* memory is the wire layout, not a packing of the locals.
|
|
6351
|
+
*
|
|
6352
|
+
* Leaves whose local is missing are skipped rather than stored as `-1`: a
|
|
6353
|
+
* field refused at declaration was never part of the value (`isSroaFieldType`
|
|
6354
|
+
* has already reported why), and the caller has been told.
|
|
6355
|
+
*/
|
|
6356
|
+
emitSroaStores(type: Type, fieldLocals: Map<string, Local>, dest: ExpressionRef, baseOffset: number, stmts: ExpressionRef[]): void;
|
|
6107
6357
|
private compileSroaLocal;
|
|
6108
6358
|
/**
|
|
6109
6359
|
* The instance fields of an `@inline struct`, in declaration order, or `null`
|
|
@@ -6289,6 +6539,7 @@ declare module "types:tensionscript/src/builtins" {
|
|
|
6289
6539
|
const select = "~lib/builtins/select";
|
|
6290
6540
|
const unreachable = "~lib/builtins/unreachable";
|
|
6291
6541
|
const changetype = "~lib/builtins/changetype";
|
|
6542
|
+
const copyInto = "~lib/builtins/copyInto";
|
|
6292
6543
|
const assert = "~lib/builtins/assert";
|
|
6293
6544
|
const call_indirect = "~lib/builtins/call_indirect";
|
|
6294
6545
|
const unchecked = "~lib/builtins/unchecked";
|