@geastack/compiler 1.0.15
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/LICENSE +202 -0
- package/README.md +149 -0
- package/dist/cli-analyze.d.ts +1 -0
- package/dist/cli-analyze.js +61 -0
- package/dist/cli-coverage.d.ts +1 -0
- package/dist/cli-coverage.js +329 -0
- package/dist/cli-emit.d.ts +10 -0
- package/dist/cli-emit.js +398 -0
- package/dist/cli-module-graph.d.ts +18 -0
- package/dist/cli-module-graph.js +123 -0
- package/dist/cli-package-source.d.ts +5 -0
- package/dist/cli-package-source.js +116 -0
- package/dist/cli-project.d.ts +2 -0
- package/dist/cli-project.js +60 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +199 -0
- package/dist/compiler.d.ts +228 -0
- package/dist/compiler.js +1029 -0
- package/dist/conversion/algebra.d.ts +218 -0
- package/dist/conversion/algebra.js +155 -0
- package/dist/conversion/build.d.ts +67 -0
- package/dist/conversion/build.js +1378 -0
- package/dist/conversion/derive.d.ts +37 -0
- package/dist/conversion/derive.js +260 -0
- package/dist/conversion/graph-validation.d.ts +8 -0
- package/dist/conversion/graph-validation.js +97 -0
- package/dist/conversion/native-callable-adapter.d.ts +13 -0
- package/dist/conversion/native-callable-adapter.js +53 -0
- package/dist/conversion/native-class-reference.d.ts +12 -0
- package/dist/conversion/native-class-reference.js +39 -0
- package/dist/conversion/native-payload-transport.d.ts +25 -0
- package/dist/conversion/native-payload-transport.js +33 -0
- package/dist/conversion/native-selection.d.ts +49 -0
- package/dist/conversion/native-selection.js +135 -0
- package/dist/conversion/native-sum.d.ts +42 -0
- package/dist/conversion/native-sum.js +115 -0
- package/dist/conversion/nodes.d.ts +55 -0
- package/dist/conversion/nodes.js +91 -0
- package/dist/conversion/operand-view.d.ts +14 -0
- package/dist/conversion/operand-view.js +20 -0
- package/dist/conversion/record-view.d.ts +157 -0
- package/dist/conversion/record-view.js +273 -0
- package/dist/conversion/registry.d.ts +217 -0
- package/dist/conversion/registry.js +1 -0
- package/dist/diagnostics/model.d.ts +76 -0
- package/dist/diagnostics/model.js +60 -0
- package/dist/diagnostics/sweep.d.ts +31 -0
- package/dist/diagnostics/sweep.js +112 -0
- package/dist/identity/ids.d.ts +179 -0
- package/dist/identity/ids.js +212 -0
- package/dist/ir/absent-class-arm.d.ts +48 -0
- package/dist/ir/absent-class-arm.js +157 -0
- package/dist/ir/borrow-effects.d.ts +23 -0
- package/dist/ir/borrow-effects.js +151 -0
- package/dist/ir/borrowed-call-arguments.d.ts +40 -0
- package/dist/ir/borrowed-call-arguments.js +117 -0
- package/dist/ir/build.d.ts +168 -0
- package/dist/ir/build.js +459 -0
- package/dist/ir/call-dispatch.d.ts +38 -0
- package/dist/ir/call-dispatch.js +502 -0
- package/dist/ir/call-entry.d.ts +142 -0
- package/dist/ir/call-entry.js +386 -0
- package/dist/ir/callable-class-flow.d.ts +27 -0
- package/dist/ir/callable-class-flow.js +1386 -0
- package/dist/ir/callable-field-slots.d.ts +22 -0
- package/dist/ir/callable-field-slots.js +166 -0
- package/dist/ir/callable-identity-demand.d.ts +52 -0
- package/dist/ir/callable-identity-demand.js +460 -0
- package/dist/ir/callable-member-candidates.d.ts +9 -0
- package/dist/ir/callable-member-candidates.js +39 -0
- package/dist/ir/callable-records.d.ts +21 -0
- package/dist/ir/callable-records.js +411 -0
- package/dist/ir/captures.d.ts +26 -0
- package/dist/ir/captures.js +335 -0
- package/dist/ir/certificate.d.ts +45 -0
- package/dist/ir/certificate.js +47 -0
- package/dist/ir/certify/carrier-keys.d.ts +73 -0
- package/dist/ir/certify/carrier-keys.js +221 -0
- package/dist/ir/certify/function-source.d.ts +4 -0
- package/dist/ir/certify/function-source.js +28 -0
- package/dist/ir/certify/has-property-key.d.ts +88 -0
- package/dist/ir/certify/has-property-key.js +116 -0
- package/dist/ir/certify/instanceof-key.d.ts +24 -0
- package/dist/ir/certify/instanceof-key.js +35 -0
- package/dist/ir/certify/property-access-keys.d.ts +172 -0
- package/dist/ir/certify/property-access-keys.js +291 -0
- package/dist/ir/certify/property-access.d.ts +3 -0
- package/dist/ir/certify/property-access.js +597 -0
- package/dist/ir/certify/runtime-helper.d.ts +3 -0
- package/dist/ir/certify/runtime-helper.js +326 -0
- package/dist/ir/certify/typeof-operand.d.ts +14 -0
- package/dist/ir/certify/typeof-operand.js +16 -0
- package/dist/ir/certify.d.ts +123 -0
- package/dist/ir/certify.js +481 -0
- package/dist/ir/class-evaluation.d.ts +26 -0
- package/dist/ir/class-evaluation.js +50 -0
- package/dist/ir/class-static-fields.d.ts +60 -0
- package/dist/ir/class-static-fields.js +108 -0
- package/dist/ir/construct-entry.d.ts +26 -0
- package/dist/ir/construct-entry.js +117 -0
- package/dist/ir/dead-values.d.ts +90 -0
- package/dist/ir/dead-values.js +184 -0
- package/dist/ir/deferral.d.ts +99 -0
- package/dist/ir/deferral.js +409 -0
- package/dist/ir/dense-loops.d.ts +230 -0
- package/dist/ir/dense-loops.js +697 -0
- package/dist/ir/dominance.d.ts +82 -0
- package/dist/ir/dominance.js +268 -0
- package/dist/ir/emission-representations.d.ts +71 -0
- package/dist/ir/emission-representations.js +350 -0
- package/dist/ir/facts.d.ts +218 -0
- package/dist/ir/facts.js +181 -0
- package/dist/ir/fixed-data-definition.d.ts +19 -0
- package/dist/ir/fixed-data-definition.js +49 -0
- package/dist/ir/generator-split.d.ts +38 -0
- package/dist/ir/generator-split.js +329 -0
- package/dist/ir/hoist.d.ts +55 -0
- package/dist/ir/hoist.js +375 -0
- package/dist/ir/instantiation.d.ts +61 -0
- package/dist/ir/instantiation.js +137 -0
- package/dist/ir/integer-storage.d.ts +170 -0
- package/dist/ir/integer-storage.js +822 -0
- package/dist/ir/integers.d.ts +161 -0
- package/dist/ir/integers.js +539 -0
- package/dist/ir/integrity-restrictions.d.ts +50 -0
- package/dist/ir/integrity-restrictions.js +118 -0
- package/dist/ir/local-iterators.d.ts +4 -0
- package/dist/ir/local-iterators.js +27 -0
- package/dist/ir/lower-allocation.d.ts +4 -0
- package/dist/ir/lower-allocation.js +325 -0
- package/dist/ir/lower-completion.d.ts +15 -0
- package/dist/ir/lower-completion.js +25 -0
- package/dist/ir/lower-destructuring.d.ts +5 -0
- package/dist/ir/lower-destructuring.js +693 -0
- package/dist/ir/lower-element.d.ts +29 -0
- package/dist/ir/lower-element.js +111 -0
- package/dist/ir/lower-exceptions.d.ts +47 -0
- package/dist/ir/lower-exceptions.js +92 -0
- package/dist/ir/lower-flow.d.ts +137 -0
- package/dist/ir/lower-flow.js +600 -0
- package/dist/ir/lower-graph.d.ts +218 -0
- package/dist/ir/lower-graph.js +687 -0
- package/dist/ir/lower-invocation.d.ts +4 -0
- package/dist/ir/lower-invocation.js +514 -0
- package/dist/ir/lower-narrow.d.ts +53 -0
- package/dist/ir/lower-narrow.js +320 -0
- package/dist/ir/lower-operands.d.ts +272 -0
- package/dist/ir/lower-operands.js +461 -0
- package/dist/ir/lower-property.d.ts +21 -0
- package/dist/ir/lower-property.js +132 -0
- package/dist/ir/lower-protocol.d.ts +11 -0
- package/dist/ir/lower-protocol.js +118 -0
- package/dist/ir/lower-short-circuit.d.ts +41 -0
- package/dist/ir/lower-short-circuit.js +63 -0
- package/dist/ir/lower.d.ts +82 -0
- package/dist/ir/lower.js +1346 -0
- package/dist/ir/model.d.ts +1474 -0
- package/dist/ir/model.js +6 -0
- package/dist/ir/native-absent-property.d.ts +3 -0
- package/dist/ir/native-absent-property.js +13 -0
- package/dist/ir/native-array-transport.d.ts +7 -0
- package/dist/ir/native-array-transport.js +46 -0
- package/dist/ir/native-callable-bind.d.ts +9 -0
- package/dist/ir/native-callable-bind.js +30 -0
- package/dist/ir/native-carrier-predicate.d.ts +34 -0
- package/dist/ir/native-carrier-predicate.js +49 -0
- package/dist/ir/native-class-accessor.d.ts +18 -0
- package/dist/ir/native-class-accessor.js +52 -0
- package/dist/ir/native-class-construction.d.ts +16 -0
- package/dist/ir/native-class-construction.js +71 -0
- package/dist/ir/native-class-initialization.d.ts +15 -0
- package/dist/ir/native-class-initialization.js +56 -0
- package/dist/ir/native-class-origins.d.ts +13 -0
- package/dist/ir/native-class-origins.js +237 -0
- package/dist/ir/native-dictionary-transport.d.ts +6 -0
- package/dist/ir/native-dictionary-transport.js +37 -0
- package/dist/ir/native-enumeration.d.ts +14 -0
- package/dist/ir/native-enumeration.js +26 -0
- package/dist/ir/native-equality.d.ts +10 -0
- package/dist/ir/native-equality.js +18 -0
- package/dist/ir/native-field-owner.d.ts +37 -0
- package/dist/ir/native-field-owner.js +183 -0
- package/dist/ir/native-fixed-layout.d.ts +41 -0
- package/dist/ir/native-fixed-layout.js +232 -0
- package/dist/ir/native-host-construction.d.ts +53 -0
- package/dist/ir/native-host-construction.js +62 -0
- package/dist/ir/native-key-query.d.ts +4 -0
- package/dist/ir/native-key-query.js +38 -0
- package/dist/ir/native-merge-transport.d.ts +25 -0
- package/dist/ir/native-merge-transport.js +71 -0
- package/dist/ir/native-record-index-transport.d.ts +11 -0
- package/dist/ir/native-record-index-transport.js +34 -0
- package/dist/ir/native-record-index.d.ts +12 -0
- package/dist/ir/native-record-index.js +27 -0
- package/dist/ir/native-reflect-field.d.ts +5 -0
- package/dist/ir/native-reflect-field.js +33 -0
- package/dist/ir/native-sequence-transport.d.ts +7 -0
- package/dist/ir/native-sequence-transport.js +53 -0
- package/dist/ir/numeric-intrinsics.d.ts +13 -0
- package/dist/ir/numeric-intrinsics.js +57 -0
- package/dist/ir/object-value-conversions.d.ts +20 -0
- package/dist/ir/object-value-conversions.js +50 -0
- package/dist/ir/physical-class-reflection.d.ts +9 -0
- package/dist/ir/physical-class-reflection.js +57 -0
- package/dist/ir/presence-proof.d.ts +42 -0
- package/dist/ir/presence-proof.js +490 -0
- package/dist/ir/program-facts.d.ts +106 -0
- package/dist/ir/program-facts.js +319 -0
- package/dist/ir/proven-branches.d.ts +16 -0
- package/dist/ir/proven-branches.js +219 -0
- package/dist/ir/queries.d.ts +41 -0
- package/dist/ir/queries.js +213 -0
- package/dist/ir/reflection-demand.d.ts +64 -0
- package/dist/ir/reflection-demand.js +1394 -0
- package/dist/ir/refusal.d.ts +43 -0
- package/dist/ir/refusal.js +28 -0
- package/dist/ir/shake.d.ts +37 -0
- package/dist/ir/shake.js +1078 -0
- package/dist/ir/static-callables.d.ts +11 -0
- package/dist/ir/static-callables.js +163 -0
- package/dist/ir/string-layout-reuse.d.ts +13 -0
- package/dist/ir/string-layout-reuse.js +39 -0
- package/dist/ir/string-length-reuse.d.ts +8 -0
- package/dist/ir/string-length-reuse.js +47 -0
- package/dist/ir/transfer.d.ts +78 -0
- package/dist/ir/transfer.js +270 -0
- package/dist/ir/type-query-results.d.ts +25 -0
- package/dist/ir/type-query-results.js +96 -0
- package/dist/ir/typed-property-access.d.ts +100 -0
- package/dist/ir/typed-property-access.js +161 -0
- package/dist/ir/verify.d.ts +19 -0
- package/dist/ir/verify.js +355 -0
- package/dist/plugins/apple/constructors.d.ts +112 -0
- package/dist/plugins/apple/constructors.js +217 -0
- package/dist/plugins/apple/host.d.ts +181 -0
- package/dist/plugins/apple/host.js +262 -0
- package/dist/plugins/apple/jsx.d.ts +2 -0
- package/dist/plugins/apple/jsx.js +293 -0
- package/dist/plugins/apple/members.d.ts +16 -0
- package/dist/plugins/apple/members.js +190 -0
- package/dist/plugins/apple/plugin.d.ts +2 -0
- package/dist/plugins/apple/plugin.js +156 -0
- package/dist/plugins/gea/component-classes.d.ts +25 -0
- package/dist/plugins/gea/component-classes.js +162 -0
- package/dist/plugins/gea/component-inline.d.ts +13 -0
- package/dist/plugins/gea/component-inline.js +532 -0
- package/dist/plugins/gea/constructors.d.ts +23 -0
- package/dist/plugins/gea/constructors.js +100 -0
- package/dist/plugins/gea/contract.d.ts +150 -0
- package/dist/plugins/gea/contract.js +195 -0
- package/dist/plugins/gea/element-ref.d.ts +31 -0
- package/dist/plugins/gea/element-ref.js +45 -0
- package/dist/plugins/gea/host.d.ts +520 -0
- package/dist/plugins/gea/host.js +762 -0
- package/dist/plugins/gea/lower.d.ts +6 -0
- package/dist/plugins/gea/lower.js +195 -0
- package/dist/plugins/gea/members.d.ts +22 -0
- package/dist/plugins/gea/members.js +221 -0
- package/dist/plugins/gea/plugin.d.ts +22 -0
- package/dist/plugins/gea/plugin.js +307 -0
- package/dist/plugins/gea/prelude.d.ts +78 -0
- package/dist/plugins/gea/prelude.js +153 -0
- package/dist/plugins/gea/producer.d.ts +5 -0
- package/dist/plugins/gea/producer.js +52 -0
- package/dist/plugins/gea/reactive-slots.d.ts +49 -0
- package/dist/plugins/gea/reactive-slots.js +578 -0
- package/dist/plugins/gea/render-bridge.d.ts +6 -0
- package/dist/plugins/gea/render-bridge.js +281 -0
- package/dist/plugins/gea/slots.d.ts +15 -0
- package/dist/plugins/gea/slots.js +36 -0
- package/dist/plugins/gea/template-analysis.d.ts +151 -0
- package/dist/plugins/gea/template-analysis.js +346 -0
- package/dist/plugins/gea/user-agent-styles.d.ts +9 -0
- package/dist/plugins/gea/user-agent-styles.js +94 -0
- package/dist/plugins/installed.d.ts +19 -0
- package/dist/plugins/installed.js +21 -0
- package/dist/plugins/load.d.ts +7 -0
- package/dist/plugins/load.js +207 -0
- package/dist/plugins/model.d.ts +735 -0
- package/dist/plugins/model.js +47 -0
- package/dist/plugins/webgl/host.d.ts +77 -0
- package/dist/plugins/webgl/host.js +162 -0
- package/dist/plugins/webgl/plugin.d.ts +40 -0
- package/dist/plugins/webgl/plugin.js +99 -0
- package/dist/preflight/obligations.d.ts +206 -0
- package/dist/preflight/obligations.js +36 -0
- package/dist/preflight/report.d.ts +20 -0
- package/dist/preflight/report.js +61 -0
- package/dist/preflight/run.d.ts +39 -0
- package/dist/preflight/run.js +403 -0
- package/dist/project-preparation.d.ts +33 -0
- package/dist/project-preparation.js +314 -0
- package/dist/projection/abi.d.ts +82 -0
- package/dist/projection/abi.js +349 -0
- package/dist/projection/apply-arguments.d.ts +12 -0
- package/dist/projection/apply-arguments.js +20 -0
- package/dist/projection/bindings.d.ts +250 -0
- package/dist/projection/bindings.js +340 -0
- package/dist/projection/callee.d.ts +196 -0
- package/dist/projection/callee.js +444 -0
- package/dist/projection/class-property-presence.d.ts +28 -0
- package/dist/projection/class-property-presence.js +58 -0
- package/dist/projection/class-prototype.d.ts +5 -0
- package/dist/projection/class-prototype.js +23 -0
- package/dist/projection/class-storage.d.ts +26 -0
- package/dist/projection/class-storage.js +236 -0
- package/dist/projection/classes.d.ts +283 -0
- package/dist/projection/classes.js +944 -0
- package/dist/projection/coercions.d.ts +20 -0
- package/dist/projection/coercions.js +33 -0
- package/dist/projection/dispatch.d.ts +167 -0
- package/dist/projection/dispatch.js +379 -0
- package/dist/projection/fields.d.ts +123 -0
- package/dist/projection/fields.js +383 -0
- package/dist/projection/instance-test.d.ts +78 -0
- package/dist/projection/instance-test.js +156 -0
- package/dist/projection/slots.d.ts +146 -0
- package/dist/projection/slots.js +663 -0
- package/dist/projection/synthesized-abi.d.ts +61 -0
- package/dist/projection/synthesized-abi.js +94 -0
- package/dist/representation/array-index.d.ts +14 -0
- package/dist/representation/array-index.js +17 -0
- package/dist/representation/callable-object.d.ts +3 -0
- package/dist/representation/callable-object.js +6 -0
- package/dist/representation/collections.d.ts +84 -0
- package/dist/representation/collections.js +139 -0
- package/dist/representation/derive.d.ts +159 -0
- package/dist/representation/derive.js +2546 -0
- package/dist/representation/difference.d.ts +30 -0
- package/dist/representation/difference.js +240 -0
- package/dist/representation/field-descriptor-policy.d.ts +19 -0
- package/dist/representation/field-descriptor-policy.js +39 -0
- package/dist/representation/function-constructor.d.ts +13 -0
- package/dist/representation/function-constructor.js +9 -0
- package/dist/representation/host-abi.d.ts +32 -0
- package/dist/representation/host-abi.js +97 -0
- package/dist/representation/host-templates.d.ts +67 -0
- package/dist/representation/host-templates.js +94 -0
- package/dist/representation/intersection.d.ts +84 -0
- package/dist/representation/intersection.js +149 -0
- package/dist/representation/literal-destination.d.ts +43 -0
- package/dist/representation/literal-destination.js +133 -0
- package/dist/representation/merge.d.ts +18 -0
- package/dist/representation/merge.js +83 -0
- package/dist/representation/model.d.ts +1160 -0
- package/dist/representation/model.js +1019 -0
- package/dist/representation/numeric-index.d.ts +13 -0
- package/dist/representation/numeric-index.js +29 -0
- package/dist/representation/object-shape.d.ts +109 -0
- package/dist/representation/object-shape.js +123 -0
- package/dist/representation/optional.d.ts +12 -0
- package/dist/representation/optional.js +87 -0
- package/dist/representation/plan.d.ts +60 -0
- package/dist/representation/plan.js +78 -0
- package/dist/representation/policies.d.ts +589 -0
- package/dist/representation/policies.js +107 -0
- package/dist/representation/primitive-domain.d.ts +1 -0
- package/dist/representation/primitive-domain.js +1 -0
- package/dist/representation/primitives.d.ts +44 -0
- package/dist/representation/primitives.js +78 -0
- package/dist/representation/publish.d.ts +49 -0
- package/dist/representation/publish.js +648 -0
- package/dist/representation/record-fields.d.ts +96 -0
- package/dist/representation/record-fields.js +116 -0
- package/dist/representation/template-object.d.ts +11 -0
- package/dist/representation/template-object.js +26 -0
- package/dist/representation/union.d.ts +30 -0
- package/dist/representation/union.js +324 -0
- package/dist/representation/value-records.d.ts +3 -0
- package/dist/representation/value-records.js +307 -0
- package/dist/representation/verify.d.ts +17 -0
- package/dist/representation/verify.js +221 -0
- package/dist/semantics/alias-this-field-declaration-transform.d.ts +4 -0
- package/dist/semantics/alias-this-field-declaration-transform.js +207 -0
- package/dist/semantics/ambient-type-realization-transform.d.ts +62 -0
- package/dist/semantics/ambient-type-realization-transform.js +168 -0
- package/dist/semantics/ambient.d.ts +24 -0
- package/dist/semantics/ambient.js +119 -0
- package/dist/semantics/borrowed-builtin-call-bind-source-transform.d.ts +4 -0
- package/dist/semantics/borrowed-builtin-call-bind-source-transform.js +341 -0
- package/dist/semantics/callable-origins.d.ts +46 -0
- package/dist/semantics/callable-origins.js +354 -0
- package/dist/semantics/class-alias.d.ts +7 -0
- package/dist/semantics/class-alias.js +37 -0
- package/dist/semantics/class-heritage.d.ts +34 -0
- package/dist/semantics/class-heritage.js +104 -0
- package/dist/semantics/commonjs-wrapper.d.ts +69 -0
- package/dist/semantics/commonjs-wrapper.js +231 -0
- package/dist/semantics/constructor-slot-subclasses.d.ts +28 -0
- package/dist/semantics/constructor-slot-subclasses.js +112 -0
- package/dist/semantics/declaration-overlay-transform.d.ts +35 -0
- package/dist/semantics/declaration-overlay-transform.js +2157 -0
- package/dist/semantics/define-property-source-transform.d.ts +4 -0
- package/dist/semantics/define-property-source-transform.js +437 -0
- package/dist/semantics/diagnostic-source-preparation.d.ts +24 -0
- package/dist/semantics/diagnostic-source-preparation.js +82 -0
- package/dist/semantics/documentation-ranges.d.ts +22 -0
- package/dist/semantics/documentation-ranges.js +36 -0
- package/dist/semantics/dynamic-fallback.d.ts +86 -0
- package/dist/semantics/dynamic-fallback.js +249 -0
- package/dist/semantics/frontend-timing.d.ts +6 -0
- package/dist/semantics/frontend-timing.js +35 -0
- package/dist/semantics/frontend.d.ts +504 -0
- package/dist/semantics/frontend.js +1157 -0
- package/dist/semantics/host-declaration-provenance.d.ts +11 -0
- package/dist/semantics/host-declaration-provenance.js +18 -0
- package/dist/semantics/host-methods.d.ts +24 -0
- package/dist/semantics/host-methods.js +74 -0
- package/dist/semantics/host-protocols.d.ts +429 -0
- package/dist/semantics/host-protocols.js +1501 -0
- package/dist/semantics/inherited-accessor.d.ts +7 -0
- package/dist/semantics/inherited-accessor.js +48 -0
- package/dist/semantics/interface-families.d.ts +70 -0
- package/dist/semantics/interface-families.js +180 -0
- package/dist/semantics/interface-implementors.d.ts +53 -0
- package/dist/semantics/interface-implementors.js +87 -0
- package/dist/semantics/jsdoc-namepath-transform.d.ts +4 -0
- package/dist/semantics/jsdoc-namepath-transform.js +85 -0
- package/dist/semantics/model/coverage.d.ts +68 -0
- package/dist/semantics/model/coverage.js +73 -0
- package/dist/semantics/model/edges.d.ts +103 -0
- package/dist/semantics/model/edges.js +20 -0
- package/dist/semantics/model/graph.d.ts +55 -0
- package/dist/semantics/model/graph.js +129 -0
- package/dist/semantics/model/operands.d.ts +159 -0
- package/dist/semantics/model/operands.js +26 -0
- package/dist/semantics/model/operations.d.ts +496 -0
- package/dist/semantics/model/operations.js +2 -0
- package/dist/semantics/model/primitive-domain.d.ts +26 -0
- package/dist/semantics/model/primitive-domain.js +38 -0
- package/dist/semantics/model/selected-signature.d.ts +261 -0
- package/dist/semantics/model/selected-signature.js +55 -0
- package/dist/semantics/model/structural-type-table.d.ts +93 -0
- package/dist/semantics/model/structural-type-table.js +237 -0
- package/dist/semantics/model/structural-types.d.ts +367 -0
- package/dist/semantics/model/structural-types.js +200 -0
- package/dist/semantics/module-resolution.d.ts +23 -0
- package/dist/semantics/module-resolution.js +227 -0
- package/dist/semantics/new-callee-class-tag-source-transform.d.ts +4 -0
- package/dist/semantics/new-callee-class-tag-source-transform.js +64 -0
- package/dist/semantics/node-project.d.ts +13 -0
- package/dist/semantics/node-project.js +107 -0
- package/dist/semantics/node-source-hooks.d.ts +1 -0
- package/dist/semantics/node-source-hooks.js +63 -0
- package/dist/semantics/normalize/absent-globals.d.ts +143 -0
- package/dist/semantics/normalize/absent-globals.js +191 -0
- package/dist/semantics/normalize/arguments-objects.d.ts +43 -0
- package/dist/semantics/normalize/arguments-objects.js +60 -0
- package/dist/semantics/normalize/asserted-arm-absence.d.ts +28 -0
- package/dist/semantics/normalize/asserted-arm-absence.js +61 -0
- package/dist/semantics/normalize/assignment-patterns.d.ts +70 -0
- package/dist/semantics/normalize/assignment-patterns.js +147 -0
- package/dist/semantics/normalize/bag-absence.d.ts +8 -0
- package/dist/semantics/normalize/bag-absence.js +42 -0
- package/dist/semantics/normalize/binding-fixpoint.d.ts +36 -0
- package/dist/semantics/normalize/binding-fixpoint.js +140 -0
- package/dist/semantics/normalize/callback-parameter-contracts.d.ts +16 -0
- package/dist/semantics/normalize/callback-parameter-contracts.js +91 -0
- package/dist/semantics/normalize/cells/agreement.d.ts +46 -0
- package/dist/semantics/normalize/cells/agreement.js +34 -0
- package/dist/semantics/normalize/cells/candidates.d.ts +17 -0
- package/dist/semantics/normalize/cells/candidates.js +35 -0
- package/dist/semantics/normalize/cells/facts.d.ts +19 -0
- package/dist/semantics/normalize/cells/facts.js +90 -0
- package/dist/semantics/normalize/cells/index.d.ts +10 -0
- package/dist/semantics/normalize/cells/index.js +6 -0
- package/dist/semantics/normalize/cells/model.d.ts +98 -0
- package/dist/semantics/normalize/cells/model.js +2 -0
- package/dist/semantics/normalize/cells/policies/bag.d.ts +44 -0
- package/dist/semantics/normalize/cells/policies/bag.js +114 -0
- package/dist/semantics/normalize/cells/policies/collection.d.ts +42 -0
- package/dist/semantics/normalize/cells/policies/collection.js +218 -0
- package/dist/semantics/normalize/cells/policies/field.d.ts +28 -0
- package/dist/semantics/normalize/cells/policies/field.js +40 -0
- package/dist/semantics/normalize/cells/policies/index.d.ts +49 -0
- package/dist/semantics/normalize/cells/policies/index.js +58 -0
- package/dist/semantics/normalize/cells/policies/local.d.ts +18 -0
- package/dist/semantics/normalize/cells/policies/local.js +37 -0
- package/dist/semantics/normalize/cells/policies/parameter.d.ts +28 -0
- package/dist/semantics/normalize/cells/policies/parameter.js +39 -0
- package/dist/semantics/normalize/cells/policies/return.d.ts +26 -0
- package/dist/semantics/normalize/cells/policies/return.js +45 -0
- package/dist/semantics/normalize/cells/policies/shared.d.ts +33 -0
- package/dist/semantics/normalize/cells/policies/shared.js +45 -0
- package/dist/semantics/normalize/cells/policy.d.ts +72 -0
- package/dist/semantics/normalize/cells/policy.js +18 -0
- package/dist/semantics/normalize/cells/registry.d.ts +14 -0
- package/dist/semantics/normalize/cells/registry.js +17 -0
- package/dist/semantics/normalize/census-refusal.d.ts +62 -0
- package/dist/semantics/normalize/census-refusal.js +27 -0
- package/dist/semantics/normalize/census.d.ts +109 -0
- package/dist/semantics/normalize/census.js +667 -0
- package/dist/semantics/normalize/collection-bindings.d.ts +278 -0
- package/dist/semantics/normalize/collection-bindings.js +677 -0
- package/dist/semantics/normalize/commonjs-module-record.d.ts +21 -0
- package/dist/semantics/normalize/commonjs-module-record.js +289 -0
- package/dist/semantics/normalize/commonjs-require.d.ts +13 -0
- package/dist/semantics/normalize/commonjs-require.js +1527 -0
- package/dist/semantics/normalize/contribution.d.ts +63 -0
- package/dist/semantics/normalize/contribution.js +172 -0
- package/dist/semantics/normalize/dead-typeof-guards.d.ts +64 -0
- package/dist/semantics/normalize/dead-typeof-guards.js +152 -0
- package/dist/semantics/normalize/deferred-intrinsic-protocols.d.ts +57 -0
- package/dist/semantics/normalize/deferred-intrinsic-protocols.js +109 -0
- package/dist/semantics/normalize/derived-expression-type.d.ts +1070 -0
- package/dist/semantics/normalize/derived-expression-type.js +3463 -0
- package/dist/semantics/normalize/evaluation-order.d.ts +16 -0
- package/dist/semantics/normalize/evaluation-order.js +37 -0
- package/dist/semantics/normalize/field-bindings.d.ts +167 -0
- package/dist/semantics/normalize/field-bindings.js +1125 -0
- package/dist/semantics/normalize/flow/array-element-continuation.d.ts +27 -0
- package/dist/semantics/normalize/flow/array-element-continuation.js +1452 -0
- package/dist/semantics/normalize/flow/callable-array-origins.d.ts +42 -0
- package/dist/semantics/normalize/flow/callable-array-origins.js +318 -0
- package/dist/semantics/normalize/flow/callable-completions.d.ts +45 -0
- package/dist/semantics/normalize/flow/callable-completions.js +82 -0
- package/dist/semantics/normalize/flow/callable-reach.d.ts +237 -0
- package/dist/semantics/normalize/flow/callable-reach.js +7174 -0
- package/dist/semantics/normalize/flow/class-family-member-read.d.ts +16 -0
- package/dist/semantics/normalize/flow/class-family-member-read.js +992 -0
- package/dist/semantics/normalize/flow/collection-value-continuation.d.ts +21 -0
- package/dist/semantics/normalize/flow/collection-value-continuation.js +192 -0
- package/dist/semantics/normalize/flow/component-solver.d.ts +199 -0
- package/dist/semantics/normalize/flow/component-solver.js +587 -0
- package/dist/semantics/normalize/flow/computed-key-set.d.ts +84 -0
- package/dist/semantics/normalize/flow/computed-key-set.js +660 -0
- package/dist/semantics/normalize/flow/export-importers.d.ts +24 -0
- package/dist/semantics/normalize/flow/export-importers.js +269 -0
- package/dist/semantics/normalize/flow/host-text-sink.d.ts +25 -0
- package/dist/semantics/normalize/flow/host-text-sink.js +87 -0
- package/dist/semantics/normalize/flow/intrinsic-array-callback-frames.d.ts +84 -0
- package/dist/semantics/normalize/flow/intrinsic-array-callback-frames.js +180 -0
- package/dist/semantics/normalize/flow/intrinsic-data-definition.d.ts +35 -0
- package/dist/semantics/normalize/flow/intrinsic-data-definition.js +140 -0
- package/dist/semantics/normalize/flow/invocation-facts.d.ts +98 -0
- package/dist/semantics/normalize/flow/invocation-facts.js +257 -0
- package/dist/semantics/normalize/flow/member-call-forwarding.d.ts +122 -0
- package/dist/semantics/normalize/flow/member-call-forwarding.js +835 -0
- package/dist/semantics/normalize/flow/model.d.ts +357 -0
- package/dist/semantics/normalize/flow/model.js +177 -0
- package/dist/semantics/normalize/flow/native-collection-protocol.d.ts +24 -0
- package/dist/semantics/normalize/flow/native-collection-protocol.js +252 -0
- package/dist/semantics/normalize/flow/node-path-token.d.ts +3 -0
- package/dist/semantics/normalize/flow/node-path-token.js +53 -0
- package/dist/semantics/normalize/flow/object-binding-continuation.d.ts +11 -0
- package/dist/semantics/normalize/flow/object-binding-continuation.js +42 -0
- package/dist/semantics/normalize/flow/origin-authority.d.ts +56 -0
- package/dist/semantics/normalize/flow/origin-authority.js +2 -0
- package/dist/semantics/normalize/flow/owned-class-receivers.d.ts +35 -0
- package/dist/semantics/normalize/flow/owned-class-receivers.js +191 -0
- package/dist/semantics/normalize/flow/parameter-values.d.ts +27 -0
- package/dist/semantics/normalize/flow/parameter-values.js +251 -0
- package/dist/semantics/normalize/flow/proof-hypotheses.d.ts +66 -0
- package/dist/semantics/normalize/flow/proof-hypotheses.js +162 -0
- package/dist/semantics/normalize/flow/record-alias-closure.d.ts +27 -0
- package/dist/semantics/normalize/flow/record-alias-closure.js +298 -0
- package/dist/semantics/normalize/flow/seeded-origins.d.ts +43 -0
- package/dist/semantics/normalize/flow/seeded-origins.js +54 -0
- package/dist/semantics/normalize/flow/source-class-data.d.ts +132 -0
- package/dist/semantics/normalize/flow/source-class-data.js +838 -0
- package/dist/semantics/normalize/flow/source-class-instanceof.d.ts +13 -0
- package/dist/semantics/normalize/flow/source-class-instanceof.js +37 -0
- package/dist/semantics/normalize/flow/source-class-static-data.d.ts +16 -0
- package/dist/semantics/normalize/flow/source-class-static-data.js +47 -0
- package/dist/semantics/normalize/flow/source-construction-frames.d.ts +12 -0
- package/dist/semantics/normalize/flow/source-construction-frames.js +118 -0
- package/dist/semantics/normalize/flow/source-invocation-frame-layout.d.ts +34 -0
- package/dist/semantics/normalize/flow/source-invocation-frame-layout.js +78 -0
- package/dist/semantics/normalize/flow/source-invocation-receiver.d.ts +37 -0
- package/dist/semantics/normalize/flow/source-invocation-receiver.js +95 -0
- package/dist/semantics/normalize/flow/source-prototype-method-identity.d.ts +23 -0
- package/dist/semantics/normalize/flow/source-prototype-method-identity.js +81 -0
- package/dist/semantics/normalize/flow/source-record-data.d.ts +29 -0
- package/dist/semantics/normalize/flow/source-record-data.js +626 -0
- package/dist/semantics/normalize/flow/source-value-session.d.ts +77 -0
- package/dist/semantics/normalize/flow/source-value-session.js +3089 -0
- package/dist/semantics/normalize/flow/targets.d.ts +118 -0
- package/dist/semantics/normalize/flow/targets.js +405 -0
- package/dist/semantics/normalize/flow/value-flow.d.ts +36 -0
- package/dist/semantics/normalize/flow/value-flow.js +823 -0
- package/dist/semantics/normalize/flow/value-provenance.d.ts +31 -0
- package/dist/semantics/normalize/flow/value-provenance.js +112 -0
- package/dist/semantics/normalize/gating.d.ts +51 -0
- package/dist/semantics/normalize/gating.js +560 -0
- package/dist/semantics/normalize/generic-function-choice.d.ts +31 -0
- package/dist/semantics/normalize/generic-function-choice.js +115 -0
- package/dist/semantics/normalize/global-host-mutations.d.ts +51 -0
- package/dist/semantics/normalize/global-host-mutations.js +5989 -0
- package/dist/semantics/normalize/host-effect-contracts.d.ts +77 -0
- package/dist/semantics/normalize/host-effect-contracts.js +143 -0
- package/dist/semantics/normalize/host-mutation-computed-keys.d.ts +38 -0
- package/dist/semantics/normalize/host-mutation-computed-keys.js +26 -0
- package/dist/semantics/normalize/host-mutation-key-reader.d.ts +66 -0
- package/dist/semantics/normalize/host-mutation-key-reader.js +192 -0
- package/dist/semantics/normalize/host-mutation-keys.d.ts +114 -0
- package/dist/semantics/normalize/host-mutation-keys.js +183 -0
- package/dist/semantics/normalize/identities.d.ts +172 -0
- package/dist/semantics/normalize/identities.js +426 -0
- package/dist/semantics/normalize/implicit-arguments-tuple.d.ts +97 -0
- package/dist/semantics/normalize/implicit-arguments-tuple.js +197 -0
- package/dist/semantics/normalize/implicit-arguments.d.ts +11 -0
- package/dist/semantics/normalize/implicit-arguments.js +39 -0
- package/dist/semantics/normalize/instantiation.d.ts +73 -0
- package/dist/semantics/normalize/instantiation.js +399 -0
- package/dist/semantics/normalize/intrinsic-property-call.d.ts +18 -0
- package/dist/semantics/normalize/intrinsic-property-call.js +69 -0
- package/dist/semantics/normalize/intrinsic-prototype.d.ts +41 -0
- package/dist/semantics/normalize/intrinsic-prototype.js +87 -0
- package/dist/semantics/normalize/intrinsic-static-member.d.ts +14 -0
- package/dist/semantics/normalize/intrinsic-static-member.js +23 -0
- package/dist/semantics/normalize/jsdoc-type-names.d.ts +32 -0
- package/dist/semantics/normalize/jsdoc-type-names.js +512 -0
- package/dist/semantics/normalize/keyof.d.ts +32 -0
- package/dist/semantics/normalize/keyof.js +110 -0
- package/dist/semantics/normalize/local-bindings.d.ts +176 -0
- package/dist/semantics/normalize/local-bindings.js +1826 -0
- package/dist/semantics/normalize/logical-result-type.d.ts +16 -0
- package/dist/semantics/normalize/logical-result-type.js +102 -0
- package/dist/semantics/normalize/namespace-paths.d.ts +57 -0
- package/dist/semantics/normalize/namespace-paths.js +108 -0
- package/dist/semantics/normalize/normalize.d.ts +57 -0
- package/dist/semantics/normalize/normalize.js +68 -0
- package/dist/semantics/normalize/object-bag-bindings.d.ts +305 -0
- package/dist/semantics/normalize/object-bag-bindings.js +1290 -0
- package/dist/semantics/normalize/omitted-stated-parameter.d.ts +53 -0
- package/dist/semantics/normalize/omitted-stated-parameter.js +59 -0
- package/dist/semantics/normalize/open-type-form.d.ts +10 -0
- package/dist/semantics/normalize/open-type-form.js +32 -0
- package/dist/semantics/normalize/parameter-bindings.d.ts +361 -0
- package/dist/semantics/normalize/parameter-bindings.js +3339 -0
- package/dist/semantics/normalize/parameter-slot.d.ts +264 -0
- package/dist/semantics/normalize/parameter-slot.js +491 -0
- package/dist/semantics/normalize/physical-overload-result.d.ts +77 -0
- package/dist/semantics/normalize/physical-overload-result.js +99 -0
- package/dist/semantics/normalize/primitive-property-absence.d.ts +12 -0
- package/dist/semantics/normalize/primitive-property-absence.js +60 -0
- package/dist/semantics/normalize/producer-context.d.ts +376 -0
- package/dist/semantics/normalize/producer-context.js +1 -0
- package/dist/semantics/normalize/producers/allocations.d.ts +3 -0
- package/dist/semantics/normalize/producers/allocations.js +863 -0
- package/dist/semantics/normalize/producers/binding-kind.d.ts +37 -0
- package/dist/semantics/normalize/producers/binding-kind.js +36 -0
- package/dist/semantics/normalize/producers/bindings.d.ts +85 -0
- package/dist/semantics/normalize/producers/bindings.js +710 -0
- package/dist/semantics/normalize/producers/boundary.d.ts +34 -0
- package/dist/semantics/normalize/producers/boundary.js +123 -0
- package/dist/semantics/normalize/producers/class-lifecycle.d.ts +3 -0
- package/dist/semantics/normalize/producers/class-lifecycle.js +902 -0
- package/dist/semantics/normalize/producers/computations.d.ts +3 -0
- package/dist/semantics/normalize/producers/computations.js +613 -0
- package/dist/semantics/normalize/producers/control-loops.d.ts +30 -0
- package/dist/semantics/normalize/producers/control-loops.js +91 -0
- package/dist/semantics/normalize/producers/control.d.ts +30 -0
- package/dist/semantics/normalize/producers/control.js +923 -0
- package/dist/semantics/normalize/producers/declaration-lifecycle.d.ts +3 -0
- package/dist/semantics/normalize/producers/declaration-lifecycle.js +390 -0
- package/dist/semantics/normalize/producers/destructuring.d.ts +45 -0
- package/dist/semantics/normalize/producers/destructuring.js +1180 -0
- package/dist/semantics/normalize/producers/dynamic-language.d.ts +3 -0
- package/dist/semantics/normalize/producers/dynamic-language.js +70 -0
- package/dist/semantics/normalize/producers/erasure.d.ts +51 -0
- package/dist/semantics/normalize/producers/erasure.js +90 -0
- package/dist/semantics/normalize/producers/installed.d.ts +3 -0
- package/dist/semantics/normalize/producers/installed.js +55 -0
- package/dist/semantics/normalize/producers/invocations.d.ts +35 -0
- package/dist/semantics/normalize/producers/invocations.js +1796 -0
- package/dist/semantics/normalize/producers/iteration-yield.d.ts +59 -0
- package/dist/semantics/normalize/producers/iteration-yield.js +235 -0
- package/dist/semantics/normalize/producers/jsx.d.ts +3 -0
- package/dist/semantics/normalize/producers/jsx.js +360 -0
- package/dist/semantics/normalize/producers/mint.d.ts +39 -0
- package/dist/semantics/normalize/producers/mint.js +44 -0
- package/dist/semantics/normalize/producers/nullish.d.ts +16 -0
- package/dist/semantics/normalize/producers/nullish.js +27 -0
- package/dist/semantics/normalize/producers/object-assignment.d.ts +8 -0
- package/dist/semantics/normalize/producers/object-assignment.js +204 -0
- package/dist/semantics/normalize/producers/object-tag.d.ts +9 -0
- package/dist/semantics/normalize/producers/object-tag.js +119 -0
- package/dist/semantics/normalize/producers/optional-chain.d.ts +44 -0
- package/dist/semantics/normalize/producers/optional-chain.js +75 -0
- package/dist/semantics/normalize/producers/properties.d.ts +21 -0
- package/dist/semantics/normalize/producers/properties.js +1053 -0
- package/dist/semantics/normalize/producers/protocol.d.ts +67 -0
- package/dist/semantics/normalize/producers/protocol.js +695 -0
- package/dist/semantics/normalize/producers/references.d.ts +53 -0
- package/dist/semantics/normalize/producers/references.js +1027 -0
- package/dist/semantics/normalize/producers/shared.d.ts +561 -0
- package/dist/semantics/normalize/producers/shared.js +1683 -0
- package/dist/semantics/normalize/producers/spread-arguments.d.ts +72 -0
- package/dist/semantics/normalize/producers/spread-arguments.js +375 -0
- package/dist/semantics/normalize/producers/tagged-template.d.ts +5 -0
- package/dist/semantics/normalize/producers/tagged-template.js +307 -0
- package/dist/semantics/normalize/producers/tuple-spread.d.ts +189 -0
- package/dist/semantics/normalize/producers/tuple-spread.js +279 -0
- package/dist/semantics/normalize/property-key-domain.d.ts +36 -0
- package/dist/semantics/normalize/property-key-domain.js +150 -0
- package/dist/semantics/normalize/reachability.d.ts +189 -0
- package/dist/semantics/normalize/reachability.js +1057 -0
- package/dist/semantics/normalize/reassigned-bindings.d.ts +13 -0
- package/dist/semantics/normalize/reassigned-bindings.js +41 -0
- package/dist/semantics/normalize/record-storage-families.d.ts +11 -0
- package/dist/semantics/normalize/record-storage-families.js +109 -0
- package/dist/semantics/normalize/return-bindings.d.ts +260 -0
- package/dist/semantics/normalize/return-bindings.js +1311 -0
- package/dist/semantics/normalize/return-paths.d.ts +2 -0
- package/dist/semantics/normalize/return-paths.js +28 -0
- package/dist/semantics/normalize/script-global-redefinition.d.ts +44 -0
- package/dist/semantics/normalize/script-global-redefinition.js +75 -0
- package/dist/semantics/normalize/specialization.d.ts +201 -0
- package/dist/semantics/normalize/specialization.js +1824 -0
- package/dist/semantics/normalize/structural-array-element.d.ts +176 -0
- package/dist/semantics/normalize/structural-array-element.js +700 -0
- package/dist/semantics/normalize/structural-array-read.d.ts +13 -0
- package/dist/semantics/normalize/structural-array-read.js +124 -0
- package/dist/semantics/normalize/structural-callable.d.ts +12 -0
- package/dist/semantics/normalize/structural-callable.js +82 -0
- package/dist/semantics/normalize/structural-creation-order.d.ts +32 -0
- package/dist/semantics/normalize/structural-creation-order.js +111 -0
- package/dist/semantics/normalize/structural-declarations.d.ts +395 -0
- package/dist/semantics/normalize/structural-declarations.js +968 -0
- package/dist/semantics/normalize/structural-declared-body.d.ts +25 -0
- package/dist/semantics/normalize/structural-declared-body.js +147 -0
- package/dist/semantics/normalize/structural-generics.d.ts +56 -0
- package/dist/semantics/normalize/structural-generics.js +120 -0
- package/dist/semantics/normalize/structural-indexed-access.d.ts +11 -0
- package/dist/semantics/normalize/structural-indexed-access.js +126 -0
- package/dist/semantics/normalize/structural-instantiated-member.d.ts +64 -0
- package/dist/semantics/normalize/structural-instantiated-member.js +407 -0
- package/dist/semantics/normalize/structural-joins.d.ts +44 -0
- package/dist/semantics/normalize/structural-joins.js +143 -0
- package/dist/semantics/normalize/structural-layout-relevance.d.ts +29 -0
- package/dist/semantics/normalize/structural-layout-relevance.js +391 -0
- package/dist/semantics/normalize/structural-layout-type.d.ts +11 -0
- package/dist/semantics/normalize/structural-layout-type.js +1468 -0
- package/dist/semantics/normalize/structural-leaves.d.ts +49 -0
- package/dist/semantics/normalize/structural-leaves.js +125 -0
- package/dist/semantics/normalize/structural-local-union.d.ts +13 -0
- package/dist/semantics/normalize/structural-local-union.js +133 -0
- package/dist/semantics/normalize/structural-members.d.ts +26 -0
- package/dist/semantics/normalize/structural-members.js +84 -0
- package/dist/semantics/normalize/structural-mutable-method.d.ts +15 -0
- package/dist/semantics/normalize/structural-mutable-method.js +109 -0
- package/dist/semantics/normalize/structural-parts.d.ts +131 -0
- package/dist/semantics/normalize/structural-parts.js +737 -0
- package/dist/semantics/normalize/structural-receiver.d.ts +66 -0
- package/dist/semantics/normalize/structural-receiver.js +551 -0
- package/dist/semantics/normalize/structural-rules.d.ts +112 -0
- package/dist/semantics/normalize/structural-rules.js +93 -0
- package/dist/semantics/normalize/structural-self-reference.d.ts +150 -0
- package/dist/semantics/normalize/structural-self-reference.js +494 -0
- package/dist/semantics/normalize/structural.d.ts +202 -0
- package/dist/semantics/normalize/structural.js +4218 -0
- package/dist/semantics/normalize/unreduced-type-form.d.ts +41 -0
- package/dist/semantics/normalize/unreduced-type-form.js +53 -0
- package/dist/semantics/normalize/unresolvable-names.d.ts +56 -0
- package/dist/semantics/normalize/unresolvable-names.js +140 -0
- package/dist/semantics/package-sources.d.ts +16 -0
- package/dist/semantics/package-sources.js +365 -0
- package/dist/semantics/program.d.ts +151 -0
- package/dist/semantics/program.js +667 -0
- package/dist/semantics/prototype-install-source-transform.d.ts +4 -0
- package/dist/semantics/prototype-install-source-transform.js +341 -0
- package/dist/semantics/prototype-object-class-source-transform.d.ts +4 -0
- package/dist/semantics/prototype-object-class-source-transform.js +525 -0
- package/dist/semantics/prototype-reparenting.d.ts +50 -0
- package/dist/semantics/prototype-reparenting.js +317 -0
- package/dist/semantics/stable-checker.d.ts +10 -0
- package/dist/semantics/stable-checker.js +148 -0
- package/dist/semantics/subclass-member-overlay-transform.d.ts +35 -0
- package/dist/semantics/subclass-member-overlay-transform.js +1418 -0
- package/dist/semantics/symbol-keyed-expando-source-transform.d.ts +4 -0
- package/dist/semantics/symbol-keyed-expando-source-transform.js +66 -0
- package/dist/semantics/this-constructor-source-transform.d.ts +4 -0
- package/dist/semantics/this-constructor-source-transform.js +122 -0
- package/dist/semantics/uninstantiable-classes.d.ts +22 -0
- package/dist/semantics/uninstantiable-classes.js +75 -0
- package/dist/targets/cpp/balanced-units.d.ts +3 -0
- package/dist/targets/cpp/balanced-units.js +58 -0
- package/dist/targets/cpp/borrowed-call-entry.d.ts +30 -0
- package/dist/targets/cpp/borrowed-call-entry.js +68 -0
- package/dist/targets/cpp/captures.d.ts +68 -0
- package/dist/targets/cpp/captures.js +269 -0
- package/dist/targets/cpp/class-layout.d.ts +313 -0
- package/dist/targets/cpp/class-layout.js +483 -0
- package/dist/targets/cpp/class-properties/computed-method-value.d.ts +25 -0
- package/dist/targets/cpp/class-properties/computed-method-value.js +22 -0
- package/dist/targets/cpp/class-properties/emit-class-properties.d.ts +216 -0
- package/dist/targets/cpp/class-properties/emit-class-properties.js +917 -0
- package/dist/targets/cpp/class-properties/native-prototype.d.ts +11 -0
- package/dist/targets/cpp/class-properties/native-prototype.js +101 -0
- package/dist/targets/cpp/class-ref-transport.d.ts +12 -0
- package/dist/targets/cpp/class-ref-transport.js +32 -0
- package/dist/targets/cpp/conversions.d.ts +3 -0
- package/dist/targets/cpp/conversions.js +2027 -0
- package/dist/targets/cpp/deferral-safety.d.ts +82 -0
- package/dist/targets/cpp/deferral-safety.js +86 -0
- package/dist/targets/cpp/direct-call-receivers.d.ts +37 -0
- package/dist/targets/cpp/direct-call-receivers.js +79 -0
- package/dist/targets/cpp/document.d.ts +74 -0
- package/dist/targets/cpp/document.js +106 -0
- package/dist/targets/cpp/emit-allocation.d.ts +60 -0
- package/dist/targets/cpp/emit-allocation.js +573 -0
- package/dist/targets/cpp/emit-arrays.d.ts +119 -0
- package/dist/targets/cpp/emit-arrays.js +1047 -0
- package/dist/targets/cpp/emit-binding-reference.d.ts +17 -0
- package/dist/targets/cpp/emit-binding-reference.js +120 -0
- package/dist/targets/cpp/emit-bindings.d.ts +158 -0
- package/dist/targets/cpp/emit-bindings.js +769 -0
- package/dist/targets/cpp/emit-buffers.d.ts +156 -0
- package/dist/targets/cpp/emit-buffers.js +573 -0
- package/dist/targets/cpp/emit-callable.d.ts +230 -0
- package/dist/targets/cpp/emit-callable.js +2154 -0
- package/dist/targets/cpp/emit-carrier-members.d.ts +406 -0
- package/dist/targets/cpp/emit-carrier-members.js +1224 -0
- package/dist/targets/cpp/emit-coercion.d.ts +26 -0
- package/dist/targets/cpp/emit-coercion.js +39 -0
- package/dist/targets/cpp/emit-context.d.ts +1882 -0
- package/dist/targets/cpp/emit-context.js +904 -0
- package/dist/targets/cpp/emit-dynamic-properties.d.ts +174 -0
- package/dist/targets/cpp/emit-dynamic-properties.js +1249 -0
- package/dist/targets/cpp/emit-equality.d.ts +39 -0
- package/dist/targets/cpp/emit-equality.js +472 -0
- package/dist/targets/cpp/emit-exceptions.d.ts +104 -0
- package/dist/targets/cpp/emit-exceptions.js +513 -0
- package/dist/targets/cpp/emit-field-owner.d.ts +4 -0
- package/dist/targets/cpp/emit-field-owner.js +27 -0
- package/dist/targets/cpp/emit-in.d.ts +31 -0
- package/dist/targets/cpp/emit-in.js +426 -0
- package/dist/targets/cpp/emit-instanceof.d.ts +19 -0
- package/dist/targets/cpp/emit-instanceof.js +601 -0
- package/dist/targets/cpp/emit-integers.d.ts +68 -0
- package/dist/targets/cpp/emit-integers.js +184 -0
- package/dist/targets/cpp/emit-iterator.d.ts +100 -0
- package/dist/targets/cpp/emit-iterator.js +1137 -0
- package/dist/targets/cpp/emit-json.d.ts +73 -0
- package/dist/targets/cpp/emit-json.js +823 -0
- package/dist/targets/cpp/emit-jsx.d.ts +74 -0
- package/dist/targets/cpp/emit-jsx.js +806 -0
- package/dist/targets/cpp/emit-mixed-binary.d.ts +51 -0
- package/dist/targets/cpp/emit-mixed-binary.js +60 -0
- package/dist/targets/cpp/emit-namespaces.d.ts +101 -0
- package/dist/targets/cpp/emit-namespaces.js +133 -0
- package/dist/targets/cpp/emit-narrowing.d.ts +738 -0
- package/dist/targets/cpp/emit-narrowing.js +3967 -0
- package/dist/targets/cpp/emit-native-equality.d.ts +3 -0
- package/dist/targets/cpp/emit-native-equality.js +14 -0
- package/dist/targets/cpp/emit-native-selection.d.ts +5 -0
- package/dist/targets/cpp/emit-native-selection.js +37 -0
- package/dist/targets/cpp/emit-object-tag.d.ts +4 -0
- package/dist/targets/cpp/emit-object-tag.js +108 -0
- package/dist/targets/cpp/emit-owned-record.d.ts +2 -0
- package/dist/targets/cpp/emit-owned-record.js +15 -0
- package/dist/targets/cpp/emit-presence.d.ts +78 -0
- package/dist/targets/cpp/emit-presence.js +376 -0
- package/dist/targets/cpp/emit-properties.d.ts +105 -0
- package/dist/targets/cpp/emit-properties.js +1640 -0
- package/dist/targets/cpp/emit-record-view.d.ts +20 -0
- package/dist/targets/cpp/emit-record-view.js +354 -0
- package/dist/targets/cpp/emit-return.d.ts +5 -0
- package/dist/targets/cpp/emit-return.js +237 -0
- package/dist/targets/cpp/emit-sum-widening.d.ts +10 -0
- package/dist/targets/cpp/emit-sum-widening.js +69 -0
- package/dist/targets/cpp/emit-tonumber.d.ts +38 -0
- package/dist/targets/cpp/emit-tonumber.js +177 -0
- package/dist/targets/cpp/emit-tostring.d.ts +92 -0
- package/dist/targets/cpp/emit-tostring.js +556 -0
- package/dist/targets/cpp/emit-typeof.d.ts +49 -0
- package/dist/targets/cpp/emit-typeof.js +317 -0
- package/dist/targets/cpp/emit-union-properties.d.ts +181 -0
- package/dist/targets/cpp/emit-union-properties.js +1281 -0
- package/dist/targets/cpp/emit.d.ts +45 -0
- package/dist/targets/cpp/emit.js +2225 -0
- package/dist/targets/cpp/error-types.d.ts +4 -0
- package/dist/targets/cpp/error-types.js +11 -0
- package/dist/targets/cpp/function-source-reads.d.ts +72 -0
- package/dist/targets/cpp/function-source-reads.js +148 -0
- package/dist/targets/cpp/host/atomics.d.ts +25 -0
- package/dist/targets/cpp/host/atomics.js +63 -0
- package/dist/targets/cpp/host/core-globals.d.ts +108 -0
- package/dist/targets/cpp/host/core-globals.js +158 -0
- package/dist/targets/cpp/host/dynamic-argument-members.d.ts +42 -0
- package/dist/targets/cpp/host/dynamic-argument-members.js +61 -0
- package/dist/targets/cpp/host/emit-host-arity.d.ts +139 -0
- package/dist/targets/cpp/host/emit-host-arity.js +232 -0
- package/dist/targets/cpp/host/emit-host-invoke.d.ts +91 -0
- package/dist/targets/cpp/host/emit-host-invoke.js +1105 -0
- package/dist/targets/cpp/host/emit-host-object.d.ts +55 -0
- package/dist/targets/cpp/host/emit-host-object.js +2206 -0
- package/dist/targets/cpp/host/emit-host-properties.d.ts +69 -0
- package/dist/targets/cpp/host/emit-host-properties.js +533 -0
- package/dist/targets/cpp/host/emit-host-reflect.d.ts +4 -0
- package/dist/targets/cpp/host/emit-host-reflect.js +180 -0
- package/dist/targets/cpp/host/emit-host-value.d.ts +120 -0
- package/dist/targets/cpp/host/emit-host-value.js +392 -0
- package/dist/targets/cpp/host/host-members.d.ts +505 -0
- package/dist/targets/cpp/host/host-members.js +819 -0
- package/dist/targets/cpp/host/host-method-aliases.d.ts +30 -0
- package/dist/targets/cpp/host/host-method-aliases.js +76 -0
- package/dist/targets/cpp/host/native-protocols.d.ts +47 -0
- package/dist/targets/cpp/host/native-protocols.js +183 -0
- package/dist/targets/cpp/host/object-protocol.d.ts +351 -0
- package/dist/targets/cpp/host/object-protocol.js +671 -0
- package/dist/targets/cpp/host-namespace-reads.d.ts +83 -0
- package/dist/targets/cpp/host-namespace-reads.js +113 -0
- package/dist/targets/cpp/manifest/capabilities.d.ts +39 -0
- package/dist/targets/cpp/manifest/capabilities.js +1484 -0
- package/dist/targets/cpp/manifest.d.ts +23 -0
- package/dist/targets/cpp/manifest.js +113 -0
- package/dist/targets/cpp/native-error-base.d.ts +38 -0
- package/dist/targets/cpp/native-error-base.js +74 -0
- package/dist/targets/cpp/native-narrowing-transport.d.ts +12 -0
- package/dist/targets/cpp/native-narrowing-transport.js +151 -0
- package/dist/targets/cpp/native-selection-helpers.d.ts +11 -0
- package/dist/targets/cpp/native-selection-helpers.js +46 -0
- package/dist/targets/cpp/native-symbol-keys.d.ts +8 -0
- package/dist/targets/cpp/native-symbol-keys.js +34 -0
- package/dist/targets/cpp/ownership.d.ts +43 -0
- package/dist/targets/cpp/ownership.js +38 -0
- package/dist/targets/cpp/owning-conversion-input.d.ts +14 -0
- package/dist/targets/cpp/owning-conversion-input.js +12 -0
- package/dist/targets/cpp/property-read-claims.d.ts +62 -0
- package/dist/targets/cpp/property-read-claims.js +23 -0
- package/dist/targets/cpp/property-store-claims.d.ts +62 -0
- package/dist/targets/cpp/property-store-claims.js +26 -0
- package/dist/targets/cpp/prototype/emit-prototype-array.d.ts +111 -0
- package/dist/targets/cpp/prototype/emit-prototype-array.js +602 -0
- package/dist/targets/cpp/prototype/emit-prototype-date.d.ts +133 -0
- package/dist/targets/cpp/prototype/emit-prototype-date.js +515 -0
- package/dist/targets/cpp/prototype/emit-prototype-error.d.ts +13 -0
- package/dist/targets/cpp/prototype/emit-prototype-error.js +54 -0
- package/dist/targets/cpp/prototype/emit-prototype-invoke.d.ts +34 -0
- package/dist/targets/cpp/prototype/emit-prototype-invoke.js +1003 -0
- package/dist/targets/cpp/prototype/emit-prototype-iterator.d.ts +47 -0
- package/dist/targets/cpp/prototype/emit-prototype-iterator.js +250 -0
- package/dist/targets/cpp/prototype/emit-prototype-promise.d.ts +46 -0
- package/dist/targets/cpp/prototype/emit-prototype-promise.js +143 -0
- package/dist/targets/cpp/prototype/emit-prototype-regexp.d.ts +335 -0
- package/dist/targets/cpp/prototype/emit-prototype-regexp.js +853 -0
- package/dist/targets/cpp/prototype/emit-prototype-string.d.ts +42 -0
- package/dist/targets/cpp/prototype/emit-prototype-string.js +252 -0
- package/dist/targets/cpp/prototype/prototype-method-reads.d.ts +25 -0
- package/dist/targets/cpp/prototype/prototype-method-reads.js +182 -0
- package/dist/targets/cpp/reactive-dependencies.d.ts +140 -0
- package/dist/targets/cpp/reactive-dependencies.js +432 -0
- package/dist/targets/cpp/reactive-origins.d.ts +44 -0
- package/dist/targets/cpp/reactive-origins.js +82 -0
- package/dist/targets/cpp/records.d.ts +277 -0
- package/dist/targets/cpp/records.js +2427 -0
- package/dist/targets/cpp/recursive-containers.d.ts +43 -0
- package/dist/targets/cpp/recursive-containers.js +144 -0
- package/dist/targets/cpp/regexp-types.d.ts +56 -0
- package/dist/targets/cpp/regexp-types.js +59 -0
- package/dist/targets/cpp/substrate.d.ts +125 -0
- package/dist/targets/cpp/substrate.js +12 -0
- package/dist/targets/cpp/translation-unit.d.ts +219 -0
- package/dist/targets/cpp/translation-unit.js +2063 -0
- package/dist/targets/cpp/types.d.ts +280 -0
- package/dist/targets/cpp/types.js +1135 -0
- package/dist/targets/cpp/virtual-methods.d.ts +95 -0
- package/dist/targets/cpp/virtual-methods.js +264 -0
- package/package.json +95 -0
- package/src/targets/cpp/runtime/gea_dynamic_proxy.h +824 -0
- package/src/targets/cpp/runtime/gea_eval.h +1376 -0
- package/src/targets/cpp/runtime/gea_native_class_prototype.h +44 -0
- package/src/targets/cpp/runtime/gea_runtime.h +29222 -0
- package/src/targets/cpp/runtime/gea_runtime_builtins.cpp +55 -0
|
@@ -0,0 +1,1047 @@
|
|
|
1
|
+
import { regexpRoleOf } from './prototype/emit-prototype-regexp.js';
|
|
2
|
+
import { boxedValueText } from './emit-dynamic-properties.js';
|
|
3
|
+
import { collectDefinitionSites, controlFlowGraphOf, dominatorTreeOf, isVisible, naturalLoopsOf } from '../../ir/dominance.js';
|
|
4
|
+
import { operandsOfIrOperation, resultOfIrOperation } from '../../ir/queries.js';
|
|
5
|
+
import { containsUnresolved, representationKey } from '../../representation/model.js';
|
|
6
|
+
import { admittedDenseLoopPlanOf, denseLoopsOf } from '../../ir/dense-loops.js';
|
|
7
|
+
import { bindingReference, cppDenseDivisorName, cppDenseFlagName, cppDenseLengthName, cppDensePointerName, cppDenseRowName, createCppEmitBlockedError, defineValue, operandText, storageTypeOf } from './emit-context.js';
|
|
8
|
+
import { readsCell } from './deferral-safety.js';
|
|
9
|
+
import { cellValueText } from './emit-bindings.js';
|
|
10
|
+
import { alignedText } from './emit-callable.js';
|
|
11
|
+
import { cppConstantLiteral, cppNarrowedIntegerType, cppGlobalName, cppRecordFieldName, cppTypeOf, cppScalarType } from './types.js';
|
|
12
|
+
import { alignedValueText, narrowedLoadText, widenedStoreText } from './emit-narrowing.js';
|
|
13
|
+
import { arrayBulkAppendMethodName } from './prototype/emit-prototype-array.js';
|
|
14
|
+
/**
|
|
15
|
+
* How many constant elements make a static table the better spelling.
|
|
16
|
+
*
|
|
17
|
+
* Every element of a literal renders as its own `push` statement, so a mesh
|
|
18
|
+
* table of 87,210 doubles is 87,210 statements in one function body. Clang's
|
|
19
|
+
* per-function passes are superlinear in statement count: `ios-metal-world-game`
|
|
20
|
+
* carries four such tables -- 252,342 elements between them -- in a single
|
|
21
|
+
* module body, which unrolled was 98% of a 256,880 line translation unit and
|
|
22
|
+
* did not finish compiling in 105 minutes at 35.7 GB resident.
|
|
23
|
+
*
|
|
24
|
+
* Below a handful the individual stores are worth keeping: they fold, they
|
|
25
|
+
* inline, and three of them read as what the source says. Past that nothing
|
|
26
|
+
* folds and the statements are pure cost -- a twelve-entry month table
|
|
27
|
+
* rebuilt on every call was twelve capacity checks and up to four
|
|
28
|
+
* reallocations (`examples/apps/weather`), where the table is one `reserve`
|
|
29
|
+
* and one copy out of `.rodata`. So the table starts where a literal stops
|
|
30
|
+
* being a handful, not at the size where the statement form stops compiling.
|
|
31
|
+
*/
|
|
32
|
+
const constantTableThreshold = 8;
|
|
33
|
+
/** How many values one line of a static table's initializer carries. A table of 87,210 doubles is otherwise a single 700 KB line. */
|
|
34
|
+
const constantTableRowWidth = 16;
|
|
35
|
+
/**
|
|
36
|
+
* The element spellings a static table may hold.
|
|
37
|
+
*
|
|
38
|
+
* Trivially copyable scalars only -- their initializer is a plain literal list
|
|
39
|
+
* and their table is `.rodata`. A `Ref` or a `std::string` element would need a
|
|
40
|
+
* dynamic initializer, which is the cost this avoids rather than one it should
|
|
41
|
+
* pay somewhere else.
|
|
42
|
+
*/
|
|
43
|
+
const constantTableElements = new Set(['double', 'long long', 'bool']);
|
|
44
|
+
/** How deep a folded constant expression may nest before this stops proving it. `-x` over a literal is one level; nothing real needs many. */
|
|
45
|
+
const constantExpressionDepth = 4;
|
|
46
|
+
/**
|
|
47
|
+
* Whether a value's rendered text is a constant expression a `static const` initializer may hold.
|
|
48
|
+
*
|
|
49
|
+
* `deferredTexts` is the gate in every case: a value that was NOT folded is
|
|
50
|
+
* spelled as a local's name, and a name is not an initializer. Past that gate a
|
|
51
|
+
* `constant` operation qualifies outright, and a unary `-`/`+` qualifies when
|
|
52
|
+
* what it negates does -- which is how a source `-0.35792` reaches here.
|
|
53
|
+
*/
|
|
54
|
+
const isConstantExpression = (ctx, value, depth) => {
|
|
55
|
+
if (!ctx.deferredTexts.has(value))
|
|
56
|
+
return false;
|
|
57
|
+
if (ctx.constantTexts.has(value))
|
|
58
|
+
return true;
|
|
59
|
+
if (depth >= constantExpressionDepth)
|
|
60
|
+
return false;
|
|
61
|
+
const origin = ctx.computeOrigins.get(value);
|
|
62
|
+
if (origin === undefined || origin.form !== 'unary')
|
|
63
|
+
return false;
|
|
64
|
+
if (origin.operator !== '-' && origin.operator !== '+')
|
|
65
|
+
return false;
|
|
66
|
+
if (origin.operands.length !== 1)
|
|
67
|
+
return false;
|
|
68
|
+
const operand = origin.operands[0];
|
|
69
|
+
if (operand === undefined)
|
|
70
|
+
return false;
|
|
71
|
+
return isConstantExpression(ctx, operand.value, depth + 1);
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* One array literal whose every element is a folded constant, as a static table.
|
|
75
|
+
*
|
|
76
|
+
* The predicate is the emitter's own records rather than the shape of the
|
|
77
|
+
* rendered text: `deferredTexts` says the value's text is spelled inline rather
|
|
78
|
+
* than as the name of a local, and `constantTexts` says it came from a
|
|
79
|
+
* `constant` operation. Both together are what make the push read
|
|
80
|
+
* `v117974->push((1.5))`, and they are what makes the same text legal inside a
|
|
81
|
+
* `static const` initializer.
|
|
82
|
+
*
|
|
83
|
+
* A source `-0.00981` is NOT a constant operation: it is unary minus over one,
|
|
84
|
+
* and it renders `(-(0.00981))`. Two of every five elements of
|
|
85
|
+
* `ios-metal-world-game`'s vertex tables are that shape, and reading only
|
|
86
|
+
* `constantTexts` refused all four tables on their account. So a folded unary
|
|
87
|
+
* `-`/`+` over a constant expression is itself one, which `computeOrigins`
|
|
88
|
+
* answers without any new bookkeeping.
|
|
89
|
+
*
|
|
90
|
+
* A literal with a hole or a spread is not a table -- a hole is observably not
|
|
91
|
+
* an element -- and neither is one whose elements are computed at run time, so
|
|
92
|
+
* both keep the statement form.
|
|
93
|
+
*/
|
|
94
|
+
const constantTableOf = (ctx, operation, elementRepresentation, element, name) => {
|
|
95
|
+
if (operation.elements.length < constantTableThreshold)
|
|
96
|
+
return null;
|
|
97
|
+
if (!constantTableElements.has(element))
|
|
98
|
+
return null;
|
|
99
|
+
const texts = [];
|
|
100
|
+
for (const slot of operation.elements) {
|
|
101
|
+
if (slot.kind !== 'element')
|
|
102
|
+
return null;
|
|
103
|
+
if (!isConstantExpression(ctx, slot.value.value, 0))
|
|
104
|
+
return null;
|
|
105
|
+
texts.push(alignedText(ctx, elementRepresentation, slot.value, 'allocate-array-object'));
|
|
106
|
+
}
|
|
107
|
+
const rows = [];
|
|
108
|
+
for (let at = 0; at < texts.length; at += constantTableRowWidth) {
|
|
109
|
+
rows.push(`${texts.slice(at, at + constantTableRowWidth).join(', ')},`);
|
|
110
|
+
}
|
|
111
|
+
return { name: `gea_table_${name}`, rows, count: texts.length };
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* An Array exotic object with its elements installed.
|
|
115
|
+
*
|
|
116
|
+
* A hole is pushed as a hole, not as a default-constructed element: the two are
|
|
117
|
+
* observably different (`0 in a`, enumeration, `length`), and this is the one
|
|
118
|
+
* place the distinction the IR carries could be silently dropped.
|
|
119
|
+
*/
|
|
120
|
+
/**
|
|
121
|
+
* One element of a WITHHELD array literal -- the only place this backend emits
|
|
122
|
+
* a braced-init-list of computed values (`gea::arrayOf<T>({a, b})`).
|
|
123
|
+
*
|
|
124
|
+
* Inside braces C++ applies the narrowing rules ([dcl.init.list]/7), which are
|
|
125
|
+
* strictly stronger than the ordinary implicit conversions every other
|
|
126
|
+
* argument position allows: `long long` to `double` is a perfectly good
|
|
127
|
+
* conversion as a function argument and a hard error as a list element,
|
|
128
|
+
* because the source type cannot be proven to round-trip. `alignedText` is
|
|
129
|
+
* right for both positions and cannot tell them apart -- it asks whether a
|
|
130
|
+
* conversion EXISTS, and this one does.
|
|
131
|
+
*
|
|
132
|
+
* So the cast is added here, at the one site the stronger rule applies, and
|
|
133
|
+
* only between two arithmetic scalars: `static_cast` is the explicit spelling
|
|
134
|
+
* of the identical conversion, which is exactly what [dcl.init.list] accepts.
|
|
135
|
+
*
|
|
136
|
+
* Measured on `examples/bouncing-balls`: `Math.max(BALL_R * 2 + 1,
|
|
137
|
+
* Math.floor(window.innerWidth()))` packs an integer-carrier `long long`
|
|
138
|
+
* beside a `double`, and clang rejected both sites with
|
|
139
|
+
* `-Wc++11-narrowing` on a program that certified, lowered and emitted
|
|
140
|
+
* cleanly.
|
|
141
|
+
*
|
|
142
|
+
* `bigint` is excluded on both sides: `gea::BigInt` is a class type, and a
|
|
143
|
+
* `static_cast` to or from it is not the arithmetic conversion this rule is
|
|
144
|
+
* about. Such a pair keeps `alignedText`'s answer, and if that answer is
|
|
145
|
+
* wrong the refusal it raises names it.
|
|
146
|
+
*/
|
|
147
|
+
const packElementText = (ctx, element, elementType, value) => {
|
|
148
|
+
const text = alignedText(ctx, element, value, 'allocate-array-object');
|
|
149
|
+
const held = value.representation;
|
|
150
|
+
if (element.kind !== 'scalar' || held.kind !== 'scalar')
|
|
151
|
+
return text;
|
|
152
|
+
if (element.domain === 'bigint' || held.domain === 'bigint')
|
|
153
|
+
return text;
|
|
154
|
+
// The STORAGE, not the carrier: a value the integer census narrowed is held
|
|
155
|
+
// in a `long long` while its carrier still says `scalar(number)`, so asking
|
|
156
|
+
// the carrier answers `double` for a variable that is not one -- and the
|
|
157
|
+
// cast this rule exists to add is exactly the one that gets skipped.
|
|
158
|
+
// `examples/bouncing-balls` and `examples/gea3d-cube` both emitted a
|
|
159
|
+
// `long long` into a `{...}` of `double` and were rejected for it.
|
|
160
|
+
if (storageTypeOf(ctx, value.value, held) === elementType)
|
|
161
|
+
return text;
|
|
162
|
+
return `static_cast<${elementType}>(${text})`;
|
|
163
|
+
};
|
|
164
|
+
export const emitAllocateArrayObject = (ctx, lines, operation) => {
|
|
165
|
+
const representation = operation.result.representation;
|
|
166
|
+
// `reason` records only WHY the destination cell is `dynamic` (an opt-in
|
|
167
|
+
// fallback literal, a rest binding of a declared `any` never narrowed, ...);
|
|
168
|
+
// it names no separate runtime representation, so the allocation below --
|
|
169
|
+
// build a native `ArrayObject<gea::Value>`, fill it, box the result -- is
|
|
170
|
+
// the correct emission for every one of them alike. Gating on one specific
|
|
171
|
+
// reason left `const [a, ...rest] = anyIterable` (`ir/lower-destructuring.ts`'s
|
|
172
|
+
// `lowerArrayPatternRest`) refusing to reach an allocation this exact branch
|
|
173
|
+
// already performs for the sibling literal `[...anyIterable]`.
|
|
174
|
+
if (representation.kind === 'dynamic') {
|
|
175
|
+
const name = defineValue(ctx, operation.result);
|
|
176
|
+
const array = `${name}_array`;
|
|
177
|
+
lines.push(`${name} = [&]() { auto ${array} = gea::makeRef<gea::ArrayObject<gea::Value>>();`);
|
|
178
|
+
for (const slot of operation.elements) {
|
|
179
|
+
if (slot.kind === 'element')
|
|
180
|
+
lines.push(`${array}->push(${boxedValueText(ctx, slot.value, 'a fallback array element')});`);
|
|
181
|
+
else if (slot.kind === 'hole')
|
|
182
|
+
lines.push(`${array}->pushHole();`);
|
|
183
|
+
else if (slot.kind === 'gather')
|
|
184
|
+
lines.push(`gea::runtime::iterator::appendGather(*${array}, ${operandText(ctx, slot.iterator)});`);
|
|
185
|
+
else
|
|
186
|
+
throw createCppEmitBlockedError('runtime-helper:allocation:array-literal:dynamic(spread)', 'fallback array spread needs dynamic iteration');
|
|
187
|
+
}
|
|
188
|
+
lines.push(`return gea::Value::box(gea::Value::Tag::Object, ${array}); }();`);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (representation.kind !== 'array-object') {
|
|
192
|
+
throw createCppEmitBlockedError(`runtime-helper:allocation:array-literal:${representation.kind}`, `carries a "${representation.kind}" result, but an array literal must allocate an "array-object" carrier`);
|
|
193
|
+
}
|
|
194
|
+
if (representation.ownership !== 'shared-refcount') {
|
|
195
|
+
throw createCppEmitBlockedError(`runtime-helper:allocation:array-literal:array-object(${representation.ownership})`, `an array allocation carries ownership "${representation.ownership}", but this emitter only spells std::make_shared for "shared-refcount"`);
|
|
196
|
+
}
|
|
197
|
+
const element = cppTypeOf(representation.element);
|
|
198
|
+
// A literal made entirely of ordinary elements whose one use is an
|
|
199
|
+
// expression away is withheld whole rather than built into a temporary --
|
|
200
|
+
// see `EmitContext.pendingPacks`. A hole or a spread is not a value an
|
|
201
|
+
// initializer list can carry, so a literal containing either keeps the
|
|
202
|
+
// statement form below; a hole in particular is observably not an element
|
|
203
|
+
// and could not survive the crossing.
|
|
204
|
+
const ordinary = operation.elements.flatMap((slot) => (slot.kind === 'element' ? [slot.value] : []));
|
|
205
|
+
if (!representation.recursive && ctx.callArgumentOnly.has(operation.result.id) && ordinary.length === operation.elements.length) {
|
|
206
|
+
const elements = ordinary.map((value) => packElementText(ctx, representation.element, element, value));
|
|
207
|
+
ctx.pendingPacks.set(operation.result.id, { elements, elementType: element });
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
const name = defineValue(ctx, operation.result);
|
|
211
|
+
// A recursive list owns the named wrapper, not its ArrayObject base. The
|
|
212
|
+
// wrapper is intentionally skipped by the braced pack fast path above too:
|
|
213
|
+
// `arrayOf<E>` returns the base `Ref<ArrayObject<E>>`, while the source
|
|
214
|
+
// value's identity is `Ref<wrapper>`.
|
|
215
|
+
lines.push(`${name} = gea::makeRef<${cppTypeOf(representation, 'owned')}>();`);
|
|
216
|
+
// The capacity this array's fill loop already states -- see
|
|
217
|
+
// `collectCapacityHints`. It renders here, at the allocation, because that
|
|
218
|
+
// is the one point every path to the loop passes through.
|
|
219
|
+
const capacity = ctx.capacityHints.get(operation.result.id);
|
|
220
|
+
if (capacity !== undefined) {
|
|
221
|
+
const count = capacity.kind === 'literal'
|
|
222
|
+
? capacity.text
|
|
223
|
+
: capacity.kind === 'value'
|
|
224
|
+
? operandText(ctx, capacity.operand)
|
|
225
|
+
: cellValueText(bindingReference(ctx, capacity.declaration, 'an array capacity hint'));
|
|
226
|
+
lines.push(`gea::reserveHint(${name}, ${count});`);
|
|
227
|
+
}
|
|
228
|
+
const table = constantTableOf(ctx, operation, representation.element, element, name);
|
|
229
|
+
if (table !== null) {
|
|
230
|
+
lines.push(`static const ${element} ${table.name}[] = {`);
|
|
231
|
+
for (const row of table.rows)
|
|
232
|
+
lines.push(` ${row}`);
|
|
233
|
+
lines.push('};');
|
|
234
|
+
lines.push(`gea::runtime::array::appendTable(${name}, ${table.name}, ${table.count});`);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
for (const slot of operation.elements) {
|
|
238
|
+
if (slot.kind === 'hole') {
|
|
239
|
+
lines.push(`${name}->pushHole();`);
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (slot.kind === 'spread') {
|
|
243
|
+
// `ir/lower-allocation.ts` already proved the source is one of the three
|
|
244
|
+
// natively-iterable shapes and that the elements its range copy produces
|
|
245
|
+
// share this literal's exact element carrier -- these are fail-closed
|
|
246
|
+
// re-checks, not a first opinion, kept for the same reason
|
|
247
|
+
// `lowerTupleLiteral`'s arity assertion is kept: a future widening of
|
|
248
|
+
// that lowering that forgot the match would otherwise emit an ill-formed
|
|
249
|
+
// range copy silently.
|
|
250
|
+
const spread = slot.value.representation;
|
|
251
|
+
// A `Set<T>` (ECMA-262 24.2.3.10) and a `string` (22.1.3.36) each drain
|
|
252
|
+
// to completion into the same destination, through their own bulk
|
|
253
|
+
// appends. Neither takes a `from`: only an Array source has a rest
|
|
254
|
+
// element's "everything past position N" shape, and `lower-allocation.ts`
|
|
255
|
+
// never mints a non-zero `from` for the other two.
|
|
256
|
+
if (spread.kind === 'keyed-collection' && spread.family === 'set') {
|
|
257
|
+
if (representationKey(spread.key) !== representationKey(representation.element) || slot.from !== 0) {
|
|
258
|
+
throw createCppEmitBlockedError(`conversion:${representationKey(spread.key)}->${representationKey(representation.element)}`, `a Set spread element's own key carrier does not match this array's "${representationKey(representation.element)}" element carrier`);
|
|
259
|
+
}
|
|
260
|
+
lines.push(`gea::appendSetRange(*${name}, *${operandText(ctx, slot.value)});`);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
// A `Map` spreads as one freshly built `[K, V]` pair per entry (ECMA-262
|
|
264
|
+
// 24.1.5.1), so the destination's element carrier must be that pair's
|
|
265
|
+
// record -- checked here by field key and by the collection's own key and
|
|
266
|
+
// value carriers, the same three facts `publish.ts`'s
|
|
267
|
+
// `mapPairCursorElementOf` checks before publishing the cursor.
|
|
268
|
+
if (spread.kind === 'keyed-collection' && spread.family === 'map') {
|
|
269
|
+
const pair = representation.element.kind === 'record' ? representation.element : null;
|
|
270
|
+
const first = pair?.fields[0];
|
|
271
|
+
const second = pair?.fields[1];
|
|
272
|
+
const matches = pair !== null &&
|
|
273
|
+
pair.fields.length === 2 &&
|
|
274
|
+
first?.key === '0' &&
|
|
275
|
+
second?.key === '1' &&
|
|
276
|
+
spread.value !== null &&
|
|
277
|
+
representationKey(first.value) === representationKey(spread.key) &&
|
|
278
|
+
representationKey(second.value) === representationKey(spread.value) &&
|
|
279
|
+
slot.from === 0;
|
|
280
|
+
if (!matches) {
|
|
281
|
+
throw createCppEmitBlockedError(`conversion:map-pair->${representationKey(representation.element)}`, `a Map spread element yields "[K, V]" pairs, which this array's "${representationKey(representation.element)}" element carrier cannot hold`);
|
|
282
|
+
}
|
|
283
|
+
lines.push(`gea::appendMapRange(*${name}, *${operandText(ctx, slot.value)});`);
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
// A `RegExpExecArray`'s capture slots (ECMA-262 22.2.7.2): a String or
|
|
287
|
+
// `undefined` in each, so the destination's element has to be the
|
|
288
|
+
// optional string -- `publish.ts`'s `patternSourceSnapshotOf` is the
|
|
289
|
+
// one thing that publishes this pairing, and this is its re-check.
|
|
290
|
+
if (regexpRoleOf(spread) === 'exec-result') {
|
|
291
|
+
const element = representation.element;
|
|
292
|
+
if (element.kind !== 'optional' || element.payload.kind !== 'string' || slot.from !== 0) {
|
|
293
|
+
throw createCppEmitBlockedError(`conversion:regexp-exec-capture->${representationKey(element)}`, `a RegExpExecArray spread yields a string or \`undefined\` per capture slot, which this array's "${representationKey(element)}" element carrier cannot hold`);
|
|
294
|
+
}
|
|
295
|
+
lines.push(`gea::runtime::regex::appendCaptureRange(*${name}, *${operandText(ctx, slot.value)});`);
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (spread.kind === 'string') {
|
|
299
|
+
if (representation.element.kind !== 'string' || slot.from !== 0) {
|
|
300
|
+
throw createCppEmitBlockedError(`conversion:code-point->${representationKey(representation.element)}`, `a string spread element yields code points, which this array's "${representationKey(representation.element)}" element carrier cannot hold`);
|
|
301
|
+
}
|
|
302
|
+
lines.push(`gea::appendCodePointRange(*${name}, ${operandText(ctx, slot.value)});`);
|
|
303
|
+
continue;
|
|
304
|
+
}
|
|
305
|
+
// A cursor source -- a `Generator<T, ...>` carried as `iterator(T)`
|
|
306
|
+
// (`representation/derive.ts`) -- is drained by pulling its own steps.
|
|
307
|
+
// `[...g]` runs the coroutine to completion, which is exactly ECMA-262
|
|
308
|
+
// 13.2.4.2 ArrayAccumulation for a SpreadElement: there is no `break`
|
|
309
|
+
// inside a spread, so a generator that never completes never returns
|
|
310
|
+
// here, the same way it never returns in node.
|
|
311
|
+
if (spread.kind === 'iterator') {
|
|
312
|
+
if (representationKey(spread.element) !== representationKey(representation.element) || slot.from !== 0) {
|
|
313
|
+
throw createCppEmitBlockedError(`conversion:${representationKey(spread.element)}->${representationKey(representation.element)}`, `a cursor spread element yields "${representationKey(spread.element)}", which this array's "${representationKey(representation.element)}" element carrier cannot hold`);
|
|
314
|
+
}
|
|
315
|
+
lines.push(`gea::appendIteratorRange(*${name}, ${operandText(ctx, slot.value)});`);
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (spread.kind !== 'array-object') {
|
|
319
|
+
throw createCppEmitBlockedError(`conversion:${representationKey(spread)}->${representationKey(representation.element)}`, `a spread element's own carrier does not match this array's "${representationKey(representation.element)}" element carrier`);
|
|
320
|
+
}
|
|
321
|
+
if (representationKey(spread.element) !== representationKey(representation.element)) {
|
|
322
|
+
// Admitted by the lowering (`slot.element`, see `IrArrayElement`) and
|
|
323
|
+
// converted per element with the same recipes a single stored value
|
|
324
|
+
// uses; a pair no recipe covers refuses here, by name.
|
|
325
|
+
const converted = slot.element !== undefined && representationKey(slot.element) === representationKey(representation.element)
|
|
326
|
+
? alignedValueText(ctx, 'emit-arrays.ts:364', spread.element, representation.element, 'gea_element')
|
|
327
|
+
: null;
|
|
328
|
+
if (converted === null) {
|
|
329
|
+
throw createCppEmitBlockedError(`conversion:${representationKey(spread.element)}->${representationKey(representation.element)}`, `a spread element's own "${representationKey(spread.element)}" carrier has no per-element conversion into this array's "${representationKey(representation.element)}" element carrier`);
|
|
330
|
+
}
|
|
331
|
+
lines.push(`${name}->appendRangeConverted(*${operandText(ctx, slot.value)}, ${slot.from}, [&](const ${cppTypeOf(spread.element)}& gea_element) { return ${converted}; });`);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
lines.push(`${name}->appendRange(*${operandText(ctx, slot.value)}, ${slot.from});`);
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
if (slot.kind === 'gather') {
|
|
338
|
+
if (representation.element.kind !== 'dynamic' || slot.iterator.representation.kind !== 'dynamic') {
|
|
339
|
+
throw createCppEmitBlockedError(`runtime-helper:allocation:array-literal:${representation.element.kind}(dynamic-gather)`, 'a generic iterator gather requires a dynamic iterator record and an array with dynamic elements');
|
|
340
|
+
}
|
|
341
|
+
lines.push(`gea::runtime::iterator::appendGather(*${name}, ${operandText(ctx, slot.iterator)});`);
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
// An element whose own carrier is not the array's is reconciled on the way
|
|
345
|
+
// in, by the same rule an argument written into a parameter slot is --
|
|
346
|
+
// conversion where one is installed, and nothing at all where the target
|
|
347
|
+
// performs it implicitly (an `NSBox` pushed into an array of `NSView`).
|
|
348
|
+
//
|
|
349
|
+
// `const retained: unknown[] = []` is why this is not simply a store: the
|
|
350
|
+
// program itself declared the element `unknown`, so the array holds the box
|
|
351
|
+
// and a concrete value has to be boxed on the way in. Without it the push
|
|
352
|
+
// assigned an `NSObject` straight into a `gea::Value` slot, which is the
|
|
353
|
+
// one thing the box's storage-only design cannot do implicitly.
|
|
354
|
+
lines.push(`${name}->push(${alignedText(ctx, representation.element, slot.value, 'allocate-array-object')});`);
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
/**
|
|
358
|
+
* Which arrays a loop fills, and how many elements that loop will push.
|
|
359
|
+
*
|
|
360
|
+
* `const data: number[] = []` followed by `for (let i = 0; i < n; i++)
|
|
361
|
+
* data.push(i)` grows the vector from empty: about `log2(n)` reallocations,
|
|
362
|
+
* each copying everything written so far, so filling N elements moves ~2N of
|
|
363
|
+
* them. The hand-written baselines this is measured against all open with
|
|
364
|
+
* `reserve(n)` -- `array_read.cpp` is literally `data.reserve(it)` -- and the
|
|
365
|
+
* previous implementation measured the same fill loop at 97 ms without the
|
|
366
|
+
* hint and 38.7 ms with it, against a native 36.7 ms. It was the single
|
|
367
|
+
* largest gap on the array fixtures and it is not a code-generation
|
|
368
|
+
* difference; it is a capacity the program states and the emitter was
|
|
369
|
+
* throwing away.
|
|
370
|
+
*
|
|
371
|
+
* A capacity is a HINT and nothing else: reserving too much wastes memory
|
|
372
|
+
* until the array grows into it, reserving too little costs a reallocation,
|
|
373
|
+
* and reserving the wrong amount can never change what the program computes.
|
|
374
|
+
* That is what makes an approximate loop-trip count -- the test's bound, with
|
|
375
|
+
* no attempt to prove the step, the start, or the absence of a `break` -- a
|
|
376
|
+
* sound thing to read. `reserveHint` in the runtime header caps what it will
|
|
377
|
+
* act on, so a loop bound that turns out to be enormous costs nothing rather
|
|
378
|
+
* than a huge allocation.
|
|
379
|
+
*
|
|
380
|
+
* What must be exact is the two facts the hint is keyed by: the array is
|
|
381
|
+
* allocated OUTSIDE the loop (so the pushes accumulate into one array rather
|
|
382
|
+
* than into a fresh one per iteration), and the bound is computed outside it
|
|
383
|
+
* (so it is a single count rather than something that changes per iteration).
|
|
384
|
+
* Both are read off the dominator tree, and the bound is additionally required
|
|
385
|
+
* to be visible where the allocation renders -- an allocation that precedes
|
|
386
|
+
* its own bound cannot name it.
|
|
387
|
+
*/
|
|
388
|
+
export const collectCapacityHints = (ctx, prepass, body) => {
|
|
389
|
+
const graph = controlFlowGraphOf(body);
|
|
390
|
+
const dominance = dominatorTreeOf(body);
|
|
391
|
+
const sites = collectDefinitionSites(body);
|
|
392
|
+
const constants = new Map();
|
|
393
|
+
const numericConstants = new Map();
|
|
394
|
+
const computes = new Map();
|
|
395
|
+
const allocations = new Map();
|
|
396
|
+
// A value the IR reads out of a binding cell, and every write into one.
|
|
397
|
+
//
|
|
398
|
+
// Neither the array nor the bound arrives as a plain SSA value in ordinary
|
|
399
|
+
// source: `const data = []` stores into a cell and every `data.push(...)`
|
|
400
|
+
// reads it back, so the receiver at the push site is a fresh `binding-read`
|
|
401
|
+
// produced INSIDE the loop, and so is the `iterations` the test compares
|
|
402
|
+
// against. Judging either by its own definition site would answer "defined
|
|
403
|
+
// in the loop" for both and refuse every real fill loop. The question that
|
|
404
|
+
// actually matters is about the CELL: which array it holds, and whether the
|
|
405
|
+
// loop can change it.
|
|
406
|
+
const bindingReads = new Map();
|
|
407
|
+
const bindingWrites = new Map();
|
|
408
|
+
// Where each value is defined and where it is read -- what a fill loop needs
|
|
409
|
+
// to know that nothing it computes outlives the turns it is about to skip.
|
|
410
|
+
const definitionBlocks = new Map();
|
|
411
|
+
const literals = new Map();
|
|
412
|
+
const pushLookups = new Map();
|
|
413
|
+
const arrayPacks = new Map();
|
|
414
|
+
const useBlocks = new Map();
|
|
415
|
+
for (const blockId of body.blockOrder) {
|
|
416
|
+
const block = body.blocks.get(blockId);
|
|
417
|
+
if (!block)
|
|
418
|
+
continue;
|
|
419
|
+
for (const operation of [...block.operations, block.terminator]) {
|
|
420
|
+
for (const operand of operandsOfIrOperation(operation)) {
|
|
421
|
+
const where = useBlocks.get(operand.value) ?? new Set();
|
|
422
|
+
where.add(blockId);
|
|
423
|
+
useBlocks.set(operand.value, where);
|
|
424
|
+
}
|
|
425
|
+
const produced = resultOfIrOperation(operation);
|
|
426
|
+
if (produced !== null)
|
|
427
|
+
definitionBlocks.set(produced.id, blockId);
|
|
428
|
+
}
|
|
429
|
+
block.operations.forEach((operation, index) => {
|
|
430
|
+
if (operation.kind === 'constant') {
|
|
431
|
+
constants.set(operation.result.id, operation.text);
|
|
432
|
+
literals.set(operation.result.id, cppConstantLiteral(operation.text, operation.literal, operation.result.representation));
|
|
433
|
+
if (operation.literal === 'number')
|
|
434
|
+
numericConstants.set(operation.result.id, operation.text);
|
|
435
|
+
}
|
|
436
|
+
if (operation.kind === 'compute')
|
|
437
|
+
computes.set(operation.result.id, operation);
|
|
438
|
+
// `arr.push` is a `get` the emitter renders as nothing -- and one the
|
|
439
|
+
// hoister is free to lift OUT of the loop that calls it, since the
|
|
440
|
+
// receiver cell never changes. So the lookup is indexed body-wide and a
|
|
441
|
+
// fill loop recognizes its call by the callee, not by an adjacent `get`.
|
|
442
|
+
//
|
|
443
|
+
// This runs in `collectCapacityHints`'s own pre-pass, before the body's
|
|
444
|
+
// operations are emitted -- so `ctx.prototypeMethodReads`
|
|
445
|
+
// (`emit-carrier-members.ts`'s `arrayAccessText`, the census this same
|
|
446
|
+
// `array-object` receiver check otherwise shares) is not populated yet
|
|
447
|
+
// and cannot be read here. `arrayBulkAppendMethodName` is the part that
|
|
448
|
+
// CAN be shared this early: a module constant, not a per-body census, so
|
|
449
|
+
// this and `arrayMethods`' own `push` entry (`emit-prototype-array.ts`)
|
|
450
|
+
// name the one method by the same identifier rather than two
|
|
451
|
+
// independent `'push'` literals free to drift apart.
|
|
452
|
+
if (operation.kind === 'allocate-array-object')
|
|
453
|
+
arrayPacks.set(operation.result.id, operation);
|
|
454
|
+
if (operation.kind === 'get' && operation.receiver.representation.kind === 'array-object') {
|
|
455
|
+
if (constants.get(operation.key.value) === arrayBulkAppendMethodName)
|
|
456
|
+
pushLookups.set(operation.result.id, operation.receiver);
|
|
457
|
+
}
|
|
458
|
+
if (operation.kind === 'allocate-array-object')
|
|
459
|
+
allocations.set(operation.result.id, { block: blockId, position: index });
|
|
460
|
+
if (operation.kind === 'binding-read')
|
|
461
|
+
bindingReads.set(operation.result.id, operation.declaration);
|
|
462
|
+
if (operation.kind === 'binding-write') {
|
|
463
|
+
const written = bindingWrites.get(operation.declaration) ?? [];
|
|
464
|
+
written.push({ site: { block: blockId, position: index }, value: operation.value });
|
|
465
|
+
bindingWrites.set(operation.declaration, written);
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
const loops = naturalLoopsOf(graph, dominance);
|
|
470
|
+
/** The array this value names, when a single allocation is the only thing its cell ever holds. */
|
|
471
|
+
const allocationBehind = (value, loop) => {
|
|
472
|
+
if (allocations.has(value))
|
|
473
|
+
return value;
|
|
474
|
+
const declaration = bindingReads.get(value);
|
|
475
|
+
if (declaration === undefined)
|
|
476
|
+
return null;
|
|
477
|
+
const written = bindingWrites.get(declaration) ?? [];
|
|
478
|
+
// More than one write and the cell is not one array; a write inside the
|
|
479
|
+
// loop and it is a FRESH array each iteration, which a capacity taken from
|
|
480
|
+
// the whole loop would size wrongly.
|
|
481
|
+
if (written.length !== 1)
|
|
482
|
+
return null;
|
|
483
|
+
const only = written[0];
|
|
484
|
+
if (!only || loop.has(only.site.block))
|
|
485
|
+
return null;
|
|
486
|
+
return allocations.has(only.value.value) ? only.value.value : null;
|
|
487
|
+
};
|
|
488
|
+
/** How `bound` can be named where `at` renders, or `null` when it holds no single number the loop cannot change. */
|
|
489
|
+
const capacityAt = (bound, loop, at) => {
|
|
490
|
+
// A numeric literal bound -- `for (let i = 0; i < 256; i++)` -- stands on
|
|
491
|
+
// its own text and needs neither a cell nor a defined SSA name. Read
|
|
492
|
+
// straight through, because the constant's own operation is withheld by
|
|
493
|
+
// the deferral census and has no variable at the allocation site.
|
|
494
|
+
const literal = numericConstants.get(bound.value);
|
|
495
|
+
if (literal !== undefined)
|
|
496
|
+
return { kind: 'literal', text: literal };
|
|
497
|
+
const declaration = bindingReads.get(bound.value);
|
|
498
|
+
if (declaration === undefined) {
|
|
499
|
+
if (ctx.deferrable.has(bound.value))
|
|
500
|
+
return null;
|
|
501
|
+
const definitions = sites.get(bound.value) ?? [];
|
|
502
|
+
if (definitions.some((site) => loop.has(site.block)))
|
|
503
|
+
return null;
|
|
504
|
+
return definitions.every((site) => isVisible(site, at.block, at.position, dominance)) ? { kind: 'value', operand: bound } : null;
|
|
505
|
+
}
|
|
506
|
+
// Only an ordinary cell this body owns. A host constant, function,
|
|
507
|
+
// namespace or class object is not storage at all -- `emitBindingRead`
|
|
508
|
+
// renders each of those by the host's own spelling and defines no variable
|
|
509
|
+
// -- and a cell whose held carrier differs from the read one goes through
|
|
510
|
+
// a narrowing this has no business reproducing.
|
|
511
|
+
const placement = ctx.placements.get(declaration);
|
|
512
|
+
if (placement?.storage.kind !== 'local' && placement?.storage.kind !== 'region')
|
|
513
|
+
return null;
|
|
514
|
+
const held = placement.representation;
|
|
515
|
+
if (held === null || representationKey(held) !== representationKey(bound.representation))
|
|
516
|
+
return null;
|
|
517
|
+
// A cell that IS a formal needs no visibility proof: it renders as the
|
|
518
|
+
// formal's own name (`EmitContext.formalCells`), which precedes every
|
|
519
|
+
// statement in the frame. Its seeding write is a formality that may render
|
|
520
|
+
// anywhere, and requiring the ALLOCATION to follow it refused the bound of
|
|
521
|
+
// every fill loop whose count is a parameter -- which is every one of them
|
|
522
|
+
// in `array_read.ts`, `array_write.ts` and `prime_sieve.ts`, the fixtures
|
|
523
|
+
// the hint exists for.
|
|
524
|
+
if (ctx.formalCells.has(declaration))
|
|
525
|
+
return { kind: 'binding', declaration };
|
|
526
|
+
const written = bindingWrites.get(declaration) ?? [];
|
|
527
|
+
if (written.length === 0)
|
|
528
|
+
return null;
|
|
529
|
+
if (written.some((write) => loop.has(write.site.block)))
|
|
530
|
+
return null;
|
|
531
|
+
return written.every((write) => isVisible(write.site, at.block, at.position, dominance)) ? { kind: 'binding', declaration } : null;
|
|
532
|
+
};
|
|
533
|
+
for (const loop of loops) {
|
|
534
|
+
const header = body.blocks.get(loop.header);
|
|
535
|
+
if (header?.terminator.kind !== 'branch')
|
|
536
|
+
continue;
|
|
537
|
+
const test = computes.get(header.terminator.condition.value);
|
|
538
|
+
if (test?.form !== 'binary' || (test.operator !== '<' && test.operator !== '<='))
|
|
539
|
+
continue;
|
|
540
|
+
const bound = test.operands[1];
|
|
541
|
+
if (!bound || bound.representation.kind !== 'scalar' || bound.representation.domain !== 'number')
|
|
542
|
+
continue;
|
|
543
|
+
for (const blockId of loop.blocks) {
|
|
544
|
+
const block = body.blocks.get(blockId);
|
|
545
|
+
if (!block)
|
|
546
|
+
continue;
|
|
547
|
+
for (const operation of block.operations) {
|
|
548
|
+
if (operation.kind !== 'get')
|
|
549
|
+
continue;
|
|
550
|
+
// Shares `arrayBulkAppendMethodName` with the push-lookup above so this
|
|
551
|
+
// sibling names the one method by the same identifier rather than a
|
|
552
|
+
// second independent `'push'` literal free to drift apart from it.
|
|
553
|
+
if (constants.get(operation.key.value) !== arrayBulkAppendMethodName)
|
|
554
|
+
continue;
|
|
555
|
+
if (operation.receiver.representation.kind !== 'array-object')
|
|
556
|
+
continue;
|
|
557
|
+
const allocated = allocationBehind(operation.receiver.value, loop.blocks);
|
|
558
|
+
if (allocated === null || ctx.capacityHints.has(allocated))
|
|
559
|
+
continue;
|
|
560
|
+
const site = allocations.get(allocated);
|
|
561
|
+
if (!site)
|
|
562
|
+
continue;
|
|
563
|
+
const capacity = capacityAt(bound, loop.blocks, site);
|
|
564
|
+
if (capacity === null)
|
|
565
|
+
continue;
|
|
566
|
+
prepass.capacityHints.set(allocated, capacity);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
// ...and the same loop, when the value it pushes never changes, is not a
|
|
570
|
+
// loop at all: it is one bulk append. See `collectFillLoop`.
|
|
571
|
+
const tested = test.operands[0];
|
|
572
|
+
const counter = tested === undefined ? undefined : bindingReads.get(tested.value);
|
|
573
|
+
const exit = [header.terminator.whenTrue, header.terminator.whenFalse].find((next) => !loop.blocks.has(next));
|
|
574
|
+
if (counter === undefined || exit === undefined)
|
|
575
|
+
continue;
|
|
576
|
+
const fill = collectFillLoop(ctx, body, loop, {
|
|
577
|
+
counter,
|
|
578
|
+
exit,
|
|
579
|
+
bound,
|
|
580
|
+
inclusive: test.operator === '<=',
|
|
581
|
+
bindingReads,
|
|
582
|
+
bindingWrites,
|
|
583
|
+
computes,
|
|
584
|
+
constants,
|
|
585
|
+
useBlocks,
|
|
586
|
+
definitionBlocks,
|
|
587
|
+
literals,
|
|
588
|
+
pushLookups,
|
|
589
|
+
arrayPacks
|
|
590
|
+
});
|
|
591
|
+
if (fill !== null)
|
|
592
|
+
prepass.fillLoops.set(loop.header, fill);
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
/**
|
|
596
|
+
* A counted loop whose whole body is `array.push(<the same value>)`.
|
|
597
|
+
*
|
|
598
|
+
* `for (let i = 0; i <= LIMIT; i++) sieve.push(true)` is how JavaScript spells
|
|
599
|
+
* "an array of LIMIT+1 trues", and it gets what it asked for: ten million
|
|
600
|
+
* calls, each a capacity test, a store and a size bump. C++ spells it
|
|
601
|
+
* `std::vector<char>(LIMIT + 1, 1)` and gets a memset. Measured on
|
|
602
|
+
* `bench/comparison/fixtures/prime_sieve.ts`, whose sieve is exactly this:
|
|
603
|
+
* 45.5ms as the loop, 36.9ms as one append -- against 36.4ms for the
|
|
604
|
+
* hand-written C++, so the loop was the whole of that fixture's gap.
|
|
605
|
+
*
|
|
606
|
+
* Every condition is a way the rewrite could be OBSERVED:
|
|
607
|
+
* - the counter must advance by exactly one, exactly once, or the turn count
|
|
608
|
+
* is not `bound - counter`;
|
|
609
|
+
* - the receiver and the pushed value must be loop-invariant, or the elements
|
|
610
|
+
* appended are not all the same one;
|
|
611
|
+
* - the loop may hold no other operation with an effect, and nothing it
|
|
612
|
+
* defines may be read after it -- those are turns the append does not run.
|
|
613
|
+
* The `push` result is the exception: one append returns the same length the
|
|
614
|
+
* last turn would have.
|
|
615
|
+
*/
|
|
616
|
+
const collectFillLoop = (ctx, body, loop, facts) => {
|
|
617
|
+
if (!invariantInLoop(facts.bound, loop, facts))
|
|
618
|
+
return null;
|
|
619
|
+
let call = null;
|
|
620
|
+
const packed = [];
|
|
621
|
+
for (const blockId of loop.blocks) {
|
|
622
|
+
const block = body.blocks.get(blockId);
|
|
623
|
+
if (!block)
|
|
624
|
+
return null;
|
|
625
|
+
if (blockId !== loop.header && block.terminator.kind !== 'jump')
|
|
626
|
+
return null;
|
|
627
|
+
for (const operation of block.operations) {
|
|
628
|
+
const result = resultOfIrOperation(operation);
|
|
629
|
+
if (result !== null && [...(facts.useBlocks.get(result.id) ?? [])].some((where) => !loop.blocks.has(where)))
|
|
630
|
+
return null;
|
|
631
|
+
if (operation.kind === 'get') {
|
|
632
|
+
if (!facts.pushLookups.has(operation.result.id))
|
|
633
|
+
return null;
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
if (operation.kind === 'call') {
|
|
637
|
+
if (call !== null || !facts.pushLookups.has(operation.callee.value) || operation.arguments.length !== 1)
|
|
638
|
+
return null;
|
|
639
|
+
call = operation;
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
if (operation.kind === 'allocate-array-object') {
|
|
643
|
+
packed.push(operation.result.id);
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
if (operation.kind === 'binding-write' && operation.declaration !== facts.counter)
|
|
647
|
+
return null;
|
|
648
|
+
if (!fillInertKinds.has(operation.kind))
|
|
649
|
+
return null;
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
const receiver = call === null ? undefined : facts.pushLookups.get(call.callee.value);
|
|
653
|
+
const argument = call?.arguments[0];
|
|
654
|
+
if (!call || !argument || !receiver || !advancesByOne(loop, facts))
|
|
655
|
+
return null;
|
|
656
|
+
// `push` is variadic, so the IR hands it its arguments already packed into a
|
|
657
|
+
// fresh Array (`packRestArguments`) that the emitted `push` never builds. The
|
|
658
|
+
// element inside that pack is the value; the pack itself is the only object
|
|
659
|
+
// the loop is allowed to allocate, since anything else it built would be one
|
|
660
|
+
// object per turn and the append builds none.
|
|
661
|
+
const pack = facts.arrayPacks.get(argument.value);
|
|
662
|
+
const only = pack?.elements.length === 1 ? pack.elements[0] : undefined;
|
|
663
|
+
if (packed.length !== (pack === undefined ? 0 : 1) || (pack !== undefined && only?.kind !== 'element'))
|
|
664
|
+
return null;
|
|
665
|
+
const value = only?.kind === 'element' ? only.value : argument;
|
|
666
|
+
// A constant is the only value a fill may name that the loop itself defines:
|
|
667
|
+
// its text is the whole of it, so the header can restate it. Anything else
|
|
668
|
+
// has to be a name the header can already read.
|
|
669
|
+
const literal = facts.literals.get(value.value) ?? null;
|
|
670
|
+
if (literal === null && !invariantInLoop(value, loop, facts))
|
|
671
|
+
return null;
|
|
672
|
+
const cell = facts.bindingReads.get(receiver.value);
|
|
673
|
+
const array = cell === undefined ? null : denseCellName(ctx, cell);
|
|
674
|
+
const counter = denseCellName(ctx, facts.counter);
|
|
675
|
+
if (array === null || counter === null)
|
|
676
|
+
return null;
|
|
677
|
+
// The bound renders on BOTH sides of the append -- once for the count, once
|
|
678
|
+
// for the counter this leaves behind -- so a bound that reads the array being
|
|
679
|
+
// appended to would render two different numbers around a `bulkAppend` that
|
|
680
|
+
// changed the length between them. No terminating program can write that
|
|
681
|
+
// loop, since such a bound grows exactly as fast as the counter, and that is
|
|
682
|
+
// precisely why this went unstated: the rewrite rested on non-termination
|
|
683
|
+
// rather than on a check. `invariantInLoop` does not cover it either -- it
|
|
684
|
+
// asks whether the loop rebinds the CELL, and `data.push(v)` mutates the
|
|
685
|
+
// array without writing the name. Stated so the guard is a proof rather than
|
|
686
|
+
// a coincidence; `deferral-safety.ts` holds the other two sites where an
|
|
687
|
+
// emitter observes a withheld read somewhere its census never placed it.
|
|
688
|
+
if (cell !== undefined && (readsCell(ctx, facts.bound.value, cell) || readsCell(ctx, value.value, cell)))
|
|
689
|
+
return null;
|
|
690
|
+
// Both ends INTEGRAL, or the turn count is not `bound + 1 - counter`.
|
|
691
|
+
// `for (let i = 0; i < 3.5; i++)` runs four times, not three, and leaves `i`
|
|
692
|
+
// at 4 rather than at 3.5 -- the count rounds one way and the counter the
|
|
693
|
+
// other. Every counted push loop in practice counts in integers, and the
|
|
694
|
+
// integer census has already settled which ones do.
|
|
695
|
+
if (!ctx.integerBindings.has(facts.counter) || !ctx.integerValues.has(facts.bound.value))
|
|
696
|
+
return null;
|
|
697
|
+
if (receiver.representation.kind !== 'array-object')
|
|
698
|
+
return null;
|
|
699
|
+
return {
|
|
700
|
+
exit: facts.exit,
|
|
701
|
+
counter,
|
|
702
|
+
bound: facts.bound,
|
|
703
|
+
inclusive: facts.inclusive,
|
|
704
|
+
array,
|
|
705
|
+
value,
|
|
706
|
+
literal,
|
|
707
|
+
element: receiver.representation.element
|
|
708
|
+
};
|
|
709
|
+
};
|
|
710
|
+
/**
|
|
711
|
+
* One counted `push` loop, rendered at its header as a single bulk append.
|
|
712
|
+
*
|
|
713
|
+
* The loop's own blocks still render, unreachable, behind this `goto`: nothing
|
|
714
|
+
* reads what they define (`collectFillLoop` checked), and the C++ compiler
|
|
715
|
+
* drops them. Emitting them anyway keeps every label this body's other jumps
|
|
716
|
+
* may name, and keeps this a terminator substitution rather than a rewrite of
|
|
717
|
+
* the block list.
|
|
718
|
+
*/
|
|
719
|
+
/**
|
|
720
|
+
* The pushed element, spelled in the ARRAY's element type.
|
|
721
|
+
*
|
|
722
|
+
* A restated literal carries the constant's own text, and C++ reads `7` as an
|
|
723
|
+
* `int`. `bulkAppend` initializes its cell with a brace -- `Cell{value}` --
|
|
724
|
+
* where an `int` reaching a `double` element is a narrowing conversion, which
|
|
725
|
+
* is ill-formed rather than merely warned about: `for (let i = 0; i < n; i++)
|
|
726
|
+
* values.push(7)` into a `number[]` emitted a translation unit clang refuses.
|
|
727
|
+
* The ordinary push path never hits this because it renders its elements
|
|
728
|
+
* through the pack, which already aligned them.
|
|
729
|
+
*
|
|
730
|
+
* Cast only for a scalar element, which is the whole of the narrowing rule's
|
|
731
|
+
* reach here: a string literal reaching `std::string` and a `bool` reaching
|
|
732
|
+
* `bool` are not narrowing conversions, and a blanket `static_cast` to a
|
|
733
|
+
* handle or reference carrier would be a new way to be wrong.
|
|
734
|
+
*/
|
|
735
|
+
const appendedElementText = (ctx, fill) => {
|
|
736
|
+
if (fill.literal === null)
|
|
737
|
+
return operandText(ctx, fill.value);
|
|
738
|
+
return fill.element.kind === 'scalar' ? `static_cast<${cppTypeOf(fill.element)}>(${fill.literal})` : fill.literal;
|
|
739
|
+
};
|
|
740
|
+
export const emitFillLoop = (ctx, lines, fill, exitLabel) => {
|
|
741
|
+
const count = `gea_fill_${ctx.declarations.length}`;
|
|
742
|
+
ctx.declarations.push({ name: count, type: 'double' });
|
|
743
|
+
const reach = `static_cast<double>(${operandText(ctx, fill.bound)})${fill.inclusive ? ' + 1' : ''}`;
|
|
744
|
+
lines.push(`${count} = ${reach} - static_cast<double>(${fill.counter});`);
|
|
745
|
+
lines.push(`gea::runtime::array::bulkAppend(${fill.array}, ${appendedElementText(ctx, fill)}, ${count});`);
|
|
746
|
+
// The counter is left where the loop would have left it -- one past the last
|
|
747
|
+
// turn it ran -- and untouched when it ran none, which is the case the count
|
|
748
|
+
// is not positive in.
|
|
749
|
+
lines.push(`if (${count} > 0) ${fill.counter} = static_cast<long long>(${reach});`);
|
|
750
|
+
lines.push(`goto ${exitLabel};`);
|
|
751
|
+
};
|
|
752
|
+
/** The operation kinds a fill loop may hold besides its one `push`: reading the counter, advancing it, testing it. */
|
|
753
|
+
const fillInertKinds = new Set(['binding-read', 'binding-write', 'compute', 'constant']);
|
|
754
|
+
/**
|
|
755
|
+
* Whether the loop can change what this operand names.
|
|
756
|
+
*
|
|
757
|
+
* Through the CELL when the operand is a binding read, because that is how a
|
|
758
|
+
* fill loop names both its array and its bound: `const data = []` stores into a
|
|
759
|
+
* cell and every `data.push(...)` reads it back, so the receiver at the push is
|
|
760
|
+
* a fresh value defined INSIDE the loop and its own definition site answers the
|
|
761
|
+
* wrong question -- the same reasoning `collectCapacityHints` states above.
|
|
762
|
+
*/
|
|
763
|
+
const invariantInLoop = (operand, loop, facts) => {
|
|
764
|
+
const cell = facts.bindingReads.get(operand.value);
|
|
765
|
+
if (cell !== undefined)
|
|
766
|
+
return !(facts.bindingWrites.get(cell) ?? []).some((write) => loop.blocks.has(write.site.block));
|
|
767
|
+
const defined = facts.definitionBlocks.get(operand.value);
|
|
768
|
+
return defined === undefined || !loop.blocks.has(defined);
|
|
769
|
+
};
|
|
770
|
+
/** Exactly one advance of the counter inside the loop, by exactly one. */
|
|
771
|
+
const advancesByOne = (loop, facts) => {
|
|
772
|
+
const writes = (facts.bindingWrites.get(facts.counter) ?? []).filter((write) => loop.blocks.has(write.site.block));
|
|
773
|
+
if (writes.length !== 1)
|
|
774
|
+
return false;
|
|
775
|
+
const advance = writes[0] === undefined ? undefined : facts.computes.get(writes[0].value.value);
|
|
776
|
+
if (advance === undefined)
|
|
777
|
+
return false;
|
|
778
|
+
if (advance.form === 'update')
|
|
779
|
+
return advance.operator === '++';
|
|
780
|
+
if (advance.form !== 'binary' || advance.operator !== '+')
|
|
781
|
+
return false;
|
|
782
|
+
const [left, right] = advance.operands;
|
|
783
|
+
if (!left || !right)
|
|
784
|
+
return false;
|
|
785
|
+
const other = facts.bindingReads.get(left.value) === facts.counter ? right : left;
|
|
786
|
+
return facts.constants.get(other.value) === '1';
|
|
787
|
+
};
|
|
788
|
+
/** The plain C++ name a dense window may read its array or its counter through, or `null` when this body has no such name for the cell. */
|
|
789
|
+
const denseCellName = (ctx, declaration) => {
|
|
790
|
+
const placement = ctx.placements.get(declaration);
|
|
791
|
+
if (!placement)
|
|
792
|
+
return null;
|
|
793
|
+
if (placement.storage.kind === 'region')
|
|
794
|
+
return cppGlobalName(declaration);
|
|
795
|
+
if (placement.storage.kind !== 'local' || placement.storage.owner !== ctx.owner)
|
|
796
|
+
return null;
|
|
797
|
+
if (ctx.captures.isBoxed(declaration))
|
|
798
|
+
return null;
|
|
799
|
+
return bindingReference(ctx, declaration, 'a dense Array window').name;
|
|
800
|
+
};
|
|
801
|
+
/** One dense-window operand as a `long long`; the census already narrowed most of them, and the rest are ordinary `number` cells. */
|
|
802
|
+
const denseIntegerText = (ctx, operand) => ctx.integerValues.has(operand.value) ? operandText(ctx, operand) : `static_cast<${cppNarrowedIntegerType}>(${operandText(ctx, operand)})`;
|
|
803
|
+
/**
|
|
804
|
+
* Admits the dense windows this body can actually render, and records them on
|
|
805
|
+
* the context for the access sites to find.
|
|
806
|
+
*
|
|
807
|
+
* `ir/dense-loops.ts`'s `admittedDenseLoopPlanOf` owns every question that is
|
|
808
|
+
* about the PROGRAM: whether the integer census narrowed an index, the
|
|
809
|
+
* wrapped-window exemption from that test, and whether anything survives once
|
|
810
|
+
* an unnamed or un-narrowed window is dropped. The one thing left here is the
|
|
811
|
+
* one thing genuinely about this backend's own storage -- whether a cell has
|
|
812
|
+
* a plain C++ name in this body at all (`denseCellName`) -- handed down as the
|
|
813
|
+
* policy hook that function cannot answer for itself.
|
|
814
|
+
*
|
|
815
|
+
* Invariant 5 audit (invariant 5: no write during render): `denseAccesses`,
|
|
816
|
+
* `denseArrays`, `denseGroups` and `denseLengths` are written ONLY here, and
|
|
817
|
+
* `emitBody` (`emit.ts`) calls this once, after the integer census and before
|
|
818
|
+
* `sealFactFieldsForRender` -- so every one of these four collections is a
|
|
819
|
+
* settled FACT by the time the first operation renders, and none of them
|
|
820
|
+
* needs an entry in `emit-context.ts`'s `renderMutableEmitContextFields`.
|
|
821
|
+
* Contrast `denseIndices` (a NAMING table): its window is admitted here too,
|
|
822
|
+
* but its content -- a minted `gea_dense_index_<N>` local -- does not exist
|
|
823
|
+
* until a `%` compute actually renders (`emit.ts`'s `emitBinaryOperation`),
|
|
824
|
+
* which is why that one field, alone of this group, is on the whitelist.
|
|
825
|
+
*/
|
|
826
|
+
export const admitDenseWindows = (ctx, prepass, body) => {
|
|
827
|
+
const plan = denseLoopsOf(body);
|
|
828
|
+
if (plan.arrays.length === 0)
|
|
829
|
+
return;
|
|
830
|
+
const admitted = admittedDenseLoopPlanOf(plan, ctx.integerValues, (declaration) => denseCellName(ctx, declaration) !== null);
|
|
831
|
+
for (const [operation, access] of admitted.accesses)
|
|
832
|
+
prepass.denseAccesses.set(operation, access);
|
|
833
|
+
for (const array of admitted.arrays) {
|
|
834
|
+
prepass.denseArrays.push(array);
|
|
835
|
+
materializeDenseReference(prepass, array.reference);
|
|
836
|
+
}
|
|
837
|
+
for (const [value, ordinal] of admitted.lengths)
|
|
838
|
+
prepass.denseLengths.set(value, ordinal);
|
|
839
|
+
for (const [ordinal, group] of admitted.groups)
|
|
840
|
+
prepass.denseGroups.set(ordinal, group);
|
|
841
|
+
};
|
|
842
|
+
/** An array named at the preheader has to be a value that materialized, not one whose text is substituted at each use. */
|
|
843
|
+
const materializeDenseReference = (prepass, reference) => {
|
|
844
|
+
if (reference.kind === 'value')
|
|
845
|
+
prepass.deferrable.delete(reference.operand.value);
|
|
846
|
+
if (reference.kind === 'element')
|
|
847
|
+
materializeDenseReference(prepass, reference.holder);
|
|
848
|
+
};
|
|
849
|
+
/**
|
|
850
|
+
* The array a window indexes, unpacked at the preheader.
|
|
851
|
+
*
|
|
852
|
+
* A cell or a value is simply named. A ROW is loaded -- `grid[i]` -- and that
|
|
853
|
+
* load is itself an element access this has to prove is in range first, so the
|
|
854
|
+
* row comes back behind a null check rather than as a bare name: every later
|
|
855
|
+
* mention of it is guarded by `guard`, and the `&&` chain the conditions are
|
|
856
|
+
* joined into is what keeps the dereference from happening when it is not.
|
|
857
|
+
*/
|
|
858
|
+
const denseHolderOf = (ctx, lines, reference, array) => {
|
|
859
|
+
if (reference.kind === 'cell') {
|
|
860
|
+
const name = denseCellName(ctx, reference.declaration);
|
|
861
|
+
if (name === null)
|
|
862
|
+
return null;
|
|
863
|
+
const held = ctx.placements.get(reference.declaration)?.representation;
|
|
864
|
+
return { text: (held && narrowedLoadText(held, reference.representation, name)) ?? name, guard: [] };
|
|
865
|
+
}
|
|
866
|
+
if (reference.kind === 'value') {
|
|
867
|
+
const stored = operandText(ctx, reference.operand);
|
|
868
|
+
return { text: narrowedLoadText(reference.storage, reference.operand.representation, stored) ?? stored, guard: [] };
|
|
869
|
+
}
|
|
870
|
+
const holder = denseHolderOf(ctx, lines, reference.holder, array);
|
|
871
|
+
if (holder === null)
|
|
872
|
+
return null;
|
|
873
|
+
const key = denseIntegerText(ctx, reference.key);
|
|
874
|
+
const row = cppDenseRowName(array.ordinal);
|
|
875
|
+
ctx.declarations.push({ name: row, type: `gea::ArrayObject<${cppTypeOf(array.element)}>*` });
|
|
876
|
+
const reachable = [
|
|
877
|
+
...holder.guard,
|
|
878
|
+
`${holder.text}->holes.empty()`,
|
|
879
|
+
`(${key}) >= 0`,
|
|
880
|
+
`(${key}) < static_cast<${cppNarrowedIntegerType}>(${holder.text}->cells.size())`
|
|
881
|
+
];
|
|
882
|
+
lines.push(`${row} = (${reachable.join(' && ')}) ? ${holder.text}->elementAtIndex(${key}).get() : nullptr;`);
|
|
883
|
+
return { text: row, guard: [`${row} != nullptr`] };
|
|
884
|
+
};
|
|
885
|
+
/**
|
|
886
|
+
* The preheader statements one loop's dense windows need: an element pointer
|
|
887
|
+
* per array, and the one loop-invariant condition that makes indexing it sound.
|
|
888
|
+
*
|
|
889
|
+
* The condition is per LOOP rather than per array -- `ir/dense-loops.ts`
|
|
890
|
+
* explains why -- and it says three things about every window in the loop: the
|
|
891
|
+
* array holds no holes, the lowest index the loop can reach is not negative,
|
|
892
|
+
* and the highest is inside the storage the pointer names. `bound + step` is
|
|
893
|
+
* the highest: the loop's test admits `bound` (or `bound - 1`), and one turn of
|
|
894
|
+
* the body may advance the counter once more before it reads.
|
|
895
|
+
*/
|
|
896
|
+
export const emitDenseSetup = (ctx, lines, blockId) => {
|
|
897
|
+
const groups = [...ctx.denseGroups.values()].filter((group) => group.preheader === blockId);
|
|
898
|
+
if (groups.length === 0)
|
|
899
|
+
return;
|
|
900
|
+
// Which arrays the windows STORE into. A store's integrity guard -- is the
|
|
901
|
+
// array frozen -- is asked here, once, and folded into the flag, rather than
|
|
902
|
+
// at every store: `ir/dense-loops.ts` admits a window only when nothing in
|
|
903
|
+
// the loop can reach the array except the indexed accesses themselves, so
|
|
904
|
+
// nothing in the loop can freeze it either. Asked per store, the guard's
|
|
905
|
+
// cold half was a call the backend had to assume could write anything, which
|
|
906
|
+
// kept the counter load and the null test inside `matrix_multiply`'s inner
|
|
907
|
+
// loop and the loop itself scalar: 27.4 ms against 4.7 for the same loop
|
|
908
|
+
// hand-written.
|
|
909
|
+
const stored = new Set();
|
|
910
|
+
for (const [operation, access] of ctx.denseAccesses)
|
|
911
|
+
if (operation.kind !== 'get')
|
|
912
|
+
stored.add(access.array);
|
|
913
|
+
for (const group of groups) {
|
|
914
|
+
const said = group.parent === null ? [] : [cppDenseFlagName(group.parent)];
|
|
915
|
+
for (const array of ctx.denseArrays.filter((candidate) => candidate.group === group.ordinal)) {
|
|
916
|
+
const holder = denseHolderOf(ctx, lines, array.reference, array);
|
|
917
|
+
if (holder === null)
|
|
918
|
+
continue;
|
|
919
|
+
const pointer = cppDensePointerName(array.ordinal);
|
|
920
|
+
const cells = `${holder.text}->cells`;
|
|
921
|
+
const data = array.typed === null ? `${cells}.data()` : `${holder.text}->data()`;
|
|
922
|
+
const size = array.typed === null ? `${cells}.size()` : `${holder.text}->size()`;
|
|
923
|
+
const shape = array.typed === null ? [`${holder.text}->holes.empty()`] : [];
|
|
924
|
+
const writable = array.typed === null && stored.has(array.ordinal) && ctx.nativeIntegrityRestricted
|
|
925
|
+
? [`gea::nativeOwnFieldsWritable(${holder.text})`]
|
|
926
|
+
: [];
|
|
927
|
+
ctx.declarations.push({
|
|
928
|
+
name: pointer,
|
|
929
|
+
type: array.typed === null ? `gea::ArrayObject<${cppTypeOf(array.element)}>::Cell*` : `${cppScalarType(array.typed)}*`
|
|
930
|
+
});
|
|
931
|
+
lines.push(`${pointer} = ${holder.guard.length === 0 ? data : `(${holder.guard.join(' && ')}) ? ${data} : nullptr`};`);
|
|
932
|
+
// A wrapped window proves its indices from the array's own length, so
|
|
933
|
+
// the only thing left to say is that the length is one a remainder can
|
|
934
|
+
// land inside of, and that no hole sits in the way. See `DenseArray.wrapped`.
|
|
935
|
+
if (array.wrapped) {
|
|
936
|
+
// What the remainder's range has to fit inside. The array's own length
|
|
937
|
+
// bounds its indices by definition, so `size() > 0` is the whole of it
|
|
938
|
+
// -- it only rules out the `x % 0` that would be NaN. A CONSTANT
|
|
939
|
+
// modulus is bounded by itself instead, and nothing ties that number to
|
|
940
|
+
// this array, so the length has to cover it: `table[i % 16]` is a
|
|
941
|
+
// window exactly when the table holds sixteen elements or more.
|
|
942
|
+
const reach = array.modulus === null ? `${cells}.size() > 0` : `${cells}.size() >= ${array.modulus}`;
|
|
943
|
+
said.push(...holder.guard, `${holder.text}->holes.empty()`, reach, ...writable);
|
|
944
|
+
// The divisor of every index in this window, read here rather than on
|
|
945
|
+
// every turn. Nothing in the loop resizes the array -- that is what the
|
|
946
|
+
// window's own admission proved -- but only this hoist tells the
|
|
947
|
+
// backend so. See `DenseLoopPlan.lengths`.
|
|
948
|
+
if ([...ctx.denseLengths.values()].includes(array.ordinal)) {
|
|
949
|
+
const length = cppDenseLengthName(array.ordinal);
|
|
950
|
+
const divisor = cppDenseDivisorName(array.ordinal);
|
|
951
|
+
ctx.declarations.push({ name: length, type: 'double' }, { name: divisor, type: 'gea::Divisor' });
|
|
952
|
+
lines.push(`${length} = ${holder.text}->length();`, `${divisor} = gea::buildDivisor(${length});`);
|
|
953
|
+
}
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
const seed = denseCellName(ctx, array.counter) ?? '';
|
|
957
|
+
const step = array.step === null ? '1' : operandText(ctx, array.step);
|
|
958
|
+
// The holder's own guard comes FIRST, and the chain is short-circuiting:
|
|
959
|
+
// a row that could not be reached is a null pointer, and nothing after
|
|
960
|
+
// this may dereference it.
|
|
961
|
+
said.push(...holder.guard, ...shape, ...writable);
|
|
962
|
+
for (const offset of array.bases) {
|
|
963
|
+
const base = offset === null ? '0' : operandText(ctx, offset);
|
|
964
|
+
said.push(`gea::denseIndexWindow(${size}, ${seed}, ${base}, ${operandText(ctx, array.bound)}, ${step}, ${array.inclusive}, ${array.widened})`);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
const flag = cppDenseFlagName(group.ordinal);
|
|
968
|
+
ctx.declarations.push({ name: flag, type: 'bool' });
|
|
969
|
+
lines.push(`${flag} = ${said.length === 0 ? 'true' : said.join(' && ')};`);
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
/**
|
|
973
|
+
* A record whose fields are a closed, contiguous run of numeric keys --
|
|
974
|
+
* `0`, `1`, ... with no gap -- poured into the array it physically is.
|
|
975
|
+
*
|
|
976
|
+
* `semantics/normalize/structural.ts`'s `restParameterArrayElementAt` is what
|
|
977
|
+
* makes this pairing reachable at all: an unannotated `...rest` parameter's
|
|
978
|
+
* checker type is a tuple with optional trailing elements (an overloaded call
|
|
979
|
+
* shape or a signature's own optional tail), and that function collapses
|
|
980
|
+
* `rest` ITSELF to the array it is at runtime. But every other place the SAME
|
|
981
|
+
* open-arity tuple still surfaces -- the enclosing function's OWN callable
|
|
982
|
+
* ABI, still stated from the checker's tuple type -- keeps publishing the
|
|
983
|
+
* `record(0?:..., 1?:...)` view, and a call site that reads `rest[0]`/
|
|
984
|
+
* `rest[1]` needs a real conversion between the two, not a second producer
|
|
985
|
+
* disagreeing with the first about which one is true.
|
|
986
|
+
*
|
|
987
|
+
* Every field must convert into the array's ONE element carrier
|
|
988
|
+
* (`widenedStoreText`, asked rather than restated -- the identical function
|
|
989
|
+
* `registry.widening`'s dynamic-target branch calls, so a field that boxes
|
|
990
|
+
* into a `dynamic` element today boxes it the same way tomorrow). A record
|
|
991
|
+
* with accessors, zero fields, or a non-contiguous key set is refused: the
|
|
992
|
+
* first has no storage to read positionally, the second has no element type
|
|
993
|
+
* to publish, and the third is not this shape at all -- `tuple-destructuring.
|
|
994
|
+
* ts`'s `representationIsPositionalTupleRecord` asks the identical question
|
|
995
|
+
* for a destructuring read, kept as a separate, smaller local check here
|
|
996
|
+
* rather than imported, since `targets/cpp` does not depend on `preflight`.
|
|
997
|
+
*
|
|
998
|
+
* `field.required` (model.ts) is not consulted, for the same reason
|
|
999
|
+
* `records.ts`'s own field-layout renderer does not: an optional field's
|
|
1000
|
+
* struct member is unconditionally present today (no physical presence bit),
|
|
1001
|
+
* so there is no runtime state to ask -- every field converts and every
|
|
1002
|
+
* element pushes, an array of exactly `source.fields.length` elements. A
|
|
1003
|
+
* caller that omitted a trailing argument the checker allowed and a caller
|
|
1004
|
+
* that passed one explicitly are indistinguishable at this carrier, which is
|
|
1005
|
+
* the same fidelity gap `records.ts` already documents rather than a new one
|
|
1006
|
+
* introduced here.
|
|
1007
|
+
*/
|
|
1008
|
+
export const recordCastableToArray = (source, target) => {
|
|
1009
|
+
if (source.accessors.length > 0)
|
|
1010
|
+
return false;
|
|
1011
|
+
if (source.fields.length === 0)
|
|
1012
|
+
return false;
|
|
1013
|
+
if (target.ownership !== 'shared-refcount')
|
|
1014
|
+
return false;
|
|
1015
|
+
if (!source.fields.every((field, index) => field.key === String(index)))
|
|
1016
|
+
return false;
|
|
1017
|
+
// `widenedStoreText` returns null both when no widening exists AND when the
|
|
1018
|
+
// two representations already match (its own top-line sentinel: "nothing to
|
|
1019
|
+
// convert"). Treating both as failure rejected every field already carrying
|
|
1020
|
+
// the target's element representation -- the exact shape of the rest-array
|
|
1021
|
+
// case, where the first field is already `dynamic` and only the trailing
|
|
1022
|
+
// optional field needs boxing. A field counts as castable if it either has
|
|
1023
|
+
// a real widening text or is already representation-identical to the target.
|
|
1024
|
+
// A PROBE: "false" is legitimate, so lattice bottom is caught here, not
|
|
1025
|
+
// left to crash `widenedStoreText` deeper in (mongodb's `Filter`).
|
|
1026
|
+
if (containsUnresolved(target.element))
|
|
1027
|
+
return false;
|
|
1028
|
+
const targetKey = representationKey(target.element);
|
|
1029
|
+
const castable = (field) => representationKey(field.value) === targetKey || widenedStoreText(target.element, field.value, '') !== null;
|
|
1030
|
+
return source.fields.every((field) => !containsUnresolved(field.value) && castable(field));
|
|
1031
|
+
};
|
|
1032
|
+
export const recastedRecordToArrayText = (source, target, text) => {
|
|
1033
|
+
if (!recordCastableToArray(source, target))
|
|
1034
|
+
return null;
|
|
1035
|
+
const fieldArrow = source.ownership === 'shared-refcount' ? '->' : '.';
|
|
1036
|
+
const elementType = cppTypeOf(target.element);
|
|
1037
|
+
const pushes = source.fields
|
|
1038
|
+
.map((field) => {
|
|
1039
|
+
const raw = `gea_from${fieldArrow}${cppRecordFieldName(field.key)}`;
|
|
1040
|
+
// `widenedStoreText` returns `null` for "already the array's own element
|
|
1041
|
+
// carrier, nothing to convert" -- `raw` unchanged is that value, the
|
|
1042
|
+
// identical fallback its every other caller in this file uses.
|
|
1043
|
+
return `gea_arr->push(${widenedStoreText(target.element, field.value, raw) ?? raw});`;
|
|
1044
|
+
})
|
|
1045
|
+
.join(' ');
|
|
1046
|
+
return `[](const ${cppTypeOf(source)}& gea_from) { auto gea_arr = gea::makeRef<gea::ArrayObject<${elementType}>>(); ${pushes} return gea_arr; }(${text})`;
|
|
1047
|
+
};
|