@loopdive/js2 0.58.0 → 0.59.0

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.
@@ -8780,7 +8780,7 @@ function lookupAllowlistEntry(name) {
8780
8780
  }
8781
8781
  return void 0;
8782
8782
  }
8783
- function isHostImportAllowed(module, name) {
8783
+ function isHostImportAllowed(module, name, linkedNamespaces) {
8784
8784
  if (module === "env") {
8785
8785
  const entry = lookupAllowlistEntry(name);
8786
8786
  if (entry) return { allowed: true };
@@ -8789,6 +8789,9 @@ function isHostImportAllowed(module, name) {
8789
8789
  if (ALWAYS_ALLOWED_IMPORT_MODULES.has(module)) {
8790
8790
  return { allowed: true };
8791
8791
  }
8792
+ if (linkedNamespaces?.has(module)) {
8793
+ return { allowed: true };
8794
+ }
8792
8795
  return { allowed: false, reason: "non-env-host-module" };
8793
8796
  }
8794
8797
  function buildStrictHostImportError(module, name) {
@@ -8803,14 +8806,14 @@ function buildStrictHostImportError(module, name) {
8803
8806
  }
8804
8807
  return `Host import "${module}.${name}" requested under --no-host-imports / WASI strict mode, but the name is not on the dual-mode allowlist (src/codegen/host-import-allowlist.ts). Either add a Wasm-native fallback for this feature or, if you need a transitional host import, add an entry to HOST_IMPORT_ALLOWLIST citing the tracking issue and include "[allowlist-grow]" in your PR description.`;
8805
8808
  }
8806
- function scanForLeakedHostImports(imports) {
8809
+ function scanForLeakedHostImports(imports, linkedNamespaces) {
8807
8810
  const leaks = [];
8808
8811
  const seen = /* @__PURE__ */ new Set();
8809
8812
  for (const imp of imports) {
8810
8813
  const key = `${imp.module}\0${imp.name}`;
8811
8814
  if (seen.has(key)) continue;
8812
8815
  seen.add(key);
8813
- const decision = isHostImportAllowed(imp.module, imp.name);
8816
+ const decision = isHostImportAllowed(imp.module, imp.name, linkedNamespaces);
8814
8817
  if (!decision.allowed) {
8815
8818
  leaks.push({ module: imp.module, name: imp.name, reason: decision.reason });
8816
8819
  }
@@ -8825,21 +8828,16 @@ function buildLeakedHostImportError(leak) {
8825
8828
  return base + `The name is not on the dual-mode allowlist (src/codegen/host-import-allowlist.ts). Add a Wasm-native fallback for this feature, or — for a transitional host import — add an allowlist entry citing the tracking issue and include "[allowlist-grow]" in your PR description.`;
8826
8829
  }
8827
8830
  function funcTypeKey(params, results) {
8828
- let key = "";
8829
- for (let i = 0; i < params.length; i++) {
8830
- const p = params[i];
8831
- if (i > 0) key += ",";
8832
- key += p.kind;
8833
- if (p.kind === "ref" || p.kind === "ref_null") key += ":" + p.typeIdx;
8834
- }
8835
- key += "|";
8836
- for (let i = 0; i < results.length; i++) {
8837
- const r = results[i];
8838
- if (i > 0) key += ",";
8839
- key += r.kind;
8840
- if (r.kind === "ref" || r.kind === "ref_null") key += ":" + r.typeIdx;
8841
- }
8842
- return key;
8831
+ const part = (v) => {
8832
+ let s = v.kind;
8833
+ if (v.kind === "ref" || v.kind === "ref_null") s += ":" + v.typeIdx;
8834
+ else if (v.kind === "i32") {
8835
+ if (v.boolean) s += ":bool";
8836
+ else if (v.symbol) s += ":sym";
8837
+ }
8838
+ return s;
8839
+ };
8840
+ return params.map(part).join(",") + "|" + results.map(part).join(",");
8843
8841
  }
8844
8842
  function addFuncType(ctx, params, results, name) {
8845
8843
  const key = funcTypeKey(params, results);
@@ -9084,7 +9082,7 @@ function addImport(ctx, module, name, desc) {
9084
9082
  );
9085
9083
  }
9086
9084
  if (ctx.strictNoHostImports) {
9087
- const decision = isHostImportAllowed(module, name);
9085
+ const decision = isHostImportAllowed(module, name, ctx.linkedNamespaces);
9088
9086
  if (!decision.allowed) {
9089
9087
  const message = buildStrictHostImportError(module, name);
9090
9088
  ctx.errors.push({ message, line: 0, column: 0, severity: "degrade" });
@@ -9130,6 +9128,11 @@ function addStringConstantGlobal(ctx, value) {
9130
9128
  function nextModuleGlobalIdx(ctx) {
9131
9129
  return ctx.numImportGlobals + ctx.mod.globals.length;
9132
9130
  }
9131
+ function recordInModuleInitFlagRead(ctx) {
9132
+ const flagGet = { op: "global.get", index: 0 };
9133
+ (ctx.inModuleInitFlagReads ??= []).push(flagGet);
9134
+ return flagGet;
9135
+ }
9133
9136
  function localGlobalIdx(ctx, absIdx) {
9134
9137
  return absIdx - ctx.numImportGlobals;
9135
9138
  }
@@ -12515,6 +12518,15 @@ function flushLateImportShifts$1(ctx, fctx) {
12515
12518
  function isAnyValue$1(type, ctx) {
12516
12519
  return (type.kind === "ref" || type.kind === "ref_null") && type.typeIdx === ctx.anyValueTypeIdx && ctx.anyValueTypeIdx >= 0;
12517
12520
  }
12521
+ function isStrictBooleanReturnType(t) {
12522
+ return (t.flags & (ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral)) !== 0;
12523
+ }
12524
+ function brandExternMethodResult(_ctx, tsReturnType, valType) {
12525
+ if (!tsReturnType) return valType;
12526
+ if (valType.kind !== "i32" || valType.boolean) return valType;
12527
+ if (!isStrictBooleanReturnType(tsReturnType)) return valType;
12528
+ return { kind: "i32", boolean: true };
12529
+ }
12518
12530
  let _ensureAnyHelpers = () => {
12519
12531
  throw unregisteredDelegateError("ensureAnyHelpers");
12520
12532
  };
@@ -34159,6 +34171,12 @@ function emitToString(ctx, fctx, valType, tsType, hint) {
34159
34171
  return nativeStringType(ctx);
34160
34172
  }
34161
34173
  if (hint === "default") {
34174
+ const refTypeIdx = valType.typeIdx;
34175
+ const structName = refTypeIdx !== void 0 ? ctx.typeIdxToStructName.get(refTypeIdx) : void 0;
34176
+ if (structName !== void 0 && ctx.funcMap.get(`${structName}_toString`) !== void 0 && ctx.funcMap.get(`${structName}_valueOf`) === void 0 && ctx.funcMap.get(`${structName}_@@toPrimitive`) === void 0) {
34177
+ coerceType$1(ctx, fctx, valType, { kind: "externref" }, "string");
34178
+ return { kind: "externref" };
34179
+ }
34162
34180
  coerceType$1(ctx, fctx, valType, { kind: "externref" });
34163
34181
  const toStrIdx = ensureLateImport$1(
34164
34182
  ctx,
@@ -34594,377 +34612,6 @@ function isAllowedUse(checker, id, safe, fnDecls, fnParamSyms, nodeFsBindings) {
34594
34612
  }
34595
34613
  return false;
34596
34614
  }
34597
- const EMPTY_RESULT = {
34598
- sites: /* @__PURE__ */ new Map(),
34599
- approved: /* @__PURE__ */ new Set(),
34600
- approvedNames: /* @__PURE__ */ new Set(),
34601
- receiverStruct: /* @__PURE__ */ new Map(),
34602
- newThisOwnerNames: /* @__PURE__ */ new Set(),
34603
- ctorDeclByName: /* @__PURE__ */ new Map()
34604
- };
34605
- function fnctorDeclFromSymbol(sym) {
34606
- for (const decl of sym.getDeclarations() ?? []) {
34607
- if (ts.isFunctionDeclaration(decl) && decl.body) return decl;
34608
- if (ts.isFunctionExpression(decl) && decl.body) return decl;
34609
- if (ts.isVariableDeclaration(decl) && decl.initializer) {
34610
- let init = decl.initializer;
34611
- while (ts.isParenthesizedExpression(init)) init = init.expression;
34612
- if (ts.isFunctionExpression(init) && init.body) return init;
34613
- }
34614
- }
34615
- return void 0;
34616
- }
34617
- const RETURN_INFER_MAX_DEPTH = 6;
34618
- const GENERIC_METHOD_CALL = /* @__PURE__ */ new Set(["call", "apply", "bind"]);
34619
- function resolveFnctorSymbol(checker, calleeExpr) {
34620
- let e = calleeExpr;
34621
- while (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isNonNullExpression(e)) {
34622
- e = e.expression;
34623
- }
34624
- if (!ts.isIdentifier(e)) return void 0;
34625
- const sym = checker.getSymbolAtLocation(e);
34626
- const decls = sym?.getDeclarations();
34627
- if (!sym || !decls) return void 0;
34628
- for (const decl of decls) {
34629
- if (ts.isClassDeclaration(decl) || ts.isClassExpression(decl)) return void 0;
34630
- if (ts.isFunctionDeclaration(decl) && decl.body) return sym;
34631
- if (ts.isFunctionExpression(decl) && decl.body) return sym;
34632
- if (ts.isVariableDeclaration(decl) && decl.initializer) {
34633
- let init = decl.initializer;
34634
- while (ts.isParenthesizedExpression(init)) init = init.expression;
34635
- if (ts.isFunctionExpression(init) && init.body) return sym;
34636
- if (ts.isArrowFunction(init)) return void 0;
34637
- }
34638
- }
34639
- return void 0;
34640
- }
34641
- function collectFnctorOwnFields(ctorSym) {
34642
- const fields = /* @__PURE__ */ new Set();
34643
- const decls = ctorSym.getDeclarations() ?? [];
34644
- for (const decl of decls) {
34645
- let body;
34646
- if ((ts.isFunctionDeclaration(decl) || ts.isFunctionExpression(decl)) && decl.body) body = decl.body;
34647
- else if (ts.isVariableDeclaration(decl) && decl.initializer) {
34648
- let init = decl.initializer;
34649
- while (ts.isParenthesizedExpression(init)) init = init.expression;
34650
- if (ts.isFunctionExpression(init) && init.body) body = init.body;
34651
- }
34652
- if (!body) continue;
34653
- const walk = (node) => {
34654
- if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(node.left) && node.left.expression.kind === ts.SyntaxKind.ThisKeyword) {
34655
- fields.add(node.left.name.text);
34656
- }
34657
- forEachChild$1(node, walk);
34658
- };
34659
- walk(body);
34660
- }
34661
- return fields;
34662
- }
34663
- function classifyUse(checker, idNode, ownFields) {
34664
- const parent = idNode.parent;
34665
- if (ts.isPropertyAccessExpression(parent) && parent.expression === idNode) {
34666
- const name = parent.name.text;
34667
- if (ownFields.has(name)) return "typed";
34668
- return "dynamic";
34669
- }
34670
- if (ts.isElementAccessExpression(parent) && parent.expression === idNode) {
34671
- return "dynamic";
34672
- }
34673
- if (ts.isCallExpression(parent) && parent.arguments.length > 0 && parent.arguments[0] === idNode) {
34674
- const callee = parent.expression;
34675
- if (ts.isPropertyAccessExpression(callee) && GENERIC_METHOD_CALL.has(callee.name.text)) {
34676
- return "dynamic";
34677
- }
34678
- }
34679
- if (ts.isCallExpression(parent)) {
34680
- const argIdx = parent.arguments.indexOf(idNode);
34681
- if (argIdx >= 0) {
34682
- const sig = checker.getResolvedSignature(parent);
34683
- const paramSym = sig?.parameters[argIdx];
34684
- if (paramSym) {
34685
- const pType = checker.getTypeOfSymbolAtLocation(paramSym, idNode);
34686
- if (isAnyOrUnknown(pType)) return "dynamic";
34687
- }
34688
- return "neutral";
34689
- }
34690
- }
34691
- if (ts.isReturnStatement(parent)) {
34692
- return "neutral";
34693
- }
34694
- return "neutral";
34695
- }
34696
- function isAnyOrUnknown(t) {
34697
- return (t.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0;
34698
- }
34699
- function bindingOf(newExpr) {
34700
- const parent = newExpr.parent;
34701
- if (ts.isVariableDeclaration(parent) && parent.initializer === newExpr && ts.isIdentifier(parent.name)) {
34702
- return parent.name;
34703
- }
34704
- return void 0;
34705
- }
34706
- function unwrapExpr(e) {
34707
- let cur = e;
34708
- while (ts.isParenthesizedExpression(cur) || ts.isAsExpression(cur) || ts.isNonNullExpression(cur)) {
34709
- cur = cur.expression;
34710
- }
34711
- return cur;
34712
- }
34713
- function isFunctionLike$2(node) {
34714
- return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node);
34715
- }
34716
- function buildProtoMethodIndex(sourceFile) {
34717
- const idx = /* @__PURE__ */ new Map();
34718
- const walk = (n) => {
34719
- if (ts.isBinaryExpression(n) && n.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(n.left)) {
34720
- const rhs = unwrapExpr(n.right);
34721
- if (isFunctionLike$2(rhs)) {
34722
- const name = n.left.name.text;
34723
- const arr = idx.get(name);
34724
- if (arr) arr.push(rhs);
34725
- else idx.set(name, [rhs]);
34726
- }
34727
- }
34728
- forEachChild$1(n, walk);
34729
- };
34730
- walk(sourceFile);
34731
- return idx;
34732
- }
34733
- function resolveCalleeFunction(checker, callExpr, protoIndex) {
34734
- const callee = unwrapExpr(callExpr.expression);
34735
- let sym;
34736
- if (ts.isPropertyAccessExpression(callee)) {
34737
- sym = checker.getSymbolAtLocation(callee.name) ?? checker.getSymbolAtLocation(callee);
34738
- } else if (ts.isIdentifier(callee)) {
34739
- sym = checker.getSymbolAtLocation(callee);
34740
- }
34741
- if (sym) {
34742
- for (const decl of sym.getDeclarations() ?? []) {
34743
- const fn = functionFromDeclaration(decl);
34744
- if (fn?.body) return fn;
34745
- }
34746
- }
34747
- if (ts.isPropertyAccessExpression(callee)) {
34748
- const cands = protoIndex.get(callee.name.text);
34749
- if (cands && cands.length === 1 && cands[0].body) return cands[0];
34750
- }
34751
- return void 0;
34752
- }
34753
- function functionFromDeclaration(decl) {
34754
- if (isFunctionLike$2(decl)) return decl;
34755
- if (ts.isVariableDeclaration(decl) && decl.initializer) {
34756
- const init = unwrapExpr(decl.initializer);
34757
- if (isFunctionLike$2(init)) return init;
34758
- return void 0;
34759
- }
34760
- if (ts.isPropertyAssignment(decl)) {
34761
- const init = unwrapExpr(decl.initializer);
34762
- if (isFunctionLike$2(init)) return init;
34763
- return void 0;
34764
- }
34765
- if (ts.isMethodDeclaration(decl)) return decl;
34766
- if (ts.isPropertyAccessExpression(decl) || ts.isElementAccessExpression(decl)) {
34767
- const parent = decl.parent;
34768
- if (ts.isBinaryExpression(parent) && parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && parent.left === decl) {
34769
- const rhs = unwrapExpr(parent.right);
34770
- if (isFunctionLike$2(rhs)) return rhs;
34771
- }
34772
- }
34773
- return void 0;
34774
- }
34775
- function singleReturnExpr(fn) {
34776
- const body = fn.body;
34777
- if (!body) return void 0;
34778
- if (!ts.isBlock(body)) return body;
34779
- const returns = [];
34780
- const walk = (n) => {
34781
- if (ts.isReturnStatement(n)) {
34782
- if (n.expression) returns.push(n.expression);
34783
- return;
34784
- }
34785
- if (isFunctionLike$2(n)) return;
34786
- forEachChild$1(n, walk);
34787
- };
34788
- walk(body);
34789
- return returns.length === 1 ? returns[0] : void 0;
34790
- }
34791
- function inferReturnStruct(checker, fn, depth, memo, protoIndex) {
34792
- if (memo.has(fn)) return memo.get(fn);
34793
- if (depth <= 0) return void 0;
34794
- memo.set(fn, void 0);
34795
- const ret2 = singleReturnExpr(fn);
34796
- let result;
34797
- if (ret2) {
34798
- const r = unwrapExpr(ret2);
34799
- if (ts.isNewExpression(r)) {
34800
- const ctorSym = resolveFnctorSymbol(checker, r.expression);
34801
- if (ctorSym) result = `__fnctor_${ctorSym.name}`;
34802
- } else if (ts.isCallExpression(r)) {
34803
- const callee = resolveCalleeFunction(checker, r, protoIndex);
34804
- if (callee) result = inferReturnStruct(checker, callee, depth - 1, memo, protoIndex);
34805
- }
34806
- }
34807
- memo.set(fn, result);
34808
- return result;
34809
- }
34810
- function buildReceiverStructMap(checker, sourceFile, usesBySymbol) {
34811
- const map = /* @__PURE__ */ new Map();
34812
- const memo = /* @__PURE__ */ new Map();
34813
- const protoIndex = buildProtoMethodIndex(sourceFile);
34814
- const visit = (node) => {
34815
- if (ts.isVariableDeclaration(node) && node.initializer && ts.isIdentifier(node.name)) {
34816
- const init = unwrapExpr(node.initializer);
34817
- if (ts.isCallExpression(init)) {
34818
- const callee = resolveCalleeFunction(checker, init, protoIndex);
34819
- const struct = callee ? inferReturnStruct(checker, callee, RETURN_INFER_MAX_DEPTH, memo, protoIndex) : void 0;
34820
- if (struct) {
34821
- const bindSym = checker.getSymbolAtLocation(node.name);
34822
- const uses = bindSym ? usesBySymbol.get(bindSym) ?? [] : [];
34823
- for (const use of uses) {
34824
- if (use === node.name) continue;
34825
- map.set(use, struct);
34826
- }
34827
- }
34828
- }
34829
- }
34830
- forEachChild$1(node, visit);
34831
- };
34832
- visit(sourceFile);
34833
- return map;
34834
- }
34835
- function analyzeFnctorEscapeGate(checker, sourceFile) {
34836
- const sites = /* @__PURE__ */ new Map();
34837
- const approved = /* @__PURE__ */ new Set();
34838
- const approvedNames = /* @__PURE__ */ new Set();
34839
- const newSites = [];
34840
- const collect = (node) => {
34841
- if (ts.isNewExpression(node)) {
34842
- const ctorSym = resolveFnctorSymbol(checker, node.expression);
34843
- if (ctorSym) newSites.push({ newExpr: node, ctorSym });
34844
- }
34845
- forEachChild$1(node, collect);
34846
- };
34847
- collect(sourceFile);
34848
- if (newSites.length === 0) return EMPTY_RESULT;
34849
- const ctorDeclByName = /* @__PURE__ */ new Map();
34850
- for (const { ctorSym } of newSites) {
34851
- if (ctorDeclByName.has(ctorSym.name)) continue;
34852
- const decl = fnctorDeclFromSymbol(ctorSym);
34853
- if (decl) ctorDeclByName.set(ctorSym.name, decl);
34854
- }
34855
- const usesBySymbol = /* @__PURE__ */ new Map();
34856
- const indexUses = (node) => {
34857
- if (ts.isIdentifier(node)) {
34858
- const sym = checker.getSymbolAtLocation(node);
34859
- if (sym) {
34860
- const arr = usesBySymbol.get(sym);
34861
- if (arr) arr.push(node);
34862
- else usesBySymbol.set(sym, [node]);
34863
- }
34864
- }
34865
- forEachChild$1(node, indexUses);
34866
- };
34867
- indexUses(sourceFile);
34868
- for (const { newExpr, ctorSym } of newSites) {
34869
- const ownFields = collectFnctorOwnFields(ctorSym);
34870
- let sawDynamic = false;
34871
- let sawTyped = false;
34872
- const bind = bindingOf(newExpr);
34873
- if (bind) {
34874
- const bindSym = checker.getSymbolAtLocation(bind);
34875
- const uses = bindSym ? usesBySymbol.get(bindSym) ?? [] : [];
34876
- for (const use of uses) {
34877
- if (use === bind) continue;
34878
- const c = classifyUse(checker, use, ownFields);
34879
- if (c === "typed") sawTyped = true;
34880
- else if (c === "dynamic") sawDynamic = true;
34881
- }
34882
- } else {
34883
- let inner = newExpr;
34884
- let parent = inner.parent;
34885
- while (ts.isParenthesizedExpression(parent) || ts.isAsExpression(parent) || ts.isNonNullExpression(parent)) {
34886
- inner = parent;
34887
- parent = parent.parent;
34888
- }
34889
- if (ts.isPropertyAccessExpression(parent) && parent.expression === inner) {
34890
- if (ownFields.has(parent.name.text)) sawTyped = true;
34891
- else sawDynamic = true;
34892
- } else if (ts.isElementAccessExpression(parent) && parent.expression === inner) {
34893
- sawDynamic = true;
34894
- } else if (ts.isCallExpression(parent) && parent.arguments.length > 0 && parent.arguments[0] === inner && ts.isPropertyAccessExpression(parent.expression) && GENERIC_METHOD_CALL.has(parent.expression.name.text)) {
34895
- sawDynamic = true;
34896
- }
34897
- }
34898
- let cls;
34899
- if (sawTyped) cls = "keep-typed";
34900
- else if (sawDynamic) cls = "reconstruct";
34901
- else cls = "keep-static";
34902
- sites.set(newExpr, cls);
34903
- if (cls === "reconstruct") {
34904
- approved.add(newExpr);
34905
- approvedNames.add(ctorSym.name);
34906
- }
34907
- }
34908
- const receiverStruct = buildReceiverStructMap(checker, sourceFile, usesBySymbol);
34909
- if (process.env.JS2WASM_LOG_FNCTOR_GATE === "1" && (sites.size > 0 || receiverStruct.size > 0)) {
34910
- const counts = { reconstruct: 0, "keep-typed": 0, "keep-static": 0 };
34911
- for (const c of sites.values()) counts[c]++;
34912
- console.error(
34913
- `[#2660 fnctor-escape-gate] ${sites.size} new F() site(s): reconstruct=${counts.reconstruct} keep-typed=${counts["keep-typed"]} keep-static=${counts["keep-static"]}; receiverStruct flow-map entries=${receiverStruct.size}`
34914
- );
34915
- }
34916
- const newThisOwnerNames = /* @__PURE__ */ new Set();
34917
- return { sites, approved, approvedNames, receiverStruct, newThisOwnerNames, ctorDeclByName };
34918
- }
34919
- function deriveFnctorFields(ctx, funcDecl) {
34920
- const body = funcDecl.body;
34921
- if (!body) return [];
34922
- const fields = [];
34923
- function recordThisField(lhs, valueExpr) {
34924
- const fieldName = lhs.name.text;
34925
- if (fields.some((f) => f.name === fieldName)) return;
34926
- const lhsType = ctx.checker.getTypeAtLocation(lhs);
34927
- const rhsType = ctx.checker.getTypeAtLocation(valueExpr);
34928
- const lhsWasm = resolveWasmType(ctx, lhsType);
34929
- const rhsWasm = resolveWasmType(ctx, rhsType);
34930
- const fieldType = lhsWasm.kind === "externref" ? rhsWasm : lhsWasm;
34931
- fields.push({ name: fieldName, type: fieldType, mutable: true });
34932
- }
34933
- function collectAssignmentChain(expr) {
34934
- if (ts.isBinaryExpression(expr) && expr.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(expr.left) && expr.left.expression.kind === ts.SyntaxKind.ThisKeyword) {
34935
- recordThisField(expr.left, expr.right);
34936
- collectAssignmentChain(expr.right);
34937
- }
34938
- }
34939
- function collectThisAssignments(stmts) {
34940
- for (const stmt of stmts) {
34941
- if (ts.isExpressionStatement(stmt) && ts.isBinaryExpression(stmt.expression)) {
34942
- collectAssignmentChain(stmt.expression);
34943
- }
34944
- if (ts.isIfStatement(stmt)) {
34945
- if (ts.isBlock(stmt.thenStatement)) {
34946
- collectThisAssignments(stmt.thenStatement.statements);
34947
- }
34948
- if (stmt.elseStatement && ts.isBlock(stmt.elseStatement)) {
34949
- collectThisAssignments(stmt.elseStatement.statements);
34950
- }
34951
- }
34952
- if ((ts.isForStatement(stmt) || ts.isForInStatement(stmt) || ts.isForOfStatement(stmt) || ts.isWhileStatement(stmt) || ts.isDoStatement(stmt)) && ts.isBlock(stmt.statement)) {
34953
- collectThisAssignments(stmt.statement.statements);
34954
- }
34955
- }
34956
- }
34957
- collectThisAssignments(body.statements);
34958
- for (const field of fields) {
34959
- if (field.type.kind === "ref") {
34960
- field.type = {
34961
- kind: "ref_null",
34962
- typeIdx: field.type.typeIdx
34963
- };
34964
- }
34965
- }
34966
- return fields;
34967
- }
34968
34615
  function fnSymbolOf(checker, node) {
34969
34616
  if (ts.isFunctionDeclaration(node) && node.name) return checker.getSymbolAtLocation(node.name);
34970
34617
  if (ts.isMethodDeclaration(node) && ts.isIdentifier(node.name)) return checker.getSymbolAtLocation(node.name);
@@ -37361,7 +37008,7 @@ function applyIrTailCalls(ctx, body, funcTypeIdx) {
37361
37008
  };
37362
37009
  return convertBuffer(ctx, body, caller);
37363
37010
  }
37364
- function isFunctionLike$1(node) {
37011
+ function isFunctionLike$2(node) {
37365
37012
  return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node) || ts.isAccessor(node) || ts.isConstructorDeclaration(node);
37366
37013
  }
37367
37014
  function containsLinearU8Allocation(ctx, node) {
@@ -37370,7 +37017,7 @@ function containsLinearU8Allocation(ctx, node) {
37370
37017
  let found = false;
37371
37018
  const visit = (child) => {
37372
37019
  if (found) return;
37373
- if (child !== node && isFunctionLike$1(child)) return;
37020
+ if (child !== node && isFunctionLike$2(child)) return;
37374
37021
  if (ts.isVariableDeclaration(child) && ts.isIdentifier(child.name) && child.initializer && ts.isNewExpression(child.initializer) && ts.isIdentifier(child.initializer.expression) && child.initializer.expression.text === "Uint8Array" && isLinearU8RepresentableNew(ctx, child.initializer)) {
37375
37022
  const sym = ctx.checker.getSymbolAtLocation(child.name);
37376
37023
  if (sym && linear.safeBindings.has(sym)) {
@@ -51355,15 +51002,184 @@ function tryEmitLinearU8StdWrite(ctx, fctx, bufArg, writeSinkIdx, fd) {
51355
51002
  fctx.body.push({ op: "drop" });
51356
51003
  return true;
51357
51004
  }
51005
+ function dispatcherName$2(propName, strict) {
51006
+ return strict ? `__set_member_${propName}` : `__set_member_nonstrict_${propName}`;
51007
+ }
51008
+ function reserveMemberSetDispatch(ctx, propName, strict, fctx) {
51009
+ const name = dispatcherName$2(propName, strict);
51010
+ const existing = ctx.funcMap.get(name);
51011
+ if (existing !== void 0) return existing;
51012
+ const fallbackName = strict ? "__extern_set_strict" : "__extern_set";
51013
+ const setIdx = ensureLateImport$1(
51014
+ ctx,
51015
+ fallbackName,
51016
+ [{ kind: "externref" }, { kind: "externref" }, { kind: "externref" }],
51017
+ []
51018
+ );
51019
+ if (setIdx === void 0) return void 0;
51020
+ addStringConstantGlobal(ctx, propName);
51021
+ addUnionImportsViaRegistry(ctx);
51022
+ if (fctx) flushLateImportShifts$1(ctx, fctx);
51023
+ const typeIdx = addFuncType(ctx, [{ kind: "externref" }, { kind: "externref" }], [], "$member_set_dispatch_type");
51024
+ const funcIdx = ctx.numImportFuncs + ctx.mod.functions.length;
51025
+ ctx.mod.functions.push({
51026
+ name,
51027
+ typeIdx,
51028
+ locals: [],
51029
+ // Placeholder; filled by fillMemberSetDispatch. `unreachable` keeps the stub
51030
+ // valid (no results) if the fill is ever skipped (it never is — the fill
51031
+ // iterates the same name set this reserve populates).
51032
+ body: [{ op: "unreachable" }],
51033
+ exported: false
51034
+ });
51035
+ ctx.funcMap.set(name, funcIdx);
51036
+ (ctx.memberSetDispatchNames ??= /* @__PURE__ */ new Set()).add(`${propName}\0${strict ? "S" : "N"}`);
51037
+ return funcIdx;
51038
+ }
51039
+ function fillMemberSetDispatch(ctx) {
51040
+ const mod = ctx.mod;
51041
+ for (const key of ctx.memberSetDispatchNames ?? []) {
51042
+ const sep = key.lastIndexOf("\0");
51043
+ const propName = sep >= 0 ? key.slice(0, sep) : key;
51044
+ const strict = sep >= 0 ? key.slice(sep + 1) === "S" : true;
51045
+ const dispIdx = ctx.funcMap.get(dispatcherName$2(propName, strict));
51046
+ if (dispIdx === void 0) continue;
51047
+ const dispFn = mod.functions[dispIdx - ctx.numImportFuncs];
51048
+ if (!dispFn) continue;
51049
+ const candidates = findAlternateStructsForField(ctx, propName, -1).filter((c) => c.mutable);
51050
+ const fallbackIdx = ctx.funcMap.get(strict ? "__extern_set_strict" : "__extern_set");
51051
+ const fallback = fallbackIdx !== void 0 ? [
51052
+ { op: "local.get", index: 0 },
51053
+ // recv
51054
+ ...stringConstantExternrefInstrs(ctx, propName),
51055
+ { op: "local.get", index: 1 },
51056
+ // val
51057
+ { op: "call", funcIdx: fallbackIdx }
51058
+ ] : [];
51059
+ const buildSetDispatch = (idx) => {
51060
+ if (idx >= candidates.length) return fallback;
51061
+ const cand = candidates[idx];
51062
+ const coerce = coercionInstrs(ctx, { kind: "externref" }, cand.fieldType);
51063
+ const setFieldInstrs = [
51064
+ { op: "local.get", index: 2 },
51065
+ // __any
51066
+ { op: "ref.cast", typeIdx: cand.structTypeIdx },
51067
+ { op: "local.get", index: 1 },
51068
+ // val (externref)
51069
+ ...coerce,
51070
+ { op: "struct.set", typeIdx: cand.structTypeIdx, fieldIdx: cand.fieldIdx }
51071
+ ];
51072
+ return [
51073
+ { op: "local.get", index: 2 },
51074
+ // __any
51075
+ { op: "ref.test", typeIdx: cand.structTypeIdx },
51076
+ {
51077
+ op: "if",
51078
+ blockType: { kind: "empty" },
51079
+ then: setFieldInstrs,
51080
+ else: buildSetDispatch(idx + 1)
51081
+ }
51082
+ ];
51083
+ };
51084
+ dispFn.locals = [{ name: "__any", type: { kind: "anyref" } }];
51085
+ dispFn.body = [
51086
+ { op: "local.get", index: 0 },
51087
+ // recv (externref)
51088
+ { op: "any.convert_extern" },
51089
+ { op: "local.set", index: 2 },
51090
+ // __any
51091
+ ...buildSetDispatch(0)
51092
+ ];
51093
+ }
51094
+ }
51095
+ function dispatcherName$1(propName) {
51096
+ return `__get_member_${propName}`;
51097
+ }
51098
+ function reserveMemberGetDispatch(ctx, propName, fctx) {
51099
+ const name = dispatcherName$1(propName);
51100
+ const existing = ctx.funcMap.get(name);
51101
+ if (existing !== void 0) return existing;
51102
+ const getIdx = ensureLateImport$1(
51103
+ ctx,
51104
+ "__extern_get",
51105
+ [{ kind: "externref" }, { kind: "externref" }],
51106
+ [{ kind: "externref" }]
51107
+ );
51108
+ if (getIdx === void 0) return void 0;
51109
+ addStringConstantGlobal(ctx, propName);
51110
+ addUnionImportsViaRegistry(ctx);
51111
+ if (fctx) flushLateImportShifts$1(ctx, fctx);
51112
+ const typeIdx = addFuncType(ctx, [{ kind: "externref" }], [{ kind: "externref" }], "$member_get_dispatch_type");
51113
+ const funcIdx = ctx.numImportFuncs + ctx.mod.functions.length;
51114
+ ctx.mod.functions.push({
51115
+ name,
51116
+ typeIdx,
51117
+ locals: [],
51118
+ body: [{ op: "unreachable" }],
51119
+ exported: false
51120
+ });
51121
+ ctx.funcMap.set(name, funcIdx);
51122
+ (ctx.memberGetDispatchNames ??= /* @__PURE__ */ new Set()).add(propName);
51123
+ return funcIdx;
51124
+ }
51125
+ function fillMemberGetDispatch(ctx) {
51126
+ const mod = ctx.mod;
51127
+ const getIdx = ctx.funcMap.get("__extern_get");
51128
+ for (const propName of ctx.memberGetDispatchNames ?? []) {
51129
+ const dispIdx = ctx.funcMap.get(dispatcherName$1(propName));
51130
+ if (dispIdx === void 0) continue;
51131
+ const dispFn = mod.functions[dispIdx - ctx.numImportFuncs];
51132
+ if (!dispFn) continue;
51133
+ const candidates = findAlternateStructsForField(ctx, propName, -1);
51134
+ const fallback = getIdx !== void 0 ? [
51135
+ { op: "local.get", index: 0 },
51136
+ // recv
51137
+ ...stringConstantExternrefInstrs(ctx, propName),
51138
+ { op: "call", funcIdx: getIdx }
51139
+ ] : [{ op: "ref.null.extern" }];
51140
+ const buildGetDispatch = (idx) => {
51141
+ if (idx >= candidates.length) return fallback;
51142
+ const cand = candidates[idx];
51143
+ const box = coercionInstrs(ctx, cand.fieldType, { kind: "externref" });
51144
+ const readInstrs = [
51145
+ { op: "local.get", index: 1 },
51146
+ // __any
51147
+ { op: "ref.cast", typeIdx: cand.structTypeIdx },
51148
+ { op: "struct.get", typeIdx: cand.structTypeIdx, fieldIdx: cand.fieldIdx },
51149
+ ...box
51150
+ ];
51151
+ return [
51152
+ { op: "local.get", index: 1 },
51153
+ // __any
51154
+ { op: "ref.test", typeIdx: cand.structTypeIdx },
51155
+ {
51156
+ op: "if",
51157
+ blockType: { kind: "val", type: { kind: "externref" } },
51158
+ then: readInstrs,
51159
+ else: buildGetDispatch(idx + 1)
51160
+ }
51161
+ ];
51162
+ };
51163
+ dispFn.locals = [{ name: "__any", type: { kind: "anyref" } }];
51164
+ dispFn.body = [
51165
+ { op: "local.get", index: 0 },
51166
+ // recv (externref)
51167
+ { op: "any.convert_extern" },
51168
+ { op: "local.set", index: 1 },
51169
+ // __any
51170
+ ...buildGetDispatch(0)
51171
+ ];
51172
+ }
51173
+ }
51358
51174
  const VEC_SEARCH_METHODS = /* @__PURE__ */ new Set(["indexOf", "lastIndexOf", "includes"]);
51359
- function dispatcherName$2(methodName, arity) {
51175
+ function dispatcherName(methodName, arity) {
51360
51176
  return `__call_m_${methodName}_${arity}`;
51361
51177
  }
51362
51178
  function varargDispatcherName(methodName) {
51363
51179
  return `__call_m_${methodName}_vararg`;
51364
51180
  }
51365
51181
  function reserveClosedMethodDispatch(ctx, methodName, arity = 0) {
51366
- const name = dispatcherName$2(methodName, arity);
51182
+ const name = dispatcherName(methodName, arity);
51367
51183
  const existing = ctx.funcMap.get(name);
51368
51184
  if (existing !== void 0) return existing;
51369
51185
  ensureObjVecBuilders(ctx);
@@ -51488,7 +51304,7 @@ function fillClosedMethodDispatch(ctx) {
51488
51304
  const slash = key.lastIndexOf("/");
51489
51305
  const methodName = slash >= 0 ? key.slice(0, slash) : key;
51490
51306
  const arity = slash >= 0 ? Number.parseInt(key.slice(slash + 1), 10) || 0 : 0;
51491
- const dispIdx = ctx.funcMap.get(dispatcherName$2(methodName, arity));
51307
+ const dispIdx = ctx.funcMap.get(dispatcherName(methodName, arity));
51492
51308
  if (dispIdx === void 0) continue;
51493
51309
  const dispFn = mod.functions[dispIdx - ctx.numImportFuncs];
51494
51310
  if (!dispFn) continue;
@@ -51686,8 +51502,8 @@ function compileConsoleCall(ctx, fctx, expr, method) {
51686
51502
  }
51687
51503
  for (const arg of expr.arguments) {
51688
51504
  const argType = ctx.checker.getTypeAtLocation(arg);
51689
- compileExpression$1(ctx, fctx, arg);
51690
51505
  if (isStringType(argType)) {
51506
+ compileExpression$1(ctx, fctx, arg);
51691
51507
  if (ctx.nativeStrings && ctx.nativeStrTypeIdx >= 0) {
51692
51508
  ensureNativeStringExternBridge(ctx);
51693
51509
  flushLateImportShifts(ctx, fctx);
@@ -51705,16 +51521,25 @@ function compileConsoleCall(ctx, fctx, expr, method) {
51705
51521
  fctx.body.push({ op: "call", funcIdx });
51706
51522
  }
51707
51523
  } else if (isBooleanType(argType)) {
51524
+ compileExpression$1(ctx, fctx, arg, { kind: "i32" });
51708
51525
  const funcIdx = ctx.funcMap.get(`console_${method}_bool`);
51709
51526
  if (funcIdx !== void 0) {
51710
51527
  fctx.body.push({ op: "call", funcIdx });
51711
51528
  }
51712
51529
  } else if (isNumberType(argType)) {
51530
+ compileExpression$1(ctx, fctx, arg, { kind: "f64" });
51713
51531
  const funcIdx = ctx.funcMap.get(`console_${method}_number`);
51714
51532
  if (funcIdx !== void 0) {
51715
51533
  fctx.body.push({ op: "call", funcIdx });
51716
51534
  }
51717
51535
  } else {
51536
+ const res = compileExpression$1(ctx, fctx, arg);
51537
+ if (res && typeof res === "object" && "kind" in res) {
51538
+ const k = res.kind;
51539
+ if (k === "f64" || k === "i32" || k === "i64") {
51540
+ coerceType$2(ctx, fctx, res, { kind: "externref" });
51541
+ }
51542
+ }
51718
51543
  const funcIdx = ctx.funcMap.get(`console_${method}_externref`);
51719
51544
  if (funcIdx !== void 0) {
51720
51545
  fctx.body.push({ op: "call", funcIdx });
@@ -60965,7 +60790,8 @@ function compileObjectKeysOrValues(ctx, fctx, method, expr) {
60965
60790
  fctx.body.push({ op: "unreachable" });
60966
60791
  return { kind: "externref" };
60967
60792
  }
60968
- const structName = resolveStructName(ctx, argType);
60793
+ const argIsHostObjectVar = ts.isIdentifier(arg) && ctx.externrefAccessorVars.has(arg.text);
60794
+ const structName = argIsHostObjectVar ? void 0 : resolveStructName(ctx, argType);
60969
60795
  if (!structName) {
60970
60796
  const isAnyOrUnknown2 = (argType.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0;
60971
60797
  const tsProps = argType.getProperties?.();
@@ -64756,13 +64582,14 @@ function compileVariableStatement(ctx, fctx, stmt) {
64756
64582
  }
64757
64583
  return false;
64758
64584
  });
64759
- if (initIsAccessorLiteral) {
64585
+ const initIsHostSpreadLiteral = decl.initializer !== void 0 && ts.isObjectLiteralExpression(decl.initializer) && objectLiteralSpreadTakesHostPath(ctx, decl.initializer);
64586
+ if (initIsAccessorLiteral || initIsHostSpreadLiteral) {
64760
64587
  ctx.externrefAccessorVars.add(name);
64761
64588
  }
64762
64589
  const standaloneRegExpMatchArrayType = inferStandaloneRegExpMatchArrayType$1(ctx, decl.initializer);
64763
64590
  const subarraySubviewType = inferSubarraySubviewType(ctx, fctx, decl.initializer);
64764
64591
  const initIsProxy = decl.initializer !== void 0 && isProxyConstruction(decl.initializer) && ts.isIdentifier(decl.name) && !proxyResultEscapesToCall(decl, decl.name.text);
64765
- const wasmType = initIsAccessorLiteral ? { kind: "externref" } : isI32CoercedLocal ? { kind: "i32" } : isI32SpecializedArray ? { kind: "ref_null", typeIdx: getOrRegisterVecType(ctx, "i32", { kind: "i32" }) } : widenedTypeIdx !== void 0 ? { kind: "ref_null", typeIdx: widenedTypeIdx } : subarraySubviewType ?? inferredVecType ?? standaloneRegExpMatchArrayType ?? (decl.initializer && isStringMethodReturningHostArray(ctx, decl.initializer) ? { kind: "externref" } : decl.initializer && isPromiseHostCall(ctx, decl.initializer) ? { kind: "externref" } : (
64592
+ const wasmType = initIsAccessorLiteral || initIsHostSpreadLiteral ? { kind: "externref" } : isI32CoercedLocal ? { kind: "i32" } : isI32SpecializedArray ? { kind: "ref_null", typeIdx: getOrRegisterVecType(ctx, "i32", { kind: "i32" }) } : widenedTypeIdx !== void 0 ? { kind: "ref_null", typeIdx: widenedTypeIdx } : subarraySubviewType ?? inferredVecType ?? standaloneRegExpMatchArrayType ?? (decl.initializer && isStringMethodReturningHostArray(ctx, decl.initializer) ? { kind: "externref" } : decl.initializer && isPromiseHostCall(ctx, decl.initializer) ? { kind: "externref" } : (
64766
64593
  // (#2615) `new Proxy(target, handler)` returns a host/native
64767
64594
  // Proxy externref. The checker types it as the TARGET's
64768
64595
  // struct (ProxyConstructor returns T), so the default slot
@@ -78146,6 +77973,7 @@ function compileNewExpression(ctx, fctx, expr) {
78146
77973
  const type = ctx.checker.getTypeAtLocation(expr);
78147
77974
  const symbol = type.getSymbol();
78148
77975
  let className = symbol?.name;
77976
+ let thisFnctorSym;
78149
77977
  if (className && !ctx.classSet.has(className)) {
78150
77978
  const mapped = ctx.classExprNameMap.get(className);
78151
77979
  if (mapped) {
@@ -78163,6 +77991,13 @@ function compileNewExpression(ctx, fctx, expr) {
78163
77991
  }
78164
77992
  }
78165
77993
  }
77994
+ if ((!className || !ctx.classSet.has(className)) && expr.expression.kind === ts.SyntaxKind.ThisKeyword) {
77995
+ const owner = resolveEnclosingFnctorOwner(ctx.checker, expr);
77996
+ if (owner && ctx.fnctorEscapeGate?.approvedNames.has(owner.name)) {
77997
+ className = owner.name;
77998
+ thisFnctorSym = owner.sym;
77999
+ }
78000
+ }
78166
78001
  if (ctx.standalone && (isGlobalRegExpType(type) || ts.isIdentifier(expr.expression) && isGlobalRegExpIdentifier(ctx, expr.expression))) {
78167
78002
  return compileStandaloneRegExpConstructor(ctx, fctx, expr.arguments ?? [], expr);
78168
78003
  }
@@ -78186,7 +78021,7 @@ function compileNewExpression(ctx, fctx, expr) {
78186
78021
  return { kind: "ref", typeIdx: cachedFnCtor.structTypeIdx };
78187
78022
  }
78188
78023
  } else {
78189
- const decls = symbol?.getDeclarations();
78024
+ const decls = (symbol ?? thisFnctorSym)?.getDeclarations();
78190
78025
  if (decls) {
78191
78026
  for (const decl of decls) {
78192
78027
  if (ts.isFunctionDeclaration(decl) && decl.body) {
@@ -81199,8 +81034,41 @@ function isGlobalEvalIdentifier(ident, checker) {
81199
81034
  if (!decls || decls.length === 0) return true;
81200
81035
  return decls.every((d) => d.getSourceFile().isDeclarationFile);
81201
81036
  }
81037
+ function ensureFuncValueWrappersRegistered(ctx, sf) {
81038
+ const flag = ctx;
81039
+ if (flag.__funcValueWrappersRegistered) return;
81040
+ flag.__funcValueWrappersRegistered = true;
81041
+ const usedAsValue = /* @__PURE__ */ new Set();
81042
+ const visit = (node) => {
81043
+ if (ts.isIdentifier(node)) {
81044
+ const p = node.parent;
81045
+ const isCallee = p && ts.isCallExpression(p) && p.expression === node;
81046
+ const isNewCallee = p && ts.isNewExpression(p) && p.expression === node;
81047
+ const isOwnName = p && (ts.isFunctionDeclaration(p) || ts.isFunctionExpression(p)) && p.name === node;
81048
+ if (!isCallee && !isNewCallee && !isOwnName) {
81049
+ const sym = ctx.checker.getSymbolAtLocation(node);
81050
+ const decl = sym?.valueDeclaration;
81051
+ if (decl && ts.isFunctionDeclaration(decl) && decl.name) {
81052
+ usedAsValue.add(decl.name.text);
81053
+ }
81054
+ }
81055
+ }
81056
+ ts.forEachChild(node, visit);
81057
+ };
81058
+ visit(sf);
81059
+ for (const name of usedAsValue) {
81060
+ const funcIdx = ctx.funcMap.get(name);
81061
+ if (funcIdx === void 0) continue;
81062
+ const caps = ctx.nestedFuncCaptures.get(name);
81063
+ if (caps && caps.length > 0) continue;
81064
+ const sig = getFuncSignature(ctx, funcIdx);
81065
+ if (!sig) continue;
81066
+ getOrCreateFuncRefWrapperTypes(ctx, sig.params, sig.results);
81067
+ }
81068
+ }
81202
81069
  function tryEmitInlineDynamicCall(ctx, fctx, expr, isKnownVariable) {
81203
81070
  if (!isKnownVariable) return null;
81071
+ ensureFuncValueWrappersRegistered(ctx, expr.getSourceFile());
81204
81072
  const arity = expr.arguments.length;
81205
81073
  const supported = (t) => {
81206
81074
  if (t === null) return true;
@@ -85183,7 +85051,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
85183
85051
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
85184
85052
  if (isEffectivelyVoidReturn(ctx, retType, fullName)) return VOID_RESULT;
85185
85053
  if (wasmFuncReturnsVoid(ctx, finalStaticIdx)) return VOID_RESULT;
85186
- return getWasmFuncReturnType(ctx, finalStaticIdx) ?? resolveWasmType(ctx, retType);
85054
+ return brandExternMethodResult(
85055
+ ctx,
85056
+ retType,
85057
+ getWasmFuncReturnType(ctx, finalStaticIdx) ?? resolveWasmType(ctx, retType)
85058
+ );
85187
85059
  }
85188
85060
  return VOID_RESULT;
85189
85061
  }
@@ -85665,7 +85537,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
85665
85537
  const retType = ctx.checker.getReturnTypeOfSignature(sig2);
85666
85538
  if (isEffectivelyVoidReturn(ctx, retType, fullName)) return VOID_RESULT;
85667
85539
  if (wasmFuncReturnsVoid(ctx, finalMethodIdx2)) return VOID_RESULT;
85668
- return getWasmFuncReturnType(ctx, finalMethodIdx2) ?? resolveWasmType(ctx, retType);
85540
+ return brandExternMethodResult(
85541
+ ctx,
85542
+ retType,
85543
+ getWasmFuncReturnType(ctx, finalMethodIdx2) ?? resolveWasmType(ctx, retType)
85544
+ );
85669
85545
  }
85670
85546
  return VOID_RESULT;
85671
85547
  }
@@ -85699,7 +85575,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
85699
85575
  if (sig2) {
85700
85576
  const retType = ctx.checker.getReturnTypeOfSignature(sig2);
85701
85577
  if (!isEffectivelyVoidReturn(ctx, retType, fullName))
85702
- callReturnType = getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType);
85578
+ callReturnType = brandExternMethodResult(
85579
+ ctx,
85580
+ retType,
85581
+ getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType)
85582
+ );
85703
85583
  }
85704
85584
  const tmp = allocLocal(fctx, `__ng_recv_${fctx.locals.length}`, recvType);
85705
85585
  fctx.body.push({ op: "local.tee", index: tmp });
@@ -85791,7 +85671,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
85791
85671
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
85792
85672
  if (isEffectivelyVoidReturn(ctx, retType, fullName)) return VOID_RESULT;
85793
85673
  if (wasmFuncReturnsVoid(ctx, finalMethodIdx)) return VOID_RESULT;
85794
- return getWasmFuncReturnType(ctx, finalMethodIdx) ?? resolveWasmType(ctx, retType);
85674
+ return brandExternMethodResult(
85675
+ ctx,
85676
+ retType,
85677
+ getWasmFuncReturnType(ctx, finalMethodIdx) ?? resolveWasmType(ctx, retType)
85678
+ );
85795
85679
  }
85796
85680
  return VOID_RESULT;
85797
85681
  }
@@ -85816,7 +85700,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
85816
85700
  if (sig2) {
85817
85701
  const retType = ctx.checker.getReturnTypeOfSignature(sig2);
85818
85702
  if (!isEffectivelyVoidReturn(ctx, retType, fullName))
85819
- callReturnType = getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType);
85703
+ callReturnType = brandExternMethodResult(
85704
+ ctx,
85705
+ retType,
85706
+ getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType)
85707
+ );
85820
85708
  }
85821
85709
  const tmp = allocLocal(fctx, `__ng_srecv_${fctx.locals.length}`, recvType);
85822
85710
  fctx.body.push({ op: "local.tee", index: tmp });
@@ -85911,7 +85799,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
85911
85799
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
85912
85800
  if (isEffectivelyVoidReturn(ctx, retType, fullName)) return VOID_RESULT;
85913
85801
  if (wasmFuncReturnsVoid(ctx, finalStructMethodIdx)) return VOID_RESULT;
85914
- return getWasmFuncReturnType(ctx, finalStructMethodIdx) ?? resolveWasmType(ctx, retType);
85802
+ return brandExternMethodResult(
85803
+ ctx,
85804
+ retType,
85805
+ getWasmFuncReturnType(ctx, finalStructMethodIdx) ?? resolveWasmType(ctx, retType)
85806
+ );
85915
85807
  }
85916
85808
  return VOID_RESULT;
85917
85809
  }
@@ -86708,6 +86600,89 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
86708
86600
  fctx.body.push({ op: "call", funcIdx: dispatchResolvedIdx });
86709
86601
  return { kind: "externref" };
86710
86602
  }
86603
+ if (!ctx.standalone && (methodName === "push" || methodName === "pop") && ctx.vecTypeMap.size > 0) {
86604
+ const mcIdx = ensureLateImport(
86605
+ ctx,
86606
+ "__extern_method_call",
86607
+ [{ kind: "externref" }, { kind: "externref" }, { kind: "externref" }],
86608
+ [{ kind: "externref" }]
86609
+ );
86610
+ const arrNewIdx = ensureLateImport(ctx, "__js_array_new", [], [{ kind: "externref" }]);
86611
+ const arrPushIdx = ensureLateImport(
86612
+ ctx,
86613
+ "__js_array_push",
86614
+ [{ kind: "externref" }, { kind: "externref" }],
86615
+ []
86616
+ );
86617
+ const boxNumIdx = methodName === "push" ? ensureLateImport(ctx, "__box_number", [{ kind: "f64" }], [{ kind: "externref" }]) : void 0;
86618
+ addStringConstantGlobal(ctx, methodName);
86619
+ flushLateImportShifts(ctx, fctx);
86620
+ const vecOpIdx = reserveVecMethodHelper(ctx, methodName === "push" ? "push" : "pop");
86621
+ if (vecOpIdx !== void 0 && mcIdx !== void 0 && arrNewIdx !== void 0 && arrPushIdx !== void 0 && (methodName === "pop" || boxNumIdx !== void 0)) {
86622
+ const recvT = compileExpression$1(ctx, fctx, propAccess.expression, { kind: "externref" });
86623
+ if (recvT && recvT.kind !== "externref") coerceType$2(ctx, fctx, recvT, { kind: "externref" });
86624
+ else if (!recvT) fctx.body.push({ op: "ref.null.extern" });
86625
+ const recvLocal = allocLocal(fctx, `__nvm_recv_${fctx.locals.length}`, { kind: "externref" });
86626
+ fctx.body.push({ op: "local.set", index: recvLocal });
86627
+ let argLocal;
86628
+ if (methodName === "push") {
86629
+ const a = expr.arguments[0];
86630
+ if (a) {
86631
+ const at = compileExpression$1(ctx, fctx, a, { kind: "externref" });
86632
+ if (at && at.kind !== "externref") coerceType$2(ctx, fctx, at, { kind: "externref" });
86633
+ else if (!at) fctx.body.push({ op: "ref.null.extern" });
86634
+ } else {
86635
+ fctx.body.push({ op: "ref.null.extern" });
86636
+ }
86637
+ argLocal = allocLocal(fctx, `__nvm_arg_${fctx.locals.length}`, { kind: "externref" });
86638
+ fctx.body.push({ op: "local.set", index: argLocal });
86639
+ }
86640
+ const anyTmp = allocLocal(fctx, `__nvm_any_${fctx.locals.length}`, { kind: "anyref" });
86641
+ fctx.body.push({ op: "local.get", index: recvLocal });
86642
+ fctx.body.push({ op: "any.convert_extern" });
86643
+ fctx.body.push({ op: "local.set", index: anyTmp });
86644
+ let emitted = false;
86645
+ for (const vi of new Set(ctx.vecTypeMap.values())) {
86646
+ fctx.body.push({ op: "local.get", index: anyTmp });
86647
+ fctx.body.push({ op: "ref.test", typeIdx: vi });
86648
+ if (emitted) fctx.body.push({ op: "i32.or" });
86649
+ emitted = true;
86650
+ }
86651
+ const thenStart = fctx.body.length;
86652
+ if (methodName === "push") {
86653
+ fctx.body.push({ op: "local.get", index: recvLocal });
86654
+ fctx.body.push({ op: "local.get", index: argLocal });
86655
+ fctx.body.push({ op: "call", funcIdx: vecOpIdx });
86656
+ fctx.body.push({ op: "f64.convert_i32_s" });
86657
+ fctx.body.push({ op: "call", funcIdx: boxNumIdx });
86658
+ } else {
86659
+ fctx.body.push({ op: "local.get", index: recvLocal });
86660
+ fctx.body.push({ op: "call", funcIdx: vecOpIdx });
86661
+ }
86662
+ const thenInstrs = fctx.body.splice(thenStart);
86663
+ const elseStart = fctx.body.length;
86664
+ fctx.body.push({ op: "call", funcIdx: arrNewIdx });
86665
+ const argsLocal = allocLocal(fctx, `__nvm_args_${fctx.locals.length}`, { kind: "externref" });
86666
+ fctx.body.push({ op: "local.set", index: argsLocal });
86667
+ if (methodName === "push") {
86668
+ fctx.body.push({ op: "local.get", index: argsLocal });
86669
+ fctx.body.push({ op: "local.get", index: argLocal });
86670
+ fctx.body.push({ op: "call", funcIdx: arrPushIdx });
86671
+ }
86672
+ fctx.body.push({ op: "local.get", index: recvLocal });
86673
+ fctx.body.push(...stringConstantExternrefInstrs(ctx, methodName));
86674
+ fctx.body.push({ op: "local.get", index: argsLocal });
86675
+ fctx.body.push({ op: "call", funcIdx: mcIdx });
86676
+ const elseInstrs = fctx.body.splice(elseStart);
86677
+ fctx.body.push({
86678
+ op: "if",
86679
+ blockType: { kind: "val", type: { kind: "externref" } },
86680
+ then: thenInstrs,
86681
+ else: elseInstrs
86682
+ });
86683
+ return { kind: "externref" };
86684
+ }
86685
+ }
86711
86686
  {
86712
86687
  let arrNewIdx;
86713
86688
  let arrPushIdx;
@@ -87842,7 +87817,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
87842
87817
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
87843
87818
  if (isEffectivelyVoidReturn(ctx, retType, funcName)) return VOID_RESULT;
87844
87819
  if (wasmFuncReturnsVoid(ctx, finalFuncIdx)) return VOID_RESULT;
87845
- return getWasmFuncReturnType(ctx, finalFuncIdx) ?? resolveWasmType(ctx, retType);
87820
+ return brandExternMethodResult(
87821
+ ctx,
87822
+ retType,
87823
+ getWasmFuncReturnType(ctx, finalFuncIdx) ?? resolveWasmType(ctx, retType)
87824
+ );
87846
87825
  }
87847
87826
  return getWasmFuncReturnType(ctx, finalFuncIdx) ?? { kind: "f64" };
87848
87827
  }
@@ -88291,7 +88270,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
88291
88270
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
88292
88271
  if (isEffectivelyVoidReturn(ctx, retType, fullName)) return VOID_RESULT;
88293
88272
  if (wasmFuncReturnsVoid(ctx, funcIdx)) return VOID_RESULT;
88294
- return getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType);
88273
+ return brandExternMethodResult(
88274
+ ctx,
88275
+ retType,
88276
+ getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType)
88277
+ );
88295
88278
  }
88296
88279
  return VOID_RESULT;
88297
88280
  }
@@ -88309,7 +88292,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
88309
88292
  if (sig2) {
88310
88293
  const retType = ctx.checker.getReturnTypeOfSignature(sig2);
88311
88294
  if (!isEffectivelyVoidReturn(ctx, retType, fullName))
88312
- callReturnType = getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType);
88295
+ callReturnType = brandExternMethodResult(
88296
+ ctx,
88297
+ retType,
88298
+ getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType)
88299
+ );
88313
88300
  }
88314
88301
  const tmp = allocLocal(fctx, `__ng_ea_recv_${fctx.locals.length}`, recvType);
88315
88302
  fctx.body.push({ op: "local.tee", index: tmp });
@@ -88382,7 +88369,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
88382
88369
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
88383
88370
  if (isEffectivelyVoidReturn(ctx, retType, fullName)) return VOID_RESULT;
88384
88371
  if (wasmFuncReturnsVoid(ctx, funcIdx)) return VOID_RESULT;
88385
- return getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType);
88372
+ return brandExternMethodResult(
88373
+ ctx,
88374
+ retType,
88375
+ getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType)
88376
+ );
88386
88377
  }
88387
88378
  return VOID_RESULT;
88388
88379
  }
@@ -88416,7 +88407,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
88416
88407
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
88417
88408
  if (isEffectivelyVoidReturn(ctx, retType, fullName)) return VOID_RESULT;
88418
88409
  if (wasmFuncReturnsVoid(ctx, funcIdx)) return VOID_RESULT;
88419
- return getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType);
88410
+ return brandExternMethodResult(
88411
+ ctx,
88412
+ retType,
88413
+ getWasmFuncReturnType(ctx, funcIdx) ?? resolveWasmType(ctx, retType)
88414
+ );
88420
88415
  }
88421
88416
  return VOID_RESULT;
88422
88417
  }
@@ -88646,7 +88641,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
88646
88641
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
88647
88642
  if (isEffectivelyVoidReturn(ctx, retType, funcName)) return VOID_RESULT;
88648
88643
  if (wasmFuncReturnsVoid(ctx, finalFuncIdx)) return VOID_RESULT;
88649
- return getWasmFuncReturnType(ctx, finalFuncIdx) ?? resolveWasmType(ctx, retType);
88644
+ return brandExternMethodResult(
88645
+ ctx,
88646
+ retType,
88647
+ getWasmFuncReturnType(ctx, finalFuncIdx) ?? resolveWasmType(ctx, retType)
88648
+ );
88650
88649
  }
88651
88650
  return getWasmFuncReturnType(ctx, finalFuncIdx) ?? { kind: "f64" };
88652
88651
  }
@@ -88693,7 +88692,11 @@ function compileCallExpression(ctx, fctx, expr, expectedType) {
88693
88692
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
88694
88693
  if (isEffectivelyVoidReturn(ctx, retType, fullName)) return VOID_RESULT;
88695
88694
  if (wasmFuncReturnsVoid(ctx, finalCallIdx)) return VOID_RESULT;
88696
- return getWasmFuncReturnType(ctx, finalCallIdx) ?? resolveWasmType(ctx, retType);
88695
+ return brandExternMethodResult(
88696
+ ctx,
88697
+ retType,
88698
+ getWasmFuncReturnType(ctx, finalCallIdx) ?? resolveWasmType(ctx, retType)
88699
+ );
88697
88700
  }
88698
88701
  return VOID_RESULT;
88699
88702
  }
@@ -89043,7 +89046,11 @@ function compileConditionalCallee(ctx, fctx, expr, condExpr) {
89043
89046
  const retType = ctx.checker.getReturnTypeOfSignature(branchSigs[0]);
89044
89047
  if (isEffectivelyVoidReturn(ctx, retType, funcName)) return VOID_RESULT;
89045
89048
  if (wasmFuncReturnsVoid(ctx, finalFuncIdx)) return VOID_RESULT;
89046
- return getWasmFuncReturnType(ctx, finalFuncIdx) ?? resolveWasmType(ctx, retType);
89049
+ return brandExternMethodResult(
89050
+ ctx,
89051
+ retType,
89052
+ getWasmFuncReturnType(ctx, finalFuncIdx) ?? resolveWasmType(ctx, retType)
89053
+ );
89047
89054
  }
89048
89055
  return callRetType ?? getWasmFuncReturnType(ctx, finalFuncIdx) ?? { kind: "f64" };
89049
89056
  }
@@ -91197,6 +91204,50 @@ function emitExternrefBackedOwnFieldWrite(ctx, fctx, target, value, fieldName) {
91197
91204
  fctx.body.push({ op: "local.get", index: tmpBoxed });
91198
91205
  return { kind: "externref" };
91199
91206
  }
91207
+ function tryEmitPinnedStructMemberSet(ctx, fctx, target, value) {
91208
+ if (ts.isPrivateIdentifier(target.name)) return void 0;
91209
+ const propName = target.name.text;
91210
+ if (propName === "length" || propName === "constructor" || propName === "__proto__" || propName === "prototype" || propName === "name") {
91211
+ return void 0;
91212
+ }
91213
+ const accessType = ctx.checker.getTypeAtLocation(target);
91214
+ if (accessType.getCallSignatures && accessType.getCallSignatures().length > 0) return void 0;
91215
+ if (reserveMemberSetDispatch(
91216
+ ctx,
91217
+ propName,
91218
+ /*strict*/
91219
+ true,
91220
+ fctx
91221
+ ) === void 0) return void 0;
91222
+ const objResult = compileExpression$1(ctx, fctx, target.expression);
91223
+ if (objResult && objResult.kind !== "externref") {
91224
+ coerceType$2(ctx, fctx, objResult, { kind: "externref" });
91225
+ } else if (!objResult) {
91226
+ fctx.body.push({ op: "ref.null.extern" });
91227
+ }
91228
+ const objLocal = allocLocal(fctx, `__pset_obj_${fctx.locals.length}`, { kind: "externref" });
91229
+ fctx.body.push({ op: "local.set", index: objLocal });
91230
+ const valResult = compileExpression$1(ctx, fctx, value);
91231
+ if (valResult && valResult.kind !== "externref") {
91232
+ coerceType$2(ctx, fctx, valResult, { kind: "externref" });
91233
+ } else if (!valResult) {
91234
+ fctx.body.push({ op: "ref.null.extern" });
91235
+ }
91236
+ const valLocal = allocLocal(fctx, `__pset_val_${fctx.locals.length}`, { kind: "externref" });
91237
+ fctx.body.push({ op: "local.set", index: valLocal });
91238
+ const dispatched = emitAlternateStructSetDispatch(
91239
+ ctx,
91240
+ fctx,
91241
+ objLocal,
91242
+ valLocal,
91243
+ propName,
91244
+ /*strict*/
91245
+ true
91246
+ );
91247
+ if (!dispatched) return void 0;
91248
+ fctx.body.push({ op: "local.get", index: valLocal });
91249
+ return { kind: "externref" };
91250
+ }
91200
91251
  function compilePropertyAssignment(ctx, fctx, target, value) {
91201
91252
  const objType = ctx.checker.getTypeAtLocation(target.expression);
91202
91253
  {
@@ -91377,6 +91428,14 @@ function compilePropertyAssignment(ctx, fctx, target, value) {
91377
91428
  return ctx.fast ? { kind: "i32" } : { kind: "f64" };
91378
91429
  }
91379
91430
  }
91431
+ {
91432
+ const pinnedThis = target.expression.kind === ts.SyntaxKind.ThisKeyword && fctx.thisStructName !== void 0 ? fctx.thisStructName : void 0;
91433
+ const pinned = pinnedThis ?? resolveReceiverStruct(ctx, fctx, target.expression);
91434
+ if (pinned !== void 0) {
91435
+ const pinnedSet = tryEmitPinnedStructMemberSet(ctx, fctx, target, value);
91436
+ if (pinnedSet !== void 0) return pinnedSet;
91437
+ }
91438
+ }
91380
91439
  {
91381
91440
  const dynPropName = ts.isPrivateIdentifier(target.name) ? "__priv_" + target.name.text.slice(1) : target.name.text;
91382
91441
  const dynSet = tryEmitDeleteAwareDynamicSet(ctx, fctx, target, value, objType, dynPropName);
@@ -93555,17 +93614,23 @@ function compilePropertyCompoundAssignmentExternref(ctx, fctx, target, rhs, op,
93555
93614
  kind: "externref"
93556
93615
  });
93557
93616
  fctx.body.push({ op: "local.set", index: keyLocal });
93617
+ const pinnedCompound = target.expression.kind === ts.SyntaxKind.ThisKeyword && fctx.thisStructName !== void 0 || resolveReceiverStruct(ctx, fctx, target.expression) !== void 0;
93558
93618
  fctx.body.push({ op: "local.get", index: objLocal });
93559
- fctx.body.push({ op: "local.get", index: keyLocal });
93560
- const getIdx = ensureLateImport(
93561
- ctx,
93562
- "__extern_get",
93563
- [{ kind: "externref" }, { kind: "externref" }],
93564
- [{ kind: "externref" }]
93565
- );
93566
- flushLateImportShifts(ctx, fctx);
93567
- if (getIdx === void 0) return null;
93568
- fctx.body.push({ op: "call", funcIdx: getIdx });
93619
+ const getDispIdx = pinnedCompound ? reserveMemberGetDispatch(ctx, propName, fctx) : void 0;
93620
+ if (getDispIdx !== void 0) {
93621
+ fctx.body.push({ op: "call", funcIdx: getDispIdx });
93622
+ } else {
93623
+ fctx.body.push({ op: "local.get", index: keyLocal });
93624
+ const getIdx = ensureLateImport(
93625
+ ctx,
93626
+ "__extern_get",
93627
+ [{ kind: "externref" }, { kind: "externref" }],
93628
+ [{ kind: "externref" }]
93629
+ );
93630
+ flushLateImportShifts(ctx, fctx);
93631
+ if (getIdx === void 0) return null;
93632
+ fctx.body.push({ op: "call", funcIdx: getIdx });
93633
+ }
93569
93634
  addUnionImports(ctx);
93570
93635
  const unboxIdx = ctx.funcMap.get("__unbox_number");
93571
93636
  if (unboxIdx === void 0) {
@@ -93598,7 +93663,7 @@ function compilePropertyCompoundAssignmentExternref(ctx, fctx, target, rhs, op,
93598
93663
  []
93599
93664
  );
93600
93665
  flushLateImportShifts(ctx, fctx);
93601
- const cmpdDispatched = emitAlternateStructSetDispatch(
93666
+ const cmpdDispatched = pinnedCompound && emitAlternateStructSetDispatch(
93602
93667
  ctx,
93603
93668
  fctx,
93604
93669
  objLocal,
@@ -98664,18 +98729,7 @@ function compileStringBinaryOp(ctx, fctx, expr, op) {
98664
98729
  }
98665
98730
  }
98666
98731
  } else if (op === ts.SyntaxKind.PlusToken && leftType && (leftType.kind === "ref" || leftType.kind === "ref_null")) {
98667
- coerceType$1(ctx, fctx, leftType, { kind: "externref" });
98668
- const toStrIdx = ensureLateImport$1(
98669
- ctx,
98670
- "__extern_to_string_default",
98671
- [{ kind: "externref" }],
98672
- [{ kind: "externref" }]
98673
- );
98674
- flushLateImportShifts$1(ctx, fctx);
98675
- const finalIdx = ctx.funcMap.get("__extern_to_string_default") ?? toStrIdx;
98676
- if (finalIdx !== void 0) {
98677
- fctx.body.push({ op: "call", funcIdx: finalIdx });
98678
- }
98732
+ emitToString(ctx, fctx, leftType, leftTsType, "default");
98679
98733
  }
98680
98734
  const isEqOrNeq = op === ts.SyntaxKind.EqualsEqualsToken || op === ts.SyntaxKind.ExclamationEqualsToken || op === ts.SyntaxKind.EqualsEqualsEqualsToken || op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
98681
98735
  const isLeftStringWrapper = (leftTsType.flags & ts.TypeFlags.Object) !== 0 && leftTsType.getSymbol()?.name === "String";
@@ -98721,18 +98775,7 @@ function compileStringBinaryOp(ctx, fctx, expr, op) {
98721
98775
  }
98722
98776
  }
98723
98777
  } else if (op === ts.SyntaxKind.PlusToken && rightType && (rightType.kind === "ref" || rightType.kind === "ref_null")) {
98724
- coerceType$1(ctx, fctx, rightType, { kind: "externref" });
98725
- const toStrIdx = ensureLateImport$1(
98726
- ctx,
98727
- "__extern_to_string_default",
98728
- [{ kind: "externref" }],
98729
- [{ kind: "externref" }]
98730
- );
98731
- flushLateImportShifts$1(ctx, fctx);
98732
- const finalIdx = ctx.funcMap.get("__extern_to_string_default") ?? toStrIdx;
98733
- if (finalIdx !== void 0) {
98734
- fctx.body.push({ op: "call", funcIdx: finalIdx });
98735
- }
98778
+ emitToString(ctx, fctx, rightType, rightTsType, "default");
98736
98779
  }
98737
98780
  const isRightStringWrapper = (rightTsType.flags & ts.TypeFlags.Object) !== 0 && rightTsType.getSymbol()?.name === "String";
98738
98781
  if (isEqOrNeq && isRightStringWrapper && rightType?.kind === "externref") {
@@ -100276,174 +100319,6 @@ function emitSymbolToString(ctx, fctx) {
100276
100319
  compileNativeStringLiteral(ctx, fctx, ")");
100277
100320
  fctx.body.push({ op: "call", funcIdx: concatIdx });
100278
100321
  }
100279
- function dispatcherName$1(propName, strict) {
100280
- return strict ? `__set_member_${propName}` : `__set_member_nonstrict_${propName}`;
100281
- }
100282
- function reserveMemberSetDispatch(ctx, propName, strict) {
100283
- const name = dispatcherName$1(propName, strict);
100284
- const existing = ctx.funcMap.get(name);
100285
- if (existing !== void 0) return existing;
100286
- const fallbackName = strict ? "__extern_set_strict" : "__extern_set";
100287
- const setIdx = ensureLateImport$1(
100288
- ctx,
100289
- fallbackName,
100290
- [{ kind: "externref" }, { kind: "externref" }, { kind: "externref" }],
100291
- []
100292
- );
100293
- if (setIdx === void 0) return void 0;
100294
- addStringConstantGlobal(ctx, propName);
100295
- addUnionImportsViaRegistry(ctx);
100296
- const typeIdx = addFuncType(ctx, [{ kind: "externref" }, { kind: "externref" }], [], "$member_set_dispatch_type");
100297
- const funcIdx = ctx.numImportFuncs + ctx.mod.functions.length;
100298
- ctx.mod.functions.push({
100299
- name,
100300
- typeIdx,
100301
- locals: [],
100302
- // Placeholder; filled by fillMemberSetDispatch. `unreachable` keeps the stub
100303
- // valid (no results) if the fill is ever skipped (it never is — the fill
100304
- // iterates the same name set this reserve populates).
100305
- body: [{ op: "unreachable" }],
100306
- exported: false
100307
- });
100308
- ctx.funcMap.set(name, funcIdx);
100309
- (ctx.memberSetDispatchNames ??= /* @__PURE__ */ new Set()).add(`${propName}\0${strict ? "S" : "N"}`);
100310
- return funcIdx;
100311
- }
100312
- function fillMemberSetDispatch(ctx) {
100313
- const mod = ctx.mod;
100314
- for (const key of ctx.memberSetDispatchNames ?? []) {
100315
- const sep = key.lastIndexOf("\0");
100316
- const propName = sep >= 0 ? key.slice(0, sep) : key;
100317
- const strict = sep >= 0 ? key.slice(sep + 1) === "S" : true;
100318
- const dispIdx = ctx.funcMap.get(dispatcherName$1(propName, strict));
100319
- if (dispIdx === void 0) continue;
100320
- const dispFn = mod.functions[dispIdx - ctx.numImportFuncs];
100321
- if (!dispFn) continue;
100322
- const candidates = findAlternateStructsForField(ctx, propName, -1).filter((c) => c.mutable);
100323
- const fallbackIdx = ctx.funcMap.get(strict ? "__extern_set_strict" : "__extern_set");
100324
- const fallback = fallbackIdx !== void 0 ? [
100325
- { op: "local.get", index: 0 },
100326
- // recv
100327
- ...stringConstantExternrefInstrs(ctx, propName),
100328
- { op: "local.get", index: 1 },
100329
- // val
100330
- { op: "call", funcIdx: fallbackIdx }
100331
- ] : [];
100332
- const buildSetDispatch = (idx) => {
100333
- if (idx >= candidates.length) return fallback;
100334
- const cand = candidates[idx];
100335
- const coerce = coercionInstrs(ctx, { kind: "externref" }, cand.fieldType);
100336
- const setFieldInstrs = [
100337
- { op: "local.get", index: 2 },
100338
- // __any
100339
- { op: "ref.cast", typeIdx: cand.structTypeIdx },
100340
- { op: "local.get", index: 1 },
100341
- // val (externref)
100342
- ...coerce,
100343
- { op: "struct.set", typeIdx: cand.structTypeIdx, fieldIdx: cand.fieldIdx }
100344
- ];
100345
- return [
100346
- { op: "local.get", index: 2 },
100347
- // __any
100348
- { op: "ref.test", typeIdx: cand.structTypeIdx },
100349
- {
100350
- op: "if",
100351
- blockType: { kind: "empty" },
100352
- then: setFieldInstrs,
100353
- else: buildSetDispatch(idx + 1)
100354
- }
100355
- ];
100356
- };
100357
- dispFn.locals = [{ name: "__any", type: { kind: "anyref" } }];
100358
- dispFn.body = [
100359
- { op: "local.get", index: 0 },
100360
- // recv (externref)
100361
- { op: "any.convert_extern" },
100362
- { op: "local.set", index: 2 },
100363
- // __any
100364
- ...buildSetDispatch(0)
100365
- ];
100366
- }
100367
- }
100368
- function dispatcherName(propName) {
100369
- return `__get_member_${propName}`;
100370
- }
100371
- function reserveMemberGetDispatch(ctx, propName, fctx) {
100372
- const name = dispatcherName(propName);
100373
- const existing = ctx.funcMap.get(name);
100374
- if (existing !== void 0) return existing;
100375
- const getIdx = ensureLateImport$1(
100376
- ctx,
100377
- "__extern_get",
100378
- [{ kind: "externref" }, { kind: "externref" }],
100379
- [{ kind: "externref" }]
100380
- );
100381
- if (getIdx === void 0) return void 0;
100382
- addStringConstantGlobal(ctx, propName);
100383
- addUnionImportsViaRegistry(ctx);
100384
- const typeIdx = addFuncType(ctx, [{ kind: "externref" }], [{ kind: "externref" }], "$member_get_dispatch_type");
100385
- const funcIdx = ctx.numImportFuncs + ctx.mod.functions.length;
100386
- ctx.mod.functions.push({
100387
- name,
100388
- typeIdx,
100389
- locals: [],
100390
- body: [{ op: "unreachable" }],
100391
- exported: false
100392
- });
100393
- ctx.funcMap.set(name, funcIdx);
100394
- (ctx.memberGetDispatchNames ??= /* @__PURE__ */ new Set()).add(propName);
100395
- if (fctx) flushLateImportShifts$1(ctx, fctx);
100396
- return funcIdx;
100397
- }
100398
- function fillMemberGetDispatch(ctx) {
100399
- const mod = ctx.mod;
100400
- const getIdx = ctx.funcMap.get("__extern_get");
100401
- for (const propName of ctx.memberGetDispatchNames ?? []) {
100402
- const dispIdx = ctx.funcMap.get(dispatcherName(propName));
100403
- if (dispIdx === void 0) continue;
100404
- const dispFn = mod.functions[dispIdx - ctx.numImportFuncs];
100405
- if (!dispFn) continue;
100406
- const candidates = findAlternateStructsForField(ctx, propName, -1);
100407
- const fallback = getIdx !== void 0 ? [
100408
- { op: "local.get", index: 0 },
100409
- // recv
100410
- ...stringConstantExternrefInstrs(ctx, propName),
100411
- { op: "call", funcIdx: getIdx }
100412
- ] : [{ op: "ref.null.extern" }];
100413
- const buildGetDispatch = (idx) => {
100414
- if (idx >= candidates.length) return fallback;
100415
- const cand = candidates[idx];
100416
- const box = coercionInstrs(ctx, cand.fieldType, { kind: "externref" });
100417
- const readInstrs = [
100418
- { op: "local.get", index: 1 },
100419
- // __any
100420
- { op: "ref.cast", typeIdx: cand.structTypeIdx },
100421
- { op: "struct.get", typeIdx: cand.structTypeIdx, fieldIdx: cand.fieldIdx },
100422
- ...box
100423
- ];
100424
- return [
100425
- { op: "local.get", index: 1 },
100426
- // __any
100427
- { op: "ref.test", typeIdx: cand.structTypeIdx },
100428
- {
100429
- op: "if",
100430
- blockType: { kind: "val", type: { kind: "externref" } },
100431
- then: readInstrs,
100432
- else: buildGetDispatch(idx + 1)
100433
- }
100434
- ];
100435
- };
100436
- dispFn.locals = [{ name: "__any", type: { kind: "anyref" } }];
100437
- dispFn.body = [
100438
- { op: "local.get", index: 0 },
100439
- // recv (externref)
100440
- { op: "any.convert_extern" },
100441
- { op: "local.set", index: 1 },
100442
- // __any
100443
- ...buildGetDispatch(0)
100444
- ];
100445
- }
100446
- }
100447
100322
  const BUILTIN_CTOR_NAMES = /* @__PURE__ */ new Set([
100448
100323
  "Object",
100449
100324
  "Array",
@@ -101136,7 +101011,7 @@ function emitNullCheckThrow(ctx, fctx, refType, node) {
101136
101011
  releaseTempLocal(fctx, tmp);
101137
101012
  }
101138
101013
  function emitAlternateStructSetDispatch(ctx, fctx, recvExtLocal, valExtLocal, propName, strict) {
101139
- const dispIdx = reserveMemberSetDispatch(ctx, propName, strict);
101014
+ const dispIdx = reserveMemberSetDispatch(ctx, propName, strict, fctx);
101140
101015
  if (dispIdx === void 0) return false;
101141
101016
  fctx.body.push({ op: "local.get", index: recvExtLocal });
101142
101017
  fctx.body.push({ op: "local.get", index: valExtLocal });
@@ -101624,6 +101499,40 @@ function emitGuardedNativeStringLength(ctx, fctx, buildElseInstrs) {
101624
101499
  else: buildElseInstrs(recvExtern)
101625
101500
  });
101626
101501
  }
101502
+ function tryEmitPinnedStructMemberGet(ctx, fctx, expr, propName) {
101503
+ if (propName === "length" || propName === "constructor" || propName === "__proto__" || propName === "prototype" || propName === "name") {
101504
+ return void 0;
101505
+ }
101506
+ const accessType = ctx.checker.getTypeAtLocation(expr);
101507
+ if (accessType.getCallSignatures && accessType.getCallSignatures().length > 0) return void 0;
101508
+ const objResult = compileExpression$1(ctx, fctx, expr.expression);
101509
+ if (objResult && objResult.kind !== "externref") {
101510
+ coerceType$2(ctx, fctx, objResult, { kind: "externref" });
101511
+ } else if (!objResult) {
101512
+ fctx.body.push({ op: "ref.null.extern" });
101513
+ }
101514
+ const getDispIdx = reserveMemberGetDispatch(ctx, propName, fctx);
101515
+ if (getDispIdx === void 0) {
101516
+ const getIdx = ensureLateImport$1(
101517
+ ctx,
101518
+ "__extern_get",
101519
+ [{ kind: "externref" }, { kind: "externref" }],
101520
+ [{ kind: "externref" }]
101521
+ );
101522
+ flushLateImportShifts$1(ctx, fctx);
101523
+ if (getIdx === void 0) {
101524
+ fctx.body.push({ op: "drop" });
101525
+ fctx.body.push({ op: "ref.null.extern" });
101526
+ return { kind: "externref" };
101527
+ }
101528
+ addStringConstantGlobal(ctx, propName);
101529
+ fctx.body.push(...stringConstantExternrefInstrs(ctx, propName));
101530
+ fctx.body.push({ op: "call", funcIdx: getIdx });
101531
+ return { kind: "externref" };
101532
+ }
101533
+ fctx.body.push({ op: "call", funcIdx: getDispIdx });
101534
+ return { kind: "externref" };
101535
+ }
101627
101536
  function tryEmitDeleteAwareDynamicGet(ctx, fctx, expr, objType, propName) {
101628
101537
  if (!ctx.moduleUsesDelete || ctx.standalone) return void 0;
101629
101538
  const isAnyOrUnknown2 = (objType.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0;
@@ -101639,17 +101548,35 @@ function tryEmitDeleteAwareDynamicGet(ctx, fctx, expr, objType, propName) {
101639
101548
  [{ kind: "externref" }, { kind: "externref" }],
101640
101549
  [{ kind: "externref" }]
101641
101550
  );
101642
- flushLateImportShifts$1(ctx, fctx);
101643
101551
  if (getIdx === void 0) return void 0;
101552
+ const getMemberIdx = ctx.wasi ? void 0 : reserveMemberGetDispatch(ctx, propName, fctx);
101553
+ addStringConstantGlobal(ctx, propName);
101554
+ flushLateImportShifts$1(ctx, fctx);
101644
101555
  const objResult = compileExpression$1(ctx, fctx, expr.expression);
101645
101556
  if (objResult && objResult.kind !== "externref") {
101646
101557
  coerceType$2(ctx, fctx, objResult, { kind: "externref" });
101647
101558
  } else if (!objResult) {
101648
101559
  fctx.body.push({ op: "ref.null.extern" });
101649
101560
  }
101650
- addStringConstantGlobal(ctx, propName);
101651
- fctx.body.push(...stringConstantExternrefInstrs(ctx, propName));
101652
- fctx.body.push({ op: "call", funcIdx: getIdx });
101561
+ if (getMemberIdx === void 0) {
101562
+ fctx.body.push(...stringConstantExternrefInstrs(ctx, propName));
101563
+ fctx.body.push({ op: "call", funcIdx: getIdx });
101564
+ return { kind: "externref" };
101565
+ }
101566
+ const flagGet = recordInModuleInitFlagRead(ctx);
101567
+ const recvLocal = allocLocal(fctx, `__dadg_recv_${fctx.locals.length}`, { kind: "externref" });
101568
+ fctx.body.push({ op: "local.set", index: recvLocal });
101569
+ fctx.body.push(flagGet);
101570
+ fctx.body.push({
101571
+ op: "if",
101572
+ blockType: { kind: "val", type: { kind: "externref" } },
101573
+ then: [{ op: "local.get", index: recvLocal }, { op: "call", funcIdx: getMemberIdx }],
101574
+ else: [
101575
+ { op: "local.get", index: recvLocal },
101576
+ ...stringConstantExternrefInstrs(ctx, propName),
101577
+ { op: "call", funcIdx: getIdx }
101578
+ ]
101579
+ });
101653
101580
  return { kind: "externref" };
101654
101581
  }
101655
101582
  function tryEmitDeleteAwareDynamicSet(ctx, fctx, target, value, objType, propName) {
@@ -101809,6 +101736,14 @@ function compilePropertyAccess(ctx, fctx, expr) {
101809
101736
  const fnctorProto = tryEmitFnctorPrototypeRead(ctx, fctx, expr, propName);
101810
101737
  if (fnctorProto !== void 0) return fnctorProto;
101811
101738
  }
101739
+ {
101740
+ const pinnedThis = expr.expression.kind === ts.SyntaxKind.ThisKeyword && fctx.thisStructName !== void 0 ? fctx.thisStructName : void 0;
101741
+ const pinned = pinnedThis ?? resolveReceiverStruct(ctx, fctx, expr.expression);
101742
+ if (pinned !== void 0) {
101743
+ const routed = tryEmitPinnedStructMemberGet(ctx, fctx, expr, propName);
101744
+ if (routed !== void 0) return routed;
101745
+ }
101746
+ }
101812
101747
  {
101813
101748
  const dyn = tryEmitDeleteAwareDynamicGet(ctx, fctx, expr, objType, propName);
101814
101749
  if (dyn !== void 0) return dyn;
@@ -103577,6 +103512,9 @@ function f1ElementBoxType(ctx, expr, elementType) {
103577
103512
  if (valueParts.every((p) => (p.flags & ts.TypeFlags.BooleanLike) !== 0)) {
103578
103513
  return { kind: "i32", boolean: true };
103579
103514
  }
103515
+ if (!noJsHost(ctx) && valueParts.every((p) => (p.flags & (ts.TypeFlags.ESSymbol | ts.TypeFlags.UniqueESSymbol)) !== 0)) {
103516
+ return { kind: "i32", symbol: true };
103517
+ }
103580
103518
  return null;
103581
103519
  }
103582
103520
  function emitPlainArrayUndefinedOobGet(ctx, fctx, arrTypeIdx, elementType, boxType = elementType) {
@@ -103608,6 +103546,41 @@ function emitPlainArrayUndefinedOobGet(ctx, fctx, arrTypeIdx, elementType, boxTy
103608
103546
  else: [{ op: "local.get", index: undefLocal }]
103609
103547
  });
103610
103548
  }
103549
+ function emitTypedArrayUndefinedOobGet(ctx, fctx, arrTypeIdx, elementType, signedness) {
103550
+ const idxLocal = allocLocal(fctx, `__taoob_idx_${fctx.locals.length}`, { kind: "i32" });
103551
+ const arrLocal = allocLocal(fctx, `__taoob_arr_${fctx.locals.length}`, { kind: "ref", typeIdx: arrTypeIdx });
103552
+ fctx.body.push({ op: "local.set", index: idxLocal });
103553
+ fctx.body.push({ op: "local.set", index: arrLocal });
103554
+ const inBoundsLocal = allocLocal(fctx, `__taoob_in_${fctx.locals.length}`, { kind: "i32" });
103555
+ fctx.body.push({ op: "local.get", index: idxLocal });
103556
+ fctx.body.push({ op: "local.get", index: arrLocal });
103557
+ fctx.body.push({ op: "array.len" });
103558
+ fctx.body.push({ op: "i32.lt_u" });
103559
+ fctx.body.push({ op: "local.set", index: inBoundsLocal });
103560
+ fctx.body.push({ op: "local.get", index: arrLocal });
103561
+ fctx.body.push({ op: "local.get", index: idxLocal });
103562
+ emitBoundsCheckedArrayGet(fctx, arrTypeIdx, elementType, ctx, false, signedness);
103563
+ if (elementType.kind === "i8" || elementType.kind === "i16") {
103564
+ fctx.body.push({ op: "f64.convert_i32_s" });
103565
+ } else if (elementType.kind === "i32") {
103566
+ fctx.body.push({ op: signedness === "u" ? "f64.convert_i32_u" : "f64.convert_i32_s" });
103567
+ } else if (elementType.kind === "f32") {
103568
+ fctx.body.push({ op: "f64.promote_f32" });
103569
+ }
103570
+ coerceType$2(ctx, fctx, { kind: "f64" }, { kind: "externref" });
103571
+ const boxedLocal = allocLocal(fctx, `__taoob_box_${fctx.locals.length}`, { kind: "externref" });
103572
+ fctx.body.push({ op: "local.set", index: boxedLocal });
103573
+ emitUndefined(ctx, fctx);
103574
+ const undefLocal = allocLocal(fctx, `__taoob_undef_${fctx.locals.length}`, { kind: "externref" });
103575
+ fctx.body.push({ op: "local.set", index: undefLocal });
103576
+ fctx.body.push({ op: "local.get", index: inBoundsLocal });
103577
+ fctx.body.push({
103578
+ op: "if",
103579
+ blockType: { kind: "val", type: { kind: "externref" } },
103580
+ then: [{ op: "local.get", index: boxedLocal }],
103581
+ else: [{ op: "local.get", index: undefLocal }]
103582
+ });
103583
+ }
103611
103584
  function emitThisReceiverGuardConvert(ctx, fctx, targetTypeIdxs, resultType, thenEmit, elseEmit) {
103612
103585
  const externrefTmp = allocTempLocal(fctx, { kind: "externref" });
103613
103586
  fctx.body.push({ op: "local.tee", index: externrefTmp });
@@ -103910,6 +103883,55 @@ function isNumericIndexExpression(ctx, index) {
103910
103883
  }
103911
103884
  function compileElementAccessBody(ctx, fctx, expr, objType, expectedType) {
103912
103885
  if (objType.kind === "externref") {
103886
+ if (!ctx.standalone && ctx.vecTypeMap.size > 0 && isNumericIndexExpression(ctx, expr.argumentExpression)) {
103887
+ const vecGetIdx = ctx.funcMap.get("__vec_get");
103888
+ const extGetIdx = ensureLateImport$1(
103889
+ ctx,
103890
+ "__extern_get",
103891
+ [{ kind: "externref" }, { kind: "externref" }],
103892
+ [{ kind: "externref" }]
103893
+ );
103894
+ const boxNumIdx = ensureLateImport$1(ctx, "__box_number", [{ kind: "f64" }], [{ kind: "externref" }]);
103895
+ flushLateImportShifts$1(ctx, fctx);
103896
+ const vgIdx = vecGetIdx ?? reserveVecMethodHelper(ctx, "get");
103897
+ if (vgIdx !== void 0 && extGetIdx !== void 0 && boxNumIdx !== void 0) {
103898
+ const recvLocal = allocLocal(fctx, `__nve_recv_${fctx.locals.length}`, { kind: "externref" });
103899
+ fctx.body.push({ op: "local.set", index: recvLocal });
103900
+ compileExpression$1(ctx, fctx, expr.argumentExpression, { kind: "f64" });
103901
+ const idxLocal = allocLocal(fctx, `__nve_idx_${fctx.locals.length}`, { kind: "f64" });
103902
+ fctx.body.push({ op: "local.set", index: idxLocal });
103903
+ const anyTmp = allocLocal(fctx, `__nve_any_${fctx.locals.length}`, { kind: "anyref" });
103904
+ fctx.body.push({ op: "local.get", index: recvLocal });
103905
+ fctx.body.push({ op: "any.convert_extern" });
103906
+ fctx.body.push({ op: "local.set", index: anyTmp });
103907
+ let emitted = false;
103908
+ for (const vi of new Set(ctx.vecTypeMap.values())) {
103909
+ fctx.body.push({ op: "local.get", index: anyTmp });
103910
+ fctx.body.push({ op: "ref.test", typeIdx: vi });
103911
+ if (emitted) fctx.body.push({ op: "i32.or" });
103912
+ emitted = true;
103913
+ }
103914
+ const thenStart = fctx.body.length;
103915
+ fctx.body.push({ op: "local.get", index: recvLocal });
103916
+ fctx.body.push({ op: "local.get", index: idxLocal });
103917
+ fctx.body.push({ op: "i32.trunc_sat_f64_s" });
103918
+ fctx.body.push({ op: "call", funcIdx: vgIdx });
103919
+ const thenInstrs = fctx.body.splice(thenStart);
103920
+ const elseStart = fctx.body.length;
103921
+ fctx.body.push({ op: "local.get", index: recvLocal });
103922
+ fctx.body.push({ op: "local.get", index: idxLocal });
103923
+ fctx.body.push({ op: "call", funcIdx: boxNumIdx });
103924
+ fctx.body.push({ op: "call", funcIdx: extGetIdx });
103925
+ const elseInstrs = fctx.body.splice(elseStart);
103926
+ fctx.body.push({
103927
+ op: "if",
103928
+ blockType: { kind: "val", type: { kind: "externref" } },
103929
+ then: thenInstrs,
103930
+ else: elseInstrs
103931
+ });
103932
+ return { kind: "externref" };
103933
+ }
103934
+ }
103913
103935
  if (ctx.standalone && isNumericIndexExpression(ctx, expr.argumentExpression)) {
103914
103936
  compileExpression$1(ctx, fctx, expr.argumentExpression, { kind: "f64" });
103915
103937
  const getIdxFn = ensureLateImport$1(
@@ -104154,7 +104176,9 @@ function compileElementAccessBody(ctx, fctx, expr, objType, expectedType) {
104154
104176
  const taSignedness = typedArrayViewSignedness(ctx, expr.expression);
104155
104177
  const isRegexMatchVec = typeDef.fields.length >= 4 && typeDef.fields[2]?.name === "index";
104156
104178
  const numericHint = expectedType?.kind === "f64" || expectedType?.kind === "i32";
104157
- const oobUndefined = !numericHint && classifyTypedArrayType(ctx.checker.getTypeAtLocation(expr.expression), ctx.checker) === "other" && !isRegexMatchVec;
104179
+ const taClass = classifyTypedArrayType(ctx.checker.getTypeAtLocation(expr.expression), ctx.checker);
104180
+ const oobUndefined = !numericHint && taClass === "other" && !isRegexMatchVec;
104181
+ const oobUndefinedTypedArray = !numericHint && taClass !== "other";
104158
104182
  const f1BoxType = f1ElementBoxType(ctx, expr, arrDef.element);
104159
104183
  fctx.body.push({ op: "struct.get", typeIdx, fieldIdx: 1 });
104160
104184
  compileExpression$1(ctx, fctx, expr.argumentExpression, { kind: "i32" });
@@ -104166,6 +104190,9 @@ function compileElementAccessBody(ctx, fctx, expr, objType, expectedType) {
104166
104190
  } else if (oobUndefined && f1BoxType !== null) {
104167
104191
  emitPlainArrayUndefinedOobGet(ctx, fctx, arrTypeIdx, arrDef.element, f1BoxType);
104168
104192
  return { kind: "externref" };
104193
+ } else if (oobUndefinedTypedArray) {
104194
+ emitTypedArrayUndefinedOobGet(ctx, fctx, arrTypeIdx, arrDef.element, taSignedness);
104195
+ return { kind: "externref" };
104169
104196
  } else {
104170
104197
  emitBoundsCheckedArrayGet(fctx, arrTypeIdx, arrDef.element, ctx, false, taSignedness);
104171
104198
  }
@@ -104180,7 +104207,10 @@ function compileElementAccessBody(ctx, fctx, expr, objType, expectedType) {
104180
104207
  return null;
104181
104208
  }
104182
104209
  const taSignednessArr = typedArrayViewSignedness(ctx, expr.expression);
104183
- const oobUndefinedArr = !(expectedType?.kind === "f64" || expectedType?.kind === "i32") && classifyTypedArrayType(ctx.checker.getTypeAtLocation(expr.expression), ctx.checker) === "other";
104210
+ const numericHintArr = expectedType?.kind === "f64" || expectedType?.kind === "i32";
104211
+ const taClassArr = classifyTypedArrayType(ctx.checker.getTypeAtLocation(expr.expression), ctx.checker);
104212
+ const oobUndefinedArr = !numericHintArr && taClassArr === "other";
104213
+ const oobUndefinedTypedArrayArr = !numericHintArr && taClassArr !== "other";
104184
104214
  const f1BoxTypeArr = f1ElementBoxType(ctx, expr, typeDef.element);
104185
104215
  compileExpression$1(ctx, fctx, expr.argumentExpression, { kind: "i32" });
104186
104216
  const valueType = typeDef.element.kind === "i8" || typeDef.element.kind === "i16" ? { kind: "i32" } : typeDef.element;
@@ -104191,6 +104221,9 @@ function compileElementAccessBody(ctx, fctx, expr, objType, expectedType) {
104191
104221
  } else if (oobUndefinedArr && f1BoxTypeArr !== null) {
104192
104222
  emitPlainArrayUndefinedOobGet(ctx, fctx, typeIdx, typeDef.element, f1BoxTypeArr);
104193
104223
  return { kind: "externref" };
104224
+ } else if (oobUndefinedTypedArrayArr) {
104225
+ emitTypedArrayUndefinedOobGet(ctx, fctx, typeIdx, typeDef.element, taSignednessArr);
104226
+ return { kind: "externref" };
104194
104227
  } else {
104195
104228
  emitBoundsCheckedArrayGet(fctx, typeIdx, typeDef.element, ctx, false, taSignednessArr);
104196
104229
  }
@@ -104972,6 +105005,12 @@ function _hasRuntimeComputedKey(ctx, expr) {
104972
105005
  }
104973
105006
  return false;
104974
105007
  }
105008
+ function objectLiteralSpreadTakesHostPath(ctx, expr) {
105009
+ if (expr.properties.length === 0) return false;
105010
+ if (!expr.properties.some((p) => ts.isSpreadAssignment(p))) return false;
105011
+ const spreadCtxType = ctx.checker.getContextualType(expr);
105012
+ return !spreadCtxType || (spreadCtxType.flags & ts.TypeFlags.Any) !== 0 || (spreadCtxType.flags & ts.TypeFlags.Unknown) !== 0 || (spreadCtxType.flags & ts.TypeFlags.NonPrimitive) !== 0 || spreadCtxType.getProperties().length === 0;
105013
+ }
104975
105014
  function compileObjectLiteral(ctx, fctx, expr) {
104976
105015
  if (expr.properties.length > 0 && (expr.properties.some((p) => ts.isGetAccessorDeclaration(p) || ts.isSetAccessorDeclaration(p)) || _hasDisposalMethod(expr) || _hasRuntimeComputedKey(ctx, expr))) {
104977
105016
  return compileObjectLiteralWithAccessors(ctx, fctx, expr);
@@ -104979,12 +105018,8 @@ function compileObjectLiteral(ctx, fctx, expr) {
104979
105018
  if (expr.properties.length > 0 && _hasAccessorSpreadSource(ctx, expr)) {
104980
105019
  return compileObjectLiteralWithAccessors(ctx, fctx, expr);
104981
105020
  }
104982
- if (expr.properties.length > 0 && expr.properties.some((p) => ts.isSpreadAssignment(p))) {
104983
- const spreadCtxType = ctx.checker.getContextualType(expr);
104984
- const nonSpecificCtx = !spreadCtxType || (spreadCtxType.flags & ts.TypeFlags.Any) !== 0 || (spreadCtxType.flags & ts.TypeFlags.Unknown) !== 0 || (spreadCtxType.flags & ts.TypeFlags.NonPrimitive) !== 0 || spreadCtxType.getProperties().length === 0;
104985
- if (nonSpecificCtx) {
104986
- return compileObjectLiteralWithAccessors(ctx, fctx, expr);
104987
- }
105021
+ if (objectLiteralSpreadTakesHostPath(ctx, expr)) {
105022
+ return compileObjectLiteralWithAccessors(ctx, fctx, expr);
104988
105023
  }
104989
105024
  if (expr.properties.length === 0 && ts.isVariableDeclaration(expr.parent) && ts.isIdentifier(expr.parent.name)) {
104990
105025
  const widenedProps = ctx.widenedTypeProperties.get(expr.parent.name.text);
@@ -113961,7 +113996,7 @@ function buildLocalCallGraph(decls, localClasses) {
113961
113996
  if (!fn.body) continue;
113962
113997
  const localBindings = collectLocalClosureBindings(fn);
113963
113998
  const visit = (node) => {
113964
- if (node !== fn && isFunctionLike(node)) return;
113999
+ if (node !== fn && isFunctionLike$1(node)) return;
113965
114000
  if (ts.isNewExpression(node)) {
113966
114001
  if (ts.isIdentifier(node.expression) && (localClasses.has(node.expression.text) || isKnownExternClass(node.expression.text))) {
113967
114002
  if (node.arguments) {
@@ -114016,7 +114051,7 @@ function collectLocalClosureBindings(fn) {
114016
114051
  const names = /* @__PURE__ */ new Set();
114017
114052
  if (!fn.body) return names;
114018
114053
  const visit = (node) => {
114019
- if (node !== fn && isFunctionLike(node)) return;
114054
+ if (node !== fn && isFunctionLike$1(node)) return;
114020
114055
  if (ts.isFunctionDeclaration(node) && node !== fn && node.name) {
114021
114056
  names.add(node.name.text);
114022
114057
  }
@@ -114035,7 +114070,7 @@ function collectLocalClosureBindings(fn) {
114035
114070
  forEachChild$1(fn.body, visit);
114036
114071
  return names;
114037
114072
  }
114038
- function isFunctionLike(node) {
114073
+ function isFunctionLike$1(node) {
114039
114074
  return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node) || ts.isClassDeclaration(node) || ts.isClassExpression(node);
114040
114075
  }
114041
114076
  function lowerFunctionAstToIr(fn, options = {}) {
@@ -114394,8 +114429,9 @@ function lowerVarDecl(stmt, cx) {
114394
114429
  }
114395
114430
  }
114396
114431
  if (!proveUnboxedNumberLocal(d.name, inferred, cx)) {
114432
+ const boundKind = asVal(inferred)?.kind === "i32" ? "i32" : "f64";
114397
114433
  throw new Error(
114398
- `ir/from-ast: local '${name}' is bound as an unboxed f64 but its TS type is not provably a pure number — keeping the no-box number representation is unsound (the f64 Wasm kind conflates number / boolean / any); demote to the SAFE boxed legacy lowering in ${cx.funcName} (#2782)`
114434
+ `ir/from-ast: local '${name}' is bound as an unboxed ${boundKind} but its TS type is not provably a pure number${boundKind === "i32" ? " or boolean" : ""} — keeping the no-box number representation is unsound (the ${boundKind} Wasm kind conflates number / boolean / any); demote to the SAFE boxed legacy lowering in ${cx.funcName} (#2782/#2790)`
114399
114435
  );
114400
114436
  }
114401
114437
  if (!isConst && cx.mutatedLets.has(name)) {
@@ -116063,12 +116099,21 @@ function proveAdditiveOperand(node, cx) {
116063
116099
  if (!checker) return "no-checker";
116064
116100
  return classifyPrimitiveProof(checker.getTypeAtLocation(node));
116065
116101
  }
116102
+ function isProvablyBoolean(t) {
116103
+ if (t.isUnion()) {
116104
+ return t.types.length > 0 && t.types.every(isProvablyBoolean);
116105
+ }
116106
+ return (t.flags & ts.TypeFlags.BooleanLike) !== 0;
116107
+ }
116066
116108
  function proveUnboxedNumberLocal(name, boundType, cx) {
116067
116109
  const bv = asVal(boundType);
116068
- if (!bv || bv.kind !== "f64") return true;
116110
+ if (!bv || bv.kind !== "f64" && bv.kind !== "i32") return true;
116069
116111
  const checker = cx.checker;
116070
116112
  if (!checker) return true;
116071
- return classifyPrimitiveProof(checker.getTypeAtLocation(name)) === "number";
116113
+ const tsType = checker.getTypeAtLocation(name);
116114
+ if (classifyPrimitiveProof(tsType) === "number") return true;
116115
+ if (bv.kind === "f64") return false;
116116
+ return isProvablyBoolean(tsType);
116072
116117
  }
116073
116118
  function lowerBinary(expr, cx, hint) {
116074
116119
  const op = expr.operatorToken.kind;
@@ -124027,6 +124072,7 @@ function walkBodyForReturns(body, paramScope, entries, cb) {
124027
124072
  function createCodegenContext(mod, checker, options) {
124028
124073
  const strictNoHostImports = options?.strictNoHostImports ?? options?.wasi ?? false;
124029
124074
  const nativeStrings = options?.nativeStrings ?? !!(options?.fast || options?.wasi || options?.standalone || strictNoHostImports || options?.utf8Storage);
124075
+ const linkedNamespaces = new Set(options?.wasi ? options?.link ?? [] : []);
124030
124076
  const ctx = {
124031
124077
  mod,
124032
124078
  checker,
@@ -124090,6 +124136,10 @@ function createCodegenContext(mod, checker, options) {
124090
124136
  // (#2001 S1) $Hole struct type; lazily registered
124091
124137
  holeGlobalIdx: void 0,
124092
124138
  // (#2001 S1) $__hole singleton global
124139
+ inModuleInitFlagReads: void 0,
124140
+ // (#2800) recorded __in_module_init flag reads
124141
+ inModuleInitGlobalIdx: void 0,
124142
+ // (#2800) __in_module_init flag global (set at finalize)
124093
124143
  usesDynRead: false,
124094
124144
  // (#2580 M0) set by a __dyn_has/__dyn_get call site (M1+); M0 adds none
124095
124145
  dynReadHelpersEmitted: false,
@@ -124235,11 +124285,17 @@ function createCodegenContext(mod, checker, options) {
124235
124285
  // (#2025)
124236
124286
  funcClosureGlobals: /* @__PURE__ */ new Map(),
124237
124287
  wasi: options?.wasi ?? false,
124238
- // #2625the linkable js2wasm:node-<mod> shims only apply under WASI; ignored otherwise.
124239
- linkNodeShims: !!(options?.wasi && options?.linkNodeShims),
124288
+ // #2783namespaces left as link-time imports (WASI-gated above).
124289
+ linkedNamespaces,
124290
+ // #2625/#2783 — the linkable js2wasm:node-<mod> std-IO path only applies under
124291
+ // WASI; derived from `node:fs` membership in the (already WASI-gated) link set.
124292
+ linkNodeShims: linkedNamespaces.has("node:fs"),
124240
124293
  nodeFsReadSyncIdx: -1,
124241
124294
  nodeFsWriteSyncIdx: -1,
124242
124295
  standalone: options?.standalone ?? false,
124296
+ // (#2796) Diff-test-harness fidelity — export __module_init + skip the wasm
124297
+ // start section so the host runs top-level code after setExports.
124298
+ deferTopLevelInit: options?.deferTopLevelInit ?? false,
124243
124299
  // #682 — native standalone RegExp engine hook. Standalone mode enables the
124244
124300
  // reduced literal-substring backend; broader QuickJS libregexp ABI linking
124245
124301
  // remains the follow-up path for near-JS parity.
@@ -130319,9 +130375,14 @@ function isI32SafeExprForArray(expr, i32Locals, depth = 0) {
130319
130375
  }
130320
130376
  if (ts.isPrefixUnaryExpression(expr)) {
130321
130377
  const op = expr.operator;
130322
- if (op === ts.SyntaxKind.PlusToken || op === ts.SyntaxKind.MinusToken || op === ts.SyntaxKind.TildeToken) {
130378
+ if (op === ts.SyntaxKind.PlusToken || op === ts.SyntaxKind.TildeToken) {
130323
130379
  return isI32SafeExprForArray(expr.operand, i32Locals, depth + 1);
130324
130380
  }
130381
+ if (op === ts.SyntaxKind.MinusToken) {
130382
+ if (!ts.isNumericLiteral(expr.operand)) return false;
130383
+ if (!isI32SafeExprForArray(expr.operand, i32Locals, depth + 1)) return false;
130384
+ return Number(expr.operand.text.replace(/_/g, "")) !== 0;
130385
+ }
130325
130386
  return false;
130326
130387
  }
130327
130388
  if (ts.isBinaryExpression(expr)) {
@@ -130333,7 +130394,7 @@ function isI32SafeExprForArray(expr, i32Locals, depth = 0) {
130333
130394
  return true;
130334
130395
  }
130335
130396
  if (op === ts.SyntaxKind.PlusToken || op === ts.SyntaxKind.MinusToken || op === ts.SyntaxKind.AsteriskToken) {
130336
- return isI32SafeExprForArray(expr.left, i32Locals, depth + 1) && isI32SafeExprForArray(expr.right, i32Locals, depth + 1);
130397
+ return false;
130337
130398
  }
130338
130399
  return false;
130339
130400
  }
@@ -130439,7 +130500,7 @@ function collectI32SpecializedArrays(decl, i32CoercedLocals) {
130439
130500
  if (ts.isBinaryExpression(node) && node.operatorToken.kind !== ts.SyntaxKind.EqualsToken && isCompoundAssignment(node.operatorToken.kind) && ts.isElementAccessExpression(node.left) && ts.isIdentifier(node.left.expression) && candidates.has(node.left.expression.text)) {
130440
130501
  const arrName = node.left.expression.text;
130441
130502
  const isBitwiseCompound = node.operatorToken.kind === ts.SyntaxKind.BarEqualsToken || node.operatorToken.kind === ts.SyntaxKind.AmpersandEqualsToken || node.operatorToken.kind === ts.SyntaxKind.CaretEqualsToken || node.operatorToken.kind === ts.SyntaxKind.LessThanLessThanEqualsToken || node.operatorToken.kind === ts.SyntaxKind.GreaterThanGreaterThanEqualsToken;
130442
- if (!isBitwiseCompound && !isI32SafeExprForArray(node.right, i32Locals)) {
130503
+ if (!isBitwiseCompound) {
130443
130504
  disqualified.add(arrName);
130444
130505
  }
130445
130506
  }
@@ -132693,9 +132754,52 @@ function inferNumericReturnTypes(ctx, sourceFile) {
132693
132754
  }
132694
132755
  }
132695
132756
  }
132757
+ const isBooleanExpr = (expr, depth = 0) => {
132758
+ if (depth > MAX_NUMERIC_DEPTH) return false;
132759
+ if (ts.isParenthesizedExpression(expr)) return isBooleanExpr(expr.expression, depth + 1);
132760
+ if (ts.isAsExpression(expr) || ts.isTypeAssertionExpression(expr) || ts.isNonNullExpression(expr)) {
132761
+ return isBooleanExpr(expr.expression, depth + 1);
132762
+ }
132763
+ if (expr.kind === ts.SyntaxKind.TrueKeyword || expr.kind === ts.SyntaxKind.FalseKeyword) return true;
132764
+ if (ts.isPrefixUnaryExpression(expr)) {
132765
+ return expr.operator === ts.SyntaxKind.ExclamationToken;
132766
+ }
132767
+ if (ts.isBinaryExpression(expr)) {
132768
+ const op = expr.operatorToken.kind;
132769
+ if (op === ts.SyntaxKind.LessThanToken || op === ts.SyntaxKind.LessThanEqualsToken || op === ts.SyntaxKind.GreaterThanToken || op === ts.SyntaxKind.GreaterThanEqualsToken || op === ts.SyntaxKind.EqualsEqualsToken || op === ts.SyntaxKind.ExclamationEqualsToken || op === ts.SyntaxKind.EqualsEqualsEqualsToken || op === ts.SyntaxKind.ExclamationEqualsEqualsToken || op === ts.SyntaxKind.InstanceOfKeyword || op === ts.SyntaxKind.InKeyword) {
132770
+ return true;
132771
+ }
132772
+ if (op === ts.SyntaxKind.AmpersandAmpersandToken || op === ts.SyntaxKind.BarBarToken) {
132773
+ return isBooleanExpr(expr.left, depth + 1) && isBooleanExpr(expr.right, depth + 1);
132774
+ }
132775
+ return false;
132776
+ }
132777
+ if (ts.isConditionalExpression(expr)) {
132778
+ return isBooleanExpr(expr.whenTrue, depth + 1) && isBooleanExpr(expr.whenFalse, depth + 1);
132779
+ }
132780
+ if (ts.isCallExpression(expr) && ts.isIdentifier(expr.expression)) {
132781
+ if (boolean.has(expr.expression.text)) return true;
132782
+ if (expr.expression.text === "Boolean") return true;
132783
+ return false;
132784
+ }
132785
+ return false;
132786
+ };
132787
+ const boolean = new Set(numeric);
132788
+ let bChanged = true;
132789
+ let bSafety = boolean.size + 1;
132790
+ while (bChanged && bSafety-- > 0) {
132791
+ bChanged = false;
132792
+ for (const fnName of [...boolean]) {
132793
+ const info = fnInfo.get(fnName);
132794
+ if (!info.returns.every((r) => isBooleanExpr(r))) {
132795
+ boolean.delete(fnName);
132796
+ bChanged = true;
132797
+ }
132798
+ }
132799
+ }
132696
132800
  const result = /* @__PURE__ */ new Map();
132697
132801
  for (const fnName of numeric) {
132698
- result.set(fnName, { kind: "f64" });
132802
+ result.set(fnName, boolean.has(fnName) ? { kind: "i32", boolean: true } : { kind: "f64" });
132699
132803
  }
132700
132804
  return result;
132701
132805
  }
@@ -133715,6 +133819,12 @@ function collectDeclarations(ctx, sourceFile, isEntryFile = true) {
133715
133819
  }
133716
133820
  }
133717
133821
  }
133822
+ if (decl.initializer.properties.some((p) => ts.isSpreadAssignment(p))) {
133823
+ const spreadCtxType = ctx.checker.getContextualType(decl.initializer);
133824
+ if (!spreadCtxType || (spreadCtxType.flags & ts.TypeFlags.Any) !== 0 || (spreadCtxType.flags & ts.TypeFlags.Unknown) !== 0 || (spreadCtxType.flags & ts.TypeFlags.NonPrimitive) !== 0 || spreadCtxType.getProperties().length === 0) {
133825
+ return true;
133826
+ }
133827
+ }
133718
133828
  return false;
133719
133829
  }
133720
133830
  function moduleGlobalWasmType(decl, varType) {
@@ -134256,6 +134366,7 @@ function compileDeclarations(ctx, sourceFile) {
134256
134366
  ctx.pendingInitBody = null;
134257
134367
  if (compiledInitFctx && compiledInitFctx.body.length > 0) {
134258
134368
  ctx.mod.hasTopLevelStatements = true;
134369
+ const exportModuleInit = ctx.deferTopLevelInit && !ctx.wasi;
134259
134370
  const initTypeIdx = addFuncType(ctx, [], [], "__module_init_type");
134260
134371
  const initFuncIdx = ctx.numImportFuncs + ctx.mod.functions.length;
134261
134372
  ctx.mod.functions.push({
@@ -134263,9 +134374,15 @@ function compileDeclarations(ctx, sourceFile) {
134263
134374
  typeIdx: initTypeIdx,
134264
134375
  locals: compiledInitFctx.locals,
134265
134376
  body: compiledInitFctx.body,
134266
- exported: false
134377
+ exported: exportModuleInit
134267
134378
  });
134268
- if (!ctx.wasi) {
134379
+ if (exportModuleInit) {
134380
+ ctx.mod.exports.push({
134381
+ name: "__module_init",
134382
+ desc: { kind: "func", index: initFuncIdx }
134383
+ });
134384
+ }
134385
+ if (!ctx.wasi && !exportModuleInit) {
134269
134386
  ctx.mod.startFuncIdx = initFuncIdx;
134270
134387
  }
134271
134388
  }
@@ -134976,6 +135093,7 @@ function generateModule(ast, options) {
134976
135093
  fillExternGetIdxVecArms(ctx);
134977
135094
  fillArrayToPrimitive(ctx);
134978
135095
  emitIsClosureExport(ctx);
135096
+ emitIsDataStructExport(ctx);
134979
135097
  fillStandaloneTypeofClosureArms(ctx);
134980
135098
  emitToPrimitiveMethodExports(ctx);
134981
135099
  fillClassToPrimitive(ctx);
@@ -134991,6 +135109,7 @@ function generateModule(ast, options) {
134991
135109
  });
134992
135110
  }
134993
135111
  ensureDynReadHelpers(ctx);
135112
+ finalizeInModuleInitFlag(ctx);
134994
135113
  markLeafStructsFinal(mod, ctx.wasi);
134995
135114
  eliminateDeadImports(mod, ctx);
134996
135115
  repairStructTypeMismatches(mod);
@@ -135012,7 +135131,7 @@ function generateModule(ast, options) {
135012
135131
  }
135013
135132
  function assertNoLeakedHostImports(ctx, mod) {
135014
135133
  if (!ctx.strictNoHostImports) return;
135015
- const leaks = scanForLeakedHostImports(mod.imports);
135134
+ const leaks = scanForLeakedHostImports(mod.imports, ctx.linkedNamespaces);
135016
135135
  for (const leak of leaks) {
135017
135136
  reportErrorNoNode(ctx, buildLeakedHostImportError(leak));
135018
135137
  }
@@ -135029,6 +135148,35 @@ function drainStackBalanceTelemetry(ctx, fileLabel) {
135029
135148
  ctx.errors.push({ message: diag.message, line: diag.line, column: diag.column, severity: diag.severity });
135030
135149
  }
135031
135150
  }
135151
+ function finalizeInModuleInitFlag(ctx) {
135152
+ const reads = ctx.inModuleInitFlagReads;
135153
+ if (!reads || reads.length === 0) return;
135154
+ const flagIdx = ctx.numImportGlobals + ctx.mod.globals.length;
135155
+ ctx.mod.globals.push({
135156
+ name: "__in_module_init",
135157
+ type: { kind: "i32" },
135158
+ mutable: true,
135159
+ init: [{ op: "i32.const", value: 0 }]
135160
+ });
135161
+ ctx.inModuleInitGlobalIdx = flagIdx;
135162
+ for (const r of reads) r.index = flagIdx;
135163
+ let initArrayIdx = -1;
135164
+ for (let i = 0; i < ctx.mod.functions.length; i++) {
135165
+ if (ctx.mod.functions[i].name === "__module_init") {
135166
+ initArrayIdx = i;
135167
+ break;
135168
+ }
135169
+ }
135170
+ if (initArrayIdx < 0) return;
135171
+ const initFn = ctx.mod.functions[initArrayIdx];
135172
+ initFn.body = [
135173
+ { op: "i32.const", value: 1 },
135174
+ { op: "global.set", index: flagIdx },
135175
+ ...initFn.body,
135176
+ { op: "i32.const", value: 0 },
135177
+ { op: "global.set", index: flagIdx }
135178
+ ];
135179
+ }
135032
135180
  function applyModuleInitGuard(ctx) {
135033
135181
  if (ctx.moduleInitGuardApplied) return;
135034
135182
  let initArrayIdx = -1;
@@ -136196,6 +136344,50 @@ function emitIsClosureExport(ctx) {
136196
136344
  desc: { kind: "func", index: funcIdx }
136197
136345
  });
136198
136346
  }
136347
+ function emitIsDataStructExport(ctx) {
136348
+ const mod = ctx.mod;
136349
+ const dataTypeIdxs = [];
136350
+ const seen = /* @__PURE__ */ new Set();
136351
+ for (const [structName] of ctx.structFields) {
136352
+ if (structName.startsWith("Wrapper") || structName === "$AnyValue" || structName.startsWith("__vec_") || structName.startsWith("__arr_"))
136353
+ continue;
136354
+ const typeIdx = ctx.structMap.get(structName);
136355
+ if (typeIdx === void 0 || seen.has(typeIdx)) continue;
136356
+ const typeDef = mod.types[typeIdx];
136357
+ if (!typeDef || typeDef.kind !== "struct") continue;
136358
+ seen.add(typeIdx);
136359
+ dataTypeIdxs.push(typeIdx);
136360
+ }
136361
+ if (dataTypeIdxs.length === 0) return;
136362
+ const isDataTypeIdx = addFuncType(ctx, [{ kind: "externref" }], [{ kind: "i32" }], "$is_data_struct_type");
136363
+ const funcIdx = ctx.numImportFuncs + mod.functions.length;
136364
+ const body = [
136365
+ { op: "local.get", index: 0 },
136366
+ { op: "any.convert_extern" },
136367
+ { op: "local.set", index: 1 }
136368
+ ];
136369
+ for (const dataType of dataTypeIdxs) {
136370
+ body.push({ op: "local.get", index: 1 });
136371
+ body.push({ op: "ref.test", typeIdx: dataType });
136372
+ body.push({
136373
+ op: "if",
136374
+ blockType: { kind: "empty" },
136375
+ then: [{ op: "i32.const", value: 1 }, { op: "return" }]
136376
+ });
136377
+ }
136378
+ body.push({ op: "i32.const", value: 0 });
136379
+ mod.functions.push({
136380
+ name: "__is_data_struct",
136381
+ typeIdx: isDataTypeIdx,
136382
+ locals: [{ name: "__any", type: { kind: "anyref" } }],
136383
+ body,
136384
+ exported: true
136385
+ });
136386
+ mod.exports.push({
136387
+ name: "__is_data_struct",
136388
+ desc: { kind: "func", index: funcIdx }
136389
+ });
136390
+ }
136199
136391
  function fillStandaloneTypeofClosureArms(ctx) {
136200
136392
  if (!ctx.nativeStrings) return;
136201
136393
  const baseTypeIdxs = collectClosureBaseWrapperTypeIdxs(ctx);
@@ -136449,6 +136641,19 @@ function emitToPrimitiveMethodExports(ctx) {
136449
136641
  emitDispatchForMethod("toString", "__call_toString");
136450
136642
  emitDispatchForMethod("valueOf", "__call_valueOf");
136451
136643
  }
136644
+ function reserveVecMethodHelper(ctx, kind) {
136645
+ const name = kind === "push" ? "__vec_push" : kind === "pop" ? "__vec_pop" : "__vec_get";
136646
+ const existing = ctx.funcMap.get(name);
136647
+ if (existing !== void 0) return existing;
136648
+ const typeIdx = kind === "push" ? addFuncType(ctx, [{ kind: "externref" }, { kind: "externref" }], [{ kind: "i32" }], "$__vec_push_type") : kind === "pop" ? addFuncType(ctx, [{ kind: "externref" }], [{ kind: "externref" }], "$__vec_pop_type") : addFuncType(ctx, [{ kind: "externref" }, { kind: "i32" }], [{ kind: "externref" }], "$__vec_get_type");
136649
+ const idx = ctx.numImportFuncs + ctx.mod.functions.length;
136650
+ const placeholder = kind === "push" ? [{ op: "i32.const", value: 0 }] : [{ op: "ref.null.extern" }];
136651
+ ctx.mod.functions.push({ name, typeIdx, locals: [], body: placeholder, exported: true });
136652
+ ctx.mod.exports.push({ name, desc: { kind: "func", index: idx } });
136653
+ ctx.funcMap.set(name, idx);
136654
+ ctx.usesVecValue = true;
136655
+ return idx;
136656
+ }
136452
136657
  function emitVecAccessExports(ctx) {
136453
136658
  if (!ctx.funcMap.has("__iterator") && !ctx.funcMap.has("JSON_stringify") && !ctx.funcMap.has("__make_iterable") && !ctx.funcMap.has("Promise_all") && !ctx.funcMap.has("Promise_race") && !ctx.funcMap.has("Promise_allSettled") && !ctx.funcMap.has("Promise_any") && !ctx.funcMap.has("__crypto_get_random_values") && // (#1503)
136454
136659
  !ctx.funcMap.has("__extern_get") && !ctx.usesVecValue) {
@@ -136609,24 +136814,29 @@ function _emitVecAccessExportsInner(ctx) {
136609
136814
  ];
136610
136815
  }
136611
136816
  body.push(...current);
136612
- mod.functions.push({
136613
- name: "__vec_get",
136614
- typeIdx: getTypeIdx,
136615
- // local 2 = __any (anyref). (#2001 S1 regress) When the module has holes,
136616
- // local 3 = __hole_scratch (externref) backs the `$Hole → undefined`
136617
- // read-boundary map (`local.tee 3` above). Declared ONLY then, so a
136618
- // hole-free module's `__vec_get` is byte-identical to pre-fix.
136619
- locals: holeMapInVecGet ? [
136620
- { name: "__any", type: { kind: "anyref" } },
136621
- { name: "__hole_scratch", type: { kind: "externref" } }
136622
- ] : [{ name: "__any", type: { kind: "anyref" } }],
136623
- body,
136624
- exported: true
136625
- });
136626
- mod.exports.push({
136627
- name: "__vec_get",
136628
- desc: { kind: "func", index: getFuncIdx }
136629
- });
136817
+ const getLocals = holeMapInVecGet ? [
136818
+ { name: "__any", type: { kind: "anyref" } },
136819
+ { name: "__hole_scratch", type: { kind: "externref" } }
136820
+ ] : [{ name: "__any", type: { kind: "anyref" } }];
136821
+ const reservedGet = ctx.funcMap.get("__vec_get");
136822
+ if (reservedGet !== void 0) {
136823
+ const fn = mod.functions[reservedGet - ctx.numImportFuncs];
136824
+ fn.locals = getLocals;
136825
+ fn.body = body;
136826
+ } else {
136827
+ mod.functions.push({
136828
+ name: "__vec_get",
136829
+ typeIdx: getTypeIdx,
136830
+ locals: getLocals,
136831
+ body,
136832
+ exported: true
136833
+ });
136834
+ mod.exports.push({
136835
+ name: "__vec_get",
136836
+ desc: { kind: "func", index: getFuncIdx }
136837
+ });
136838
+ ctx.funcMap.set("__vec_get", getFuncIdx);
136839
+ }
136630
136840
  }
136631
136841
  const unboxNumIdx = ctx.funcMap.get("__unbox_number");
136632
136842
  const boxNumIdx2 = ctx.funcMap.get("__box_number");
@@ -136820,14 +137030,22 @@ function _emitVecAccessExportsInner(ctx) {
136820
137030
  ];
136821
137031
  }
136822
137032
  body.push(...current);
136823
- mod.functions.push({
136824
- name: "__vec_push",
136825
- typeIdx: pushTypeIdx,
136826
- locals,
136827
- body,
136828
- exported: true
136829
- });
136830
- mod.exports.push({ name: "__vec_push", desc: { kind: "func", index: pushFuncIdx } });
137033
+ const reservedPush = ctx.funcMap.get("__vec_push");
137034
+ if (reservedPush !== void 0) {
137035
+ const fn = mod.functions[reservedPush - ctx.numImportFuncs];
137036
+ fn.locals = locals;
137037
+ fn.body = body;
137038
+ } else {
137039
+ mod.functions.push({
137040
+ name: "__vec_push",
137041
+ typeIdx: pushTypeIdx,
137042
+ locals,
137043
+ body,
137044
+ exported: true
137045
+ });
137046
+ mod.exports.push({ name: "__vec_push", desc: { kind: "func", index: pushFuncIdx } });
137047
+ ctx.funcMap.set("__vec_push", pushFuncIdx);
137048
+ }
136831
137049
  }
136832
137050
  {
136833
137051
  const popTypeIdx = addFuncType(ctx, [{ kind: "externref" }], [{ kind: "externref" }], "$__vec_pop_type");
@@ -136895,14 +137113,22 @@ function _emitVecAccessExportsInner(ctx) {
136895
137113
  ];
136896
137114
  }
136897
137115
  body.push(...current);
136898
- mod.functions.push({
136899
- name: "__vec_pop",
136900
- typeIdx: popTypeIdx,
136901
- locals,
136902
- body,
136903
- exported: true
136904
- });
136905
- mod.exports.push({ name: "__vec_pop", desc: { kind: "func", index: popFuncIdx } });
137116
+ const reservedPop = ctx.funcMap.get("__vec_pop");
137117
+ if (reservedPop !== void 0) {
137118
+ const fn = mod.functions[reservedPop - ctx.numImportFuncs];
137119
+ fn.locals = locals;
137120
+ fn.body = body;
137121
+ } else {
137122
+ mod.functions.push({
137123
+ name: "__vec_pop",
137124
+ typeIdx: popTypeIdx,
137125
+ locals,
137126
+ body,
137127
+ exported: true
137128
+ });
137129
+ mod.exports.push({ name: "__vec_pop", desc: { kind: "func", index: popFuncIdx } });
137130
+ ctx.funcMap.set("__vec_pop", popFuncIdx);
137131
+ }
136906
137132
  }
136907
137133
  }
136908
137134
  function emitVecSetByteExport(ctx) {
@@ -137371,6 +137597,7 @@ function generateMultiModule(multiAst, options) {
137371
137597
  emitClosureCallExport(ctx);
137372
137598
  emitClosureCallExport1(ctx);
137373
137599
  emitIsClosureExport(ctx);
137600
+ emitIsDataStructExport(ctx);
137374
137601
  fillStandaloneTypeofClosureArms(ctx);
137375
137602
  emitToPrimitiveMethodExports(ctx);
137376
137603
  emitToPrimitiveMethodExport(ctx);
@@ -137386,6 +137613,7 @@ function generateMultiModule(multiAst, options) {
137386
137613
  });
137387
137614
  }
137388
137615
  ensureDynReadHelpers(ctx);
137616
+ finalizeInModuleInitFlag(ctx);
137389
137617
  markLeafStructsFinal(mod, ctx.wasi);
137390
137618
  eliminateDeadImports(mod, ctx);
137391
137619
  repairStructTypeMismatches(mod);
@@ -139117,6 +139345,10 @@ function addUnionImports(ctx) {
139117
139345
  kind: "func",
139118
139346
  typeIdx: boxBoolType
139119
139347
  });
139348
+ addImport(ctx, "env", "__box_symbol", {
139349
+ kind: "func",
139350
+ typeIdx: boxBoolType
139351
+ });
139120
139352
  const boxBigType = addFuncType(ctx, [{ kind: "i64" }], [{ kind: "externref" }]);
139121
139353
  addImport(ctx, "env", "__box_bigint", { kind: "func", typeIdx: boxBigType });
139122
139354
  const toBigType = addFuncType(ctx, [{ kind: "externref" }], [{ kind: "i64" }]);
@@ -139165,6 +139397,7 @@ function addUnionImports(ctx) {
139165
139397
  "__unbox_boolean",
139166
139398
  "__box_number",
139167
139399
  "__box_boolean",
139400
+ "__box_symbol",
139168
139401
  "__box_bigint",
139169
139402
  "__to_bigint",
139170
139403
  "__bigint_ctor",
@@ -140763,7 +140996,7 @@ function collectExternClass(ctx, decl, namespacePath) {
140763
140996
  if (!p.questionToken && !p.initializer) requiredParams++;
140764
140997
  }
140765
140998
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
140766
- const results = isVoidType(retType) ? [] : [mapTsTypeToWasm(retType, ctx.checker)];
140999
+ const results = isVoidType(retType) ? [] : [brandExternMethodResult(ctx, retType, mapTsTypeToWasm(retType, ctx.checker))];
140767
141000
  info.methods.set(methodName, { params, results, requiredParams });
140768
141001
  }
140769
141002
  }
@@ -140877,7 +141110,7 @@ function collectInterfaceMembers(ctx, iface, info, locationNode) {
140877
141110
  if (!p.questionToken && !p.initializer) requiredParams++;
140878
141111
  }
140879
141112
  const retType = ctx.checker.getReturnTypeOfSignature(sig);
140880
- const results = isVoidType(retType) ? [] : [mapTsTypeToWasm(retType, ctx.checker)];
141113
+ const results = isVoidType(retType) ? [] : [brandExternMethodResult(ctx, retType, mapTsTypeToWasm(retType, ctx.checker))];
140881
141114
  info.methods.set(methodName, { params, results, requiredParams });
140882
141115
  }
140883
141116
  }
@@ -141421,6 +141654,11 @@ function hoistVarDecl(ctx, fctx, decl) {
141421
141654
  }
141422
141655
  }
141423
141656
  }
141657
+ if (!initForcesExternref && decl.initializer.properties.some((p) => ts.isSpreadAssignment(p))) {
141658
+ const spreadCtxType = ctx.checker.getContextualType(decl.initializer);
141659
+ const nonSpecificCtx = !spreadCtxType || (spreadCtxType.flags & ts.TypeFlags.Any) !== 0 || (spreadCtxType.flags & ts.TypeFlags.Unknown) !== 0 || (spreadCtxType.flags & ts.TypeFlags.NonPrimitive) !== 0 || spreadCtxType.getProperties().length === 0;
141660
+ if (nonSpecificCtx) initForcesExternref = true;
141661
+ }
141424
141662
  }
141425
141663
  const wasmType = initForcesExternref || isNullablePrimitiveType(varType) ? { kind: "externref" } : resolveWasmType(ctx, varType);
141426
141664
  if (initForcesExternref) ctx.externrefAccessorVars.add(name);
@@ -141728,10 +141966,15 @@ function walkStmtForLetConst(ctx, fctx, stmt) {
141728
141966
  const varType = ctx.checker.getTypeAtLocation(decl);
141729
141967
  const isI32Coerced = fctx.i32CoercedLocals?.has(name) === true && (varType.flags & ts.TypeFlags.NumberLike) !== 0;
141730
141968
  const initIsAccessorLiteral = decl.initializer !== void 0 && ts.isObjectLiteralExpression(decl.initializer) && decl.initializer.properties.some((p) => ts.isGetAccessorDeclaration(p) || ts.isSetAccessorDeclaration(p));
141731
- if (initIsAccessorLiteral) {
141969
+ let initIsHostSpreadLiteral = false;
141970
+ if (!initIsAccessorLiteral && decl.initializer !== void 0 && ts.isObjectLiteralExpression(decl.initializer) && decl.initializer.properties.some((p) => ts.isSpreadAssignment(p))) {
141971
+ const spreadCtxType = ctx.checker.getContextualType(decl.initializer);
141972
+ initIsHostSpreadLiteral = !spreadCtxType || (spreadCtxType.flags & ts.TypeFlags.Any) !== 0 || (spreadCtxType.flags & ts.TypeFlags.Unknown) !== 0 || (spreadCtxType.flags & ts.TypeFlags.NonPrimitive) !== 0 || spreadCtxType.getProperties().length === 0;
141973
+ }
141974
+ if (initIsAccessorLiteral || initIsHostSpreadLiteral) {
141732
141975
  ctx.externrefAccessorVars.add(name);
141733
141976
  }
141734
- const wasmType = initIsAccessorLiteral ? { kind: "externref" } : isI32Coerced ? { kind: "i32" } : isNullablePrimitiveType(varType) ? { kind: "externref" } : inferLetConstInitializerWasmType(ctx, fctx, decl.initializer) ?? resolveWasmType(ctx, varType);
141977
+ const wasmType = initIsAccessorLiteral || initIsHostSpreadLiteral ? { kind: "externref" } : isI32Coerced ? { kind: "i32" } : isNullablePrimitiveType(varType) ? { kind: "externref" } : inferLetConstInitializerWasmType(ctx, fctx, decl.initializer) ?? resolveWasmType(ctx, varType);
141735
141978
  allocLocal(fctx, name, wasmType);
141736
141979
  if (needsTdzFlag(ctx, decl)) {
141737
141980
  if (!fctx.tdzFlagLocals) fctx.tdzFlagLocals = /* @__PURE__ */ new Map();
@@ -141894,6 +142137,448 @@ function ensureI32Condition(fctx, condType, ctx) {
141894
142137
  fctx.body.push({ op: "i32.eqz" });
141895
142138
  }
141896
142139
  }
142140
+ const EMPTY_RESULT = {
142141
+ sites: /* @__PURE__ */ new Map(),
142142
+ approved: /* @__PURE__ */ new Set(),
142143
+ approvedNames: /* @__PURE__ */ new Set(),
142144
+ receiverStruct: /* @__PURE__ */ new Map(),
142145
+ newThisOwnerNames: /* @__PURE__ */ new Set(),
142146
+ ctorDeclByName: /* @__PURE__ */ new Map()
142147
+ };
142148
+ function fnctorDeclFromSymbol(sym) {
142149
+ for (const decl of sym.getDeclarations() ?? []) {
142150
+ if (ts.isFunctionDeclaration(decl) && decl.body) return decl;
142151
+ if (ts.isFunctionExpression(decl) && decl.body) return decl;
142152
+ if (ts.isVariableDeclaration(decl) && decl.initializer) {
142153
+ let init = decl.initializer;
142154
+ while (ts.isParenthesizedExpression(init)) init = init.expression;
142155
+ if (ts.isFunctionExpression(init) && init.body) return init;
142156
+ }
142157
+ }
142158
+ return void 0;
142159
+ }
142160
+ const RETURN_INFER_MAX_DEPTH = 6;
142161
+ const GENERIC_METHOD_CALL = /* @__PURE__ */ new Set(["call", "apply", "bind"]);
142162
+ function resolveFnctorSymbol(checker, calleeExpr) {
142163
+ let e = calleeExpr;
142164
+ while (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isNonNullExpression(e)) {
142165
+ e = e.expression;
142166
+ }
142167
+ if (!ts.isIdentifier(e)) return void 0;
142168
+ const sym = checker.getSymbolAtLocation(e);
142169
+ const decls = sym?.getDeclarations();
142170
+ if (!sym || !decls) return void 0;
142171
+ for (const decl of decls) {
142172
+ if (ts.isClassDeclaration(decl) || ts.isClassExpression(decl)) return void 0;
142173
+ if (ts.isFunctionDeclaration(decl) && decl.body) return sym;
142174
+ if (ts.isFunctionExpression(decl) && decl.body) return sym;
142175
+ if (ts.isVariableDeclaration(decl) && decl.initializer) {
142176
+ let init = decl.initializer;
142177
+ while (ts.isParenthesizedExpression(init)) init = init.expression;
142178
+ if (ts.isFunctionExpression(init) && init.body) return sym;
142179
+ if (ts.isArrowFunction(init)) return void 0;
142180
+ }
142181
+ }
142182
+ return void 0;
142183
+ }
142184
+ function resolveEnclosingFnctorOwner(checker, node) {
142185
+ let fn = node;
142186
+ while (fn && !ts.isFunctionExpression(fn) && !ts.isFunctionDeclaration(fn)) {
142187
+ fn = fn.parent;
142188
+ }
142189
+ if (!fn) return void 0;
142190
+ const assign = fn.parent;
142191
+ if (!ts.isBinaryExpression(assign) || assign.operatorToken.kind !== ts.SyntaxKind.EqualsToken || assign.right !== fn || !ts.isPropertyAccessExpression(assign.left)) {
142192
+ return void 0;
142193
+ }
142194
+ const left = assign.left;
142195
+ if (ts.isPropertyAccessExpression(left.expression) && ts.isIdentifier(left.expression.name) && left.expression.name.text === "prototype") {
142196
+ const sym = resolveFnctorSymbol(checker, left.expression.expression);
142197
+ if (sym) return { name: sym.name, sym, viaPrototype: true };
142198
+ return void 0;
142199
+ }
142200
+ const holder = left.expression;
142201
+ const direct = resolveFnctorSymbol(checker, holder);
142202
+ if (direct) return { name: direct.name, sym: direct, viaPrototype: false };
142203
+ if (ts.isIdentifier(holder)) {
142204
+ const hsym = checker.getSymbolAtLocation(holder);
142205
+ for (const decl of hsym?.getDeclarations() ?? []) {
142206
+ if (ts.isVariableDeclaration(decl) && decl.initializer) {
142207
+ let init = decl.initializer;
142208
+ while (ts.isParenthesizedExpression(init)) init = init.expression;
142209
+ if (ts.isPropertyAccessExpression(init) && ts.isIdentifier(init.name) && init.name.text === "prototype") {
142210
+ const fsym = resolveFnctorSymbol(checker, init.expression);
142211
+ if (fsym) return { name: fsym.name, sym: fsym, viaPrototype: true };
142212
+ }
142213
+ }
142214
+ }
142215
+ }
142216
+ return void 0;
142217
+ }
142218
+ function resolveLiftedMethodThisStruct(ctx, fn) {
142219
+ const owner = resolveEnclosingFnctorOwner(ctx.checker, fn);
142220
+ if (!owner || !owner.viaPrototype) return void 0;
142221
+ if (!ctx.fnctorEscapeGate?.approvedNames.has(owner.name)) return void 0;
142222
+ return `__fnctor_${owner.name}`;
142223
+ }
142224
+ function collectFnctorOwnFields(ctorSym) {
142225
+ const fields = /* @__PURE__ */ new Set();
142226
+ const decls = ctorSym.getDeclarations() ?? [];
142227
+ for (const decl of decls) {
142228
+ let body;
142229
+ if ((ts.isFunctionDeclaration(decl) || ts.isFunctionExpression(decl)) && decl.body) body = decl.body;
142230
+ else if (ts.isVariableDeclaration(decl) && decl.initializer) {
142231
+ let init = decl.initializer;
142232
+ while (ts.isParenthesizedExpression(init)) init = init.expression;
142233
+ if (ts.isFunctionExpression(init) && init.body) body = init.body;
142234
+ }
142235
+ if (!body) continue;
142236
+ const walk = (node) => {
142237
+ if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(node.left) && node.left.expression.kind === ts.SyntaxKind.ThisKeyword) {
142238
+ fields.add(node.left.name.text);
142239
+ }
142240
+ forEachChild$1(node, walk);
142241
+ };
142242
+ walk(body);
142243
+ }
142244
+ return fields;
142245
+ }
142246
+ function classifyUse(checker, idNode, ownFields) {
142247
+ const parent = idNode.parent;
142248
+ if (ts.isPropertyAccessExpression(parent) && parent.expression === idNode) {
142249
+ const name = parent.name.text;
142250
+ if (ownFields.has(name)) return "typed";
142251
+ return "dynamic";
142252
+ }
142253
+ if (ts.isElementAccessExpression(parent) && parent.expression === idNode) {
142254
+ return "dynamic";
142255
+ }
142256
+ if (ts.isCallExpression(parent) && parent.arguments.length > 0 && parent.arguments[0] === idNode) {
142257
+ const callee = parent.expression;
142258
+ if (ts.isPropertyAccessExpression(callee) && GENERIC_METHOD_CALL.has(callee.name.text)) {
142259
+ return "dynamic";
142260
+ }
142261
+ }
142262
+ if (ts.isCallExpression(parent)) {
142263
+ const argIdx = parent.arguments.indexOf(idNode);
142264
+ if (argIdx >= 0) {
142265
+ const sig = checker.getResolvedSignature(parent);
142266
+ const paramSym = sig?.parameters[argIdx];
142267
+ if (paramSym) {
142268
+ const pType = checker.getTypeOfSymbolAtLocation(paramSym, idNode);
142269
+ if (isAnyOrUnknown(pType)) return "dynamic";
142270
+ }
142271
+ return "neutral";
142272
+ }
142273
+ }
142274
+ if (ts.isReturnStatement(parent)) {
142275
+ return "neutral";
142276
+ }
142277
+ return "neutral";
142278
+ }
142279
+ function isAnyOrUnknown(t) {
142280
+ return (t.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0;
142281
+ }
142282
+ function bindingOf(newExpr) {
142283
+ const parent = newExpr.parent;
142284
+ if (ts.isVariableDeclaration(parent) && parent.initializer === newExpr && ts.isIdentifier(parent.name)) {
142285
+ return parent.name;
142286
+ }
142287
+ return void 0;
142288
+ }
142289
+ function unwrapExpr(e) {
142290
+ let cur = e;
142291
+ while (ts.isParenthesizedExpression(cur) || ts.isAsExpression(cur) || ts.isNonNullExpression(cur)) {
142292
+ cur = cur.expression;
142293
+ }
142294
+ return cur;
142295
+ }
142296
+ function isFunctionLike(node) {
142297
+ return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node);
142298
+ }
142299
+ function buildProtoMethodIndex(sourceFile) {
142300
+ const idx = /* @__PURE__ */ new Map();
142301
+ const walk = (n) => {
142302
+ if (ts.isBinaryExpression(n) && n.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(n.left)) {
142303
+ const rhs = unwrapExpr(n.right);
142304
+ if (isFunctionLike(rhs)) {
142305
+ const name = n.left.name.text;
142306
+ const arr = idx.get(name);
142307
+ if (arr) arr.push(rhs);
142308
+ else idx.set(name, [rhs]);
142309
+ }
142310
+ }
142311
+ forEachChild$1(n, walk);
142312
+ };
142313
+ walk(sourceFile);
142314
+ return idx;
142315
+ }
142316
+ function resolveCalleeFunction(checker, callExpr, protoIndex) {
142317
+ const callee = unwrapExpr(callExpr.expression);
142318
+ let sym;
142319
+ if (ts.isPropertyAccessExpression(callee)) {
142320
+ sym = checker.getSymbolAtLocation(callee.name) ?? checker.getSymbolAtLocation(callee);
142321
+ } else if (ts.isIdentifier(callee)) {
142322
+ sym = checker.getSymbolAtLocation(callee);
142323
+ }
142324
+ if (sym) {
142325
+ for (const decl of sym.getDeclarations() ?? []) {
142326
+ const fn = functionFromDeclaration(decl);
142327
+ if (fn?.body) return fn;
142328
+ }
142329
+ }
142330
+ if (ts.isPropertyAccessExpression(callee)) {
142331
+ const cands = protoIndex.get(callee.name.text);
142332
+ if (cands && cands.length === 1 && cands[0].body) return cands[0];
142333
+ }
142334
+ return void 0;
142335
+ }
142336
+ function functionFromDeclaration(decl) {
142337
+ if (isFunctionLike(decl)) return decl;
142338
+ if (ts.isVariableDeclaration(decl) && decl.initializer) {
142339
+ const init = unwrapExpr(decl.initializer);
142340
+ if (isFunctionLike(init)) return init;
142341
+ return void 0;
142342
+ }
142343
+ if (ts.isPropertyAssignment(decl)) {
142344
+ const init = unwrapExpr(decl.initializer);
142345
+ if (isFunctionLike(init)) return init;
142346
+ return void 0;
142347
+ }
142348
+ if (ts.isMethodDeclaration(decl)) return decl;
142349
+ if (ts.isPropertyAccessExpression(decl) || ts.isElementAccessExpression(decl)) {
142350
+ const parent = decl.parent;
142351
+ if (ts.isBinaryExpression(parent) && parent.operatorToken.kind === ts.SyntaxKind.EqualsToken && parent.left === decl) {
142352
+ const rhs = unwrapExpr(parent.right);
142353
+ if (isFunctionLike(rhs)) return rhs;
142354
+ }
142355
+ }
142356
+ return void 0;
142357
+ }
142358
+ function singleReturnExpr(fn) {
142359
+ const body = fn.body;
142360
+ if (!body) return void 0;
142361
+ if (!ts.isBlock(body)) return body;
142362
+ const returns = [];
142363
+ const walk = (n) => {
142364
+ if (ts.isReturnStatement(n)) {
142365
+ if (n.expression) returns.push(n.expression);
142366
+ return;
142367
+ }
142368
+ if (isFunctionLike(n)) return;
142369
+ forEachChild$1(n, walk);
142370
+ };
142371
+ walk(body);
142372
+ return returns.length === 1 ? returns[0] : void 0;
142373
+ }
142374
+ function inferReturnStruct(checker, fn, depth, memo, protoIndex) {
142375
+ if (memo.has(fn)) return memo.get(fn);
142376
+ if (depth <= 0) return void 0;
142377
+ memo.set(fn, void 0);
142378
+ const ret2 = singleReturnExpr(fn);
142379
+ let result;
142380
+ if (ret2) {
142381
+ const r = unwrapExpr(ret2);
142382
+ if (ts.isNewExpression(r)) {
142383
+ let ctorSym = resolveFnctorSymbol(checker, r.expression);
142384
+ if (!ctorSym && r.expression.kind === ts.SyntaxKind.ThisKeyword) {
142385
+ ctorSym = resolveEnclosingFnctorOwner(checker, r)?.sym;
142386
+ }
142387
+ if (ctorSym) result = `__fnctor_${ctorSym.name}`;
142388
+ } else if (ts.isCallExpression(r)) {
142389
+ const callee = resolveCalleeFunction(checker, r, protoIndex);
142390
+ if (callee) result = inferReturnStruct(checker, callee, depth - 1, memo, protoIndex);
142391
+ }
142392
+ }
142393
+ memo.set(fn, result);
142394
+ return result;
142395
+ }
142396
+ function buildReceiverStructMap(checker, sourceFile, usesBySymbol) {
142397
+ const map = /* @__PURE__ */ new Map();
142398
+ const memo = /* @__PURE__ */ new Map();
142399
+ const protoIndex = buildProtoMethodIndex(sourceFile);
142400
+ const visit = (node) => {
142401
+ if (ts.isVariableDeclaration(node) && node.initializer && ts.isIdentifier(node.name)) {
142402
+ const init = unwrapExpr(node.initializer);
142403
+ let struct;
142404
+ if (ts.isCallExpression(init)) {
142405
+ const callee = resolveCalleeFunction(checker, init, protoIndex);
142406
+ struct = callee ? inferReturnStruct(checker, callee, RETURN_INFER_MAX_DEPTH, memo, protoIndex) : void 0;
142407
+ } else if (ts.isNewExpression(init)) {
142408
+ let ctorSym = resolveFnctorSymbol(checker, init.expression);
142409
+ if (!ctorSym && init.expression.kind === ts.SyntaxKind.ThisKeyword) {
142410
+ ctorSym = resolveEnclosingFnctorOwner(checker, init)?.sym;
142411
+ }
142412
+ struct = ctorSym ? `__fnctor_${ctorSym.name}` : void 0;
142413
+ }
142414
+ if (struct) {
142415
+ const bindSym = checker.getSymbolAtLocation(node.name);
142416
+ const uses = bindSym ? usesBySymbol.get(bindSym) ?? [] : [];
142417
+ for (const use of uses) {
142418
+ if (use === node.name) continue;
142419
+ map.set(use, struct);
142420
+ }
142421
+ }
142422
+ }
142423
+ forEachChild$1(node, visit);
142424
+ };
142425
+ visit(sourceFile);
142426
+ return map;
142427
+ }
142428
+ function resolveReceiverStruct(ctx, fctx, recvExpr) {
142429
+ const recv = unwrapExpr(recvExpr);
142430
+ let name;
142431
+ if (recv.kind === ts.SyntaxKind.ThisKeyword) {
142432
+ name = fctx.thisStructName;
142433
+ } else {
142434
+ name = ctx.fnctorEscapeGate?.receiverStruct.get(recv);
142435
+ }
142436
+ if (name !== void 0 && ctx.structMap.has(name)) return name;
142437
+ return void 0;
142438
+ }
142439
+ function analyzeFnctorEscapeGate(checker, sourceFile) {
142440
+ const sites = /* @__PURE__ */ new Map();
142441
+ const approved = /* @__PURE__ */ new Set();
142442
+ const approvedNames = /* @__PURE__ */ new Set();
142443
+ const newSites = [];
142444
+ const newThisSites = /* @__PURE__ */ new Set();
142445
+ const collect = (node) => {
142446
+ if (ts.isNewExpression(node)) {
142447
+ let ctorSym = resolveFnctorSymbol(checker, node.expression);
142448
+ if (!ctorSym && node.expression.kind === ts.SyntaxKind.ThisKeyword) {
142449
+ const owner = resolveEnclosingFnctorOwner(checker, node);
142450
+ if (owner) {
142451
+ ctorSym = owner.sym;
142452
+ newThisSites.add(node);
142453
+ }
142454
+ }
142455
+ if (ctorSym) newSites.push({ newExpr: node, ctorSym });
142456
+ }
142457
+ forEachChild$1(node, collect);
142458
+ };
142459
+ collect(sourceFile);
142460
+ if (newSites.length === 0) return EMPTY_RESULT;
142461
+ const ctorDeclByName = /* @__PURE__ */ new Map();
142462
+ for (const { ctorSym } of newSites) {
142463
+ if (ctorDeclByName.has(ctorSym.name)) continue;
142464
+ const decl = fnctorDeclFromSymbol(ctorSym);
142465
+ if (decl) ctorDeclByName.set(ctorSym.name, decl);
142466
+ }
142467
+ const usesBySymbol = /* @__PURE__ */ new Map();
142468
+ const indexUses = (node) => {
142469
+ if (ts.isIdentifier(node)) {
142470
+ const sym = checker.getSymbolAtLocation(node);
142471
+ if (sym) {
142472
+ const arr = usesBySymbol.get(sym);
142473
+ if (arr) arr.push(node);
142474
+ else usesBySymbol.set(sym, [node]);
142475
+ }
142476
+ }
142477
+ forEachChild$1(node, indexUses);
142478
+ };
142479
+ indexUses(sourceFile);
142480
+ const newThisOwnerNames = /* @__PURE__ */ new Set();
142481
+ for (const { newExpr, ctorSym } of newSites) {
142482
+ const ownFields = collectFnctorOwnFields(ctorSym);
142483
+ let sawDynamic = false;
142484
+ let sawTyped = false;
142485
+ const bind = bindingOf(newExpr);
142486
+ if (bind) {
142487
+ const bindSym = checker.getSymbolAtLocation(bind);
142488
+ const uses = bindSym ? usesBySymbol.get(bindSym) ?? [] : [];
142489
+ for (const use of uses) {
142490
+ if (use === bind) continue;
142491
+ const c = classifyUse(checker, use, ownFields);
142492
+ if (c === "typed") sawTyped = true;
142493
+ else if (c === "dynamic") sawDynamic = true;
142494
+ }
142495
+ } else {
142496
+ let inner = newExpr;
142497
+ let parent = inner.parent;
142498
+ while (ts.isParenthesizedExpression(parent) || ts.isAsExpression(parent) || ts.isNonNullExpression(parent)) {
142499
+ inner = parent;
142500
+ parent = parent.parent;
142501
+ }
142502
+ if (ts.isPropertyAccessExpression(parent) && parent.expression === inner) {
142503
+ if (ownFields.has(parent.name.text)) sawTyped = true;
142504
+ else sawDynamic = true;
142505
+ } else if (ts.isElementAccessExpression(parent) && parent.expression === inner) {
142506
+ sawDynamic = true;
142507
+ } else if (ts.isCallExpression(parent) && parent.arguments.length > 0 && parent.arguments[0] === inner && ts.isPropertyAccessExpression(parent.expression) && GENERIC_METHOD_CALL.has(parent.expression.name.text)) {
142508
+ sawDynamic = true;
142509
+ }
142510
+ }
142511
+ let cls;
142512
+ if (newThisSites.has(newExpr)) cls = "reconstruct";
142513
+ else if (sawTyped) cls = "keep-typed";
142514
+ else if (sawDynamic) cls = "reconstruct";
142515
+ else cls = "keep-static";
142516
+ sites.set(newExpr, cls);
142517
+ if (cls === "reconstruct") {
142518
+ approved.add(newExpr);
142519
+ approvedNames.add(ctorSym.name);
142520
+ if (newThisSites.has(newExpr)) newThisOwnerNames.add(ctorSym.name);
142521
+ }
142522
+ }
142523
+ const receiverStruct = buildReceiverStructMap(checker, sourceFile, usesBySymbol);
142524
+ if (process.env.JS2WASM_LOG_FNCTOR_GATE === "1" && (sites.size > 0 || receiverStruct.size > 0)) {
142525
+ const counts = { reconstruct: 0, "keep-typed": 0, "keep-static": 0 };
142526
+ for (const c of sites.values()) counts[c]++;
142527
+ console.error(
142528
+ `[#2660 fnctor-escape-gate] ${sites.size} new F() site(s): reconstruct=${counts.reconstruct} keep-typed=${counts["keep-typed"]} keep-static=${counts["keep-static"]}; receiverStruct flow-map entries=${receiverStruct.size}`
142529
+ );
142530
+ }
142531
+ return { sites, approved, approvedNames, receiverStruct, newThisOwnerNames, ctorDeclByName };
142532
+ }
142533
+ function deriveFnctorFields(ctx, funcDecl) {
142534
+ const body = funcDecl.body;
142535
+ if (!body) return [];
142536
+ const fields = [];
142537
+ function recordThisField(lhs, valueExpr) {
142538
+ const fieldName = lhs.name.text;
142539
+ if (fields.some((f) => f.name === fieldName)) return;
142540
+ const lhsType = ctx.checker.getTypeAtLocation(lhs);
142541
+ const rhsType = ctx.checker.getTypeAtLocation(valueExpr);
142542
+ const lhsWasm = resolveWasmType(ctx, lhsType);
142543
+ const rhsWasm = resolveWasmType(ctx, rhsType);
142544
+ const fieldType = lhsWasm.kind === "externref" ? rhsWasm : lhsWasm;
142545
+ fields.push({ name: fieldName, type: fieldType, mutable: true });
142546
+ }
142547
+ function collectAssignmentChain(expr) {
142548
+ if (ts.isBinaryExpression(expr) && expr.operatorToken.kind === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(expr.left) && expr.left.expression.kind === ts.SyntaxKind.ThisKeyword) {
142549
+ recordThisField(expr.left, expr.right);
142550
+ collectAssignmentChain(expr.right);
142551
+ }
142552
+ }
142553
+ function collectThisAssignments(stmts) {
142554
+ for (const stmt of stmts) {
142555
+ if (ts.isExpressionStatement(stmt) && ts.isBinaryExpression(stmt.expression)) {
142556
+ collectAssignmentChain(stmt.expression);
142557
+ }
142558
+ if (ts.isIfStatement(stmt)) {
142559
+ if (ts.isBlock(stmt.thenStatement)) {
142560
+ collectThisAssignments(stmt.thenStatement.statements);
142561
+ }
142562
+ if (stmt.elseStatement && ts.isBlock(stmt.elseStatement)) {
142563
+ collectThisAssignments(stmt.elseStatement.statements);
142564
+ }
142565
+ }
142566
+ if ((ts.isForStatement(stmt) || ts.isForInStatement(stmt) || ts.isForOfStatement(stmt) || ts.isWhileStatement(stmt) || ts.isDoStatement(stmt)) && ts.isBlock(stmt.statement)) {
142567
+ collectThisAssignments(stmt.statement.statements);
142568
+ }
142569
+ }
142570
+ }
142571
+ collectThisAssignments(body.statements);
142572
+ for (const field of fields) {
142573
+ if (field.type.kind === "ref") {
142574
+ field.type = {
142575
+ kind: "ref_null",
142576
+ typeIdx: field.type.typeIdx
142577
+ };
142578
+ }
142579
+ }
142580
+ return fields;
142581
+ }
141897
142582
  function isFunctionScopeBoundary(node) {
141898
142583
  return ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node) || ts.isConstructorDeclaration(node);
141899
142584
  }
@@ -142999,7 +143684,15 @@ function compileArrowAsClosure(ctx, fctx, arrow) {
142999
143684
  // which installs the host receiver into `__current_this`. Allow `this`
143000
143685
  // (with no other binding) to read that global. Named functions / methods
143001
143686
  // are NOT lifted here and keep `undefined`/globalObject `this`.
143002
- readsCurrentThis: true
143687
+ readsCurrentThis: true,
143688
+ // (#2681/#2686 A3) When this lifted closure is a fnctor PROTOTYPE method of an
143689
+ // approved-for-reconstruction fnctor (`F.prototype.m = fn` / aliased `var pp =
143690
+ // F.prototype; pp.m = fn`), pin its `this` receiver to `__fnctor_F` so the
143691
+ // dynamic `this.<field>` read dispatch (property-access.ts) routes through the
143692
+ // finalize-filled `__get_member_<name>` struct dispatcher instead of the
143693
+ // host-proxy `__extern_get` (whose externref identity diverges from the stored
143694
+ // native struct → the #2681/#2686 throw).
143695
+ thisStructName: resolveLiftedMethodThisStruct(ctx, arrow)
143003
143696
  };
143004
143697
  ctx.liveBodies.add(liftedFctx.body);
143005
143698
  for (let i = 0; i < liftedFctx.params.length; i++) {
@@ -144869,7 +145562,7 @@ function compileStaticPropIncDec(ctx, fctx, globalIdx, f64Op, mode) {
144869
145562
  fctx.body.push({ op: "local.get", index: mode === "postfix" ? oldTmp : newTmp });
144870
145563
  return { kind: "f64" };
144871
145564
  }
144872
- function emitExternrefMemberIncDec(ctx, fctx, objLocal, propName, f64Op, mode) {
145565
+ function emitExternrefMemberIncDec(ctx, fctx, objLocal, propName, f64Op, mode, pinned) {
144873
145566
  addStringConstantGlobal(ctx, propName);
144874
145567
  const keyResult = compileStringLiteral(ctx, fctx, propName);
144875
145568
  if (keyResult && keyResult.kind !== "externref") {
@@ -144878,16 +145571,21 @@ function emitExternrefMemberIncDec(ctx, fctx, objLocal, propName, f64Op, mode) {
144878
145571
  const keyLocal = allocLocal(fctx, `__incdec_ekey_${fctx.locals.length}`, { kind: "externref" });
144879
145572
  fctx.body.push({ op: "local.set", index: keyLocal });
144880
145573
  fctx.body.push({ op: "local.get", index: objLocal });
144881
- fctx.body.push({ op: "local.get", index: keyLocal });
144882
- const getIdx = ensureLateImport(
144883
- ctx,
144884
- "__extern_get",
144885
- [{ kind: "externref" }, { kind: "externref" }],
144886
- [{ kind: "externref" }]
144887
- );
144888
- flushLateImportShifts(ctx, fctx);
144889
- if (getIdx !== void 0) {
144890
- fctx.body.push({ op: "call", funcIdx: getIdx });
145574
+ const getDispIdx = pinned ? reserveMemberGetDispatch(ctx, propName, fctx) : void 0;
145575
+ if (getDispIdx !== void 0) {
145576
+ fctx.body.push({ op: "call", funcIdx: getDispIdx });
145577
+ } else {
145578
+ fctx.body.push({ op: "local.get", index: keyLocal });
145579
+ const getIdx = ensureLateImport(
145580
+ ctx,
145581
+ "__extern_get",
145582
+ [{ kind: "externref" }, { kind: "externref" }],
145583
+ [{ kind: "externref" }]
145584
+ );
145585
+ flushLateImportShifts(ctx, fctx);
145586
+ if (getIdx !== void 0) {
145587
+ fctx.body.push({ op: "call", funcIdx: getIdx });
145588
+ }
144891
145589
  }
144892
145590
  addUnionImports(ctx);
144893
145591
  const unboxIdx = ctx.funcMap.get("__unbox_number");
@@ -144914,7 +145612,7 @@ function emitExternrefMemberIncDec(ctx, fctx, objLocal, propName, f64Op, mode) {
144914
145612
  []
144915
145613
  );
144916
145614
  flushLateImportShifts(ctx, fctx);
144917
- const dispatched = emitAlternateStructSetDispatch(
145615
+ const dispatched = pinned && emitAlternateStructSetDispatch(
144918
145616
  ctx,
144919
145617
  fctx,
144920
145618
  objLocal,
@@ -144975,25 +145673,10 @@ function emitExternrefElementIncDec(ctx, fctx, baseLocal, keyExpr, f64Op, mode)
144975
145673
  []
144976
145674
  );
144977
145675
  flushLateImportShifts(ctx, fctx);
144978
- const litName = ts.isStringLiteral(keyExpr) ? keyExpr.text : void 0;
144979
- let dispatched = false;
144980
- if (litName !== void 0) {
144981
- dispatched = emitAlternateStructSetDispatch(
144982
- ctx,
144983
- fctx,
144984
- baseLocal,
144985
- boxedLocal,
144986
- litName,
144987
- /*strict*/
144988
- false
144989
- );
144990
- }
144991
- if (!dispatched) {
144992
- fctx.body.push({ op: "local.get", index: baseLocal });
144993
- fctx.body.push({ op: "local.get", index: keyLocal });
144994
- fctx.body.push({ op: "local.get", index: boxedLocal });
144995
- if (setIdx !== void 0) fctx.body.push({ op: "call", funcIdx: setIdx });
144996
- }
145676
+ fctx.body.push({ op: "local.get", index: baseLocal });
145677
+ fctx.body.push({ op: "local.get", index: keyLocal });
145678
+ fctx.body.push({ op: "local.get", index: boxedLocal });
145679
+ if (setIdx !== void 0) fctx.body.push({ op: "call", funcIdx: setIdx });
144997
145680
  fctx.body.push({ op: "local.get", index: mode === "postfix" ? oldTmp : newTmp });
144998
145681
  return { kind: "f64" };
144999
145682
  }
@@ -145019,6 +145702,7 @@ function compileMemberIncDec(ctx, fctx, operand, arithOp, mode) {
145019
145702
  typeName = ctx.widenedVarStructMap.get(operand.expression.text);
145020
145703
  }
145021
145704
  if (!typeName) {
145705
+ const incDecPinned = operand.expression.kind === ts.SyntaxKind.ThisKeyword && fctx.thisStructName !== void 0 || resolveReceiverStruct(ctx, fctx, operand.expression) !== void 0;
145022
145706
  const objResult2 = compileExpression$1(ctx, fctx, operand.expression);
145023
145707
  if (objResult2) {
145024
145708
  const objLocal = allocLocal(fctx, `__incdec_eobj_${fctx.locals.length}`, { kind: "externref" });
@@ -145026,7 +145710,7 @@ function compileMemberIncDec(ctx, fctx, operand, arithOp, mode) {
145026
145710
  coerceType$2(ctx, fctx, objResult2, { kind: "externref" });
145027
145711
  }
145028
145712
  fctx.body.push({ op: "local.set", index: objLocal });
145029
- return emitExternrefMemberIncDec(ctx, fctx, objLocal, propName, f64Op, mode);
145713
+ return emitExternrefMemberIncDec(ctx, fctx, objLocal, propName, f64Op, mode, incDecPinned);
145030
145714
  }
145031
145715
  reportSilentFallback(ctx, "const-fallback", "unary-updates:incdec-unresolvable-receiver-type", operand);
145032
145716
  fctx.body.push({ op: "f64.const", value: NaN });
@@ -146647,11 +147331,11 @@ function compileExpressionInner(ctx, fctx, expr, expectedType) {
146647
147331
  }
146648
147332
  if (expr.kind === ts.SyntaxKind.TrueKeyword) {
146649
147333
  fctx.body.push({ op: "i32.const", value: 1 });
146650
- return { kind: "i32" };
147334
+ return { kind: "i32", boolean: true };
146651
147335
  }
146652
147336
  if (expr.kind === ts.SyntaxKind.FalseKeyword) {
146653
147337
  fctx.body.push({ op: "i32.const", value: 0 });
146654
- return { kind: "i32" };
147338
+ return { kind: "i32", boolean: true };
146655
147339
  }
146656
147340
  if (expr.kind === ts.SyntaxKind.NullKeyword) {
146657
147341
  fctx.body.push({ op: "ref.null.extern" });
@@ -154570,7 +155254,18 @@ declare function __wasiStdinSetReader(cb: () => void): void;
154570
155254
  declare function __wasiStdinStop(): void;
154571
155255
 
154572
155256
  class __Js2wasmReadable {
154573
- private chunk: string = "";
155257
+ // #2777 accumulate drained bytes in an amortized-growth byte buffer instead
155258
+ // of building each 'data' chunk via per-byte string concatenation. Building the
155259
+ // chunk by \`this.chunk = this.chunk + String.fromCharCode(b)\` made a large
155260
+ // frame's read side quadratic (the consumer then re-flattened the growing
155261
+ // cons-rope on every charCodeAt/substring), which SIGKILLed nm_node_process at
155262
+ // multi-MiB. The bytes now live in \`buf[head..tail)\`; the chunk STRING the
155263
+ // Node 'data' contract delivers is materialised ONCE per emit/read from that
155264
+ // slice (a single flatten), so consumers receive a FLAT string and their
155265
+ // charCodeAt/substring over it is O(1)/O(k), not a re-flatten per access.
155266
+ private buf: Uint8Array = new Uint8Array(64);
155267
+ private head: number = 0;
155268
+ private tail: number = 0;
154574
155269
  private dataCbs: ((c: string) => void)[] = [];
154575
155270
  private endCbs: (() => void)[] = [];
154576
155271
  private readableCbs: (() => void)[] = [];
@@ -154582,17 +155277,60 @@ class __Js2wasmReadable {
154582
155277
  private eofReadableFired: boolean = false;
154583
155278
  private destroyed: boolean = false;
154584
155279
 
155280
+ // Buffered byte count.
155281
+ private avail(): number { return this.tail - this.head; }
155282
+
155283
+ // Ensure room for \`extra\` more bytes at \`tail\`: first reclaim any consumed
155284
+ // prefix (head > 0), then amortized-double the backing array until it fits.
155285
+ private ensure(extra: number): void {
155286
+ if (this.tail + extra <= this.buf.length) { return; }
155287
+ if (this.head > 0) {
155288
+ const m = this.tail - this.head;
155289
+ let i = 0;
155290
+ while (i < m) { this.buf[i] = this.buf[this.head + i]; i = i + 1; }
155291
+ this.head = 0;
155292
+ this.tail = m;
155293
+ if (this.tail + extra <= this.buf.length) { return; }
155294
+ }
155295
+ let cap = this.buf.length;
155296
+ if (cap < 16) { cap = 16; }
155297
+ while (cap < this.tail + extra) { cap = cap * 2; }
155298
+ const nb = new Uint8Array(cap);
155299
+ let j = 0;
155300
+ while (j < this.tail) { nb[j] = this.buf[j]; j = j + 1; }
155301
+ this.buf = nb;
155302
+ }
155303
+
155304
+ // Materialise buf[start..end) as a FLAT string (one char per byte). The
155305
+ // trailing substring(0, len) forces a SINGLE flatten of the cons-rope built by
155306
+ // the per-byte concat, so the delivered chunk is flat — a consumer's
155307
+ // charCodeAt/substring over it is then O(1)/O(k), never a re-flatten per call.
155308
+ private slice(start: number, end: number): string {
155309
+ let s = "";
155310
+ let i = start;
155311
+ while (i < end) { s = s + String.fromCharCode(this.buf[i]); i = i + 1; }
155312
+ return s.substring(0, end - start);
155313
+ }
155314
+
155315
+ // Append all currently-buffered stdin bytes into \`buf\` — O(n), no string ops.
154585
155316
  private drainBytes(): number {
154586
155317
  let n = 0;
154587
155318
  let b = __wasiStdinReadByte();
154588
- while (b >= 0) { this.chunk = this.chunk + String.fromCharCode(b); n = n + 1; b = __wasiStdinReadByte(); }
155319
+ while (b >= 0) {
155320
+ this.ensure(1);
155321
+ this.buf[this.tail] = b;
155322
+ this.tail = this.tail + 1;
155323
+ n = n + 1;
155324
+ b = __wasiStdinReadByte();
155325
+ }
154589
155326
  return n;
154590
155327
  }
154591
155328
 
154592
155329
  private emitChunk(): void {
154593
- if (this.chunk.length === 0) return;
154594
- const out = this.chunk;
154595
- this.chunk = "";
155330
+ if (this.tail <= this.head) { return; }
155331
+ const out = this.slice(this.head, this.tail);
155332
+ this.head = 0;
155333
+ this.tail = 0;
154596
155334
  for (let i = 0; i < this.dataCbs.length; i = i + 1) { this.dataCbs[i](out); }
154597
155335
  }
154598
155336
 
@@ -154605,7 +155343,7 @@ class __Js2wasmReadable {
154605
155343
  // 'readable' fires when new bytes arrived OR when the stream has just reached
154606
155344
  // EOF with bytes still buffered (Node emits a final 'readable' at end-of-
154607
155345
  // stream so the consumer can read the last partial chunk before 'end').
154608
- const eofFlush = atEof && !this.eofReadableFired && this.chunk.length > 0;
155346
+ const eofFlush = atEof && !this.eofReadableFired && this.avail() > 0;
154609
155347
  if (got > 0 || eofFlush) {
154610
155348
  if (eofFlush) { this.eofReadableFired = true; }
154611
155349
  for (let i = 0; i < this.readableCbs.length; i = i + 1) { this.readableCbs[i](); }
@@ -154614,7 +155352,7 @@ class __Js2wasmReadable {
154614
155352
  // 'end' only after fd EOF AND the stream's own buffer is fully delivered
154615
155353
  // (a paused stream withholds bytes in this.chunk, so EOF alone is not the
154616
155354
  // end of the readable side -- matches Node).
154617
- if (atEof && this.chunk.length === 0 && !this.ended) {
155355
+ if (atEof && this.avail() === 0 && !this.ended) {
154618
155356
  this.ended = true;
154619
155357
  for (let i = 0; i < this.endCbs.length; i = i + 1) { this.endCbs[i](); }
154620
155358
  }
@@ -154657,24 +155395,27 @@ class __Js2wasmReadable {
154657
155395
  if (this.destroyed) { return null; }
154658
155396
  // Pull any freshly-ready bytes so a paused .read() sees the latest buffer.
154659
155397
  this.drainBytes();
154660
- const avail = this.chunk.length;
155398
+ const avail = this.avail();
154661
155399
  if (size === undefined || size < 0) {
154662
155400
  if (avail === 0) { return null; }
154663
- const all = this.chunk;
154664
- this.chunk = "";
155401
+ const all = this.slice(this.head, this.tail);
155402
+ this.head = 0;
155403
+ this.tail = 0;
154665
155404
  return all;
154666
155405
  }
154667
155406
  if (avail < size) {
154668
155407
  if (__wasiStdinEof() && avail > 0) {
154669
- const rest = this.chunk;
154670
- this.chunk = "";
155408
+ const rest = this.slice(this.head, this.tail);
155409
+ this.head = 0;
155410
+ this.tail = 0;
154671
155411
  return rest;
154672
155412
  }
154673
155413
  return null;
154674
155414
  }
154675
- const head = this.chunk.substring(0, size);
154676
- this.chunk = this.chunk.substring(size);
154677
- return head;
155415
+ const out = this.slice(this.head, this.head + size);
155416
+ this.head = this.head + size;
155417
+ if (this.head >= this.tail) { this.head = 0; this.tail = 0; }
155418
+ return out;
154678
155419
  }
154679
155420
 
154680
155421
  pause(): __Js2wasmReadable { this.paused = true; return this; }
@@ -155522,8 +156263,14 @@ function buildCodegenOptions(options, emitSourceMap, prep) {
155522
156263
  utf8Storage: options.utf8Storage,
155523
156264
  testRuntime: options.testRuntime,
155524
156265
  wasi: options.target === "wasi",
155525
- linkNodeShims: options.linkNodeShims,
156266
+ // #2783 — the dynamic-linking axis: namespaces to leave as link-time imports
156267
+ // (deduped). `link: ["node:fs"]` is the only spelling; the old `linkNodeShims`
156268
+ // boolean was removed.
156269
+ link: [...new Set(options.link ?? [])],
155526
156270
  standalone: options.target === "standalone",
156271
+ // (#2796) Diff-test-harness fidelity — defer top-level init to an export so
156272
+ // the host runs it after setExports (symmetric with standalone `_start`).
156273
+ deferTopLevelInit: options.deferTopLevelInit,
155527
156274
  strictNoHostImports: options.strictNoHostImports,
155528
156275
  // (#2119) thread module-strictness inference uniformly across all drivers.
155529
156276
  inferModuleStrictArguments: options.inferModuleStrictArguments,
@@ -157704,6 +158451,7 @@ const _PROTO_CB_SLOTS = {
157704
158451
  catch: { argIdx: 0, arity: 1 },
157705
158452
  finally: { argIdx: 0, arity: 0 }
157706
158453
  };
158454
+ const _VEC_PRIMITIVE_READ_METHODS = /* @__PURE__ */ new Set(["indexOf", "lastIndexOf", "includes", "join"]);
157707
158455
  function _readIterResultField(result, field, exports$1) {
157708
158456
  if (result != null && typeof result === "object" && _isWasmStruct(result)) {
157709
158457
  const getter = exports$1?.[`__sget_${field}`];
@@ -159370,9 +160118,97 @@ function _setLikeRecordForHost(arg, exports$1, state) {
159370
160118
  };
159371
160119
  return { size: fixField("size"), has: fixField("has"), keys: fixField("keys") };
159372
160120
  }
160121
+ function _asArrayIndex(key) {
160122
+ if (key === "0") return 0;
160123
+ if (key.length === 0 || key.charCodeAt(0) === 48) return void 0;
160124
+ const n = Number(key);
160125
+ if (Number.isInteger(n) && n >= 0 && n < 4294967295 && String(n) === key) return n;
160126
+ return void 0;
160127
+ }
160128
+ function _wrapVecForHost(vec, exports$1) {
160129
+ const cached = _hostProxyCache.get(vec);
160130
+ if (cached) return cached;
160131
+ const lenFn = exports$1.__vec_len;
160132
+ const getFn = exports$1.__vec_get;
160133
+ if (typeof lenFn !== "function" || typeof getFn !== "function") return void 0;
160134
+ const liveLen = () => {
160135
+ try {
160136
+ const n = lenFn(vec);
160137
+ return typeof n === "number" && n >= 0 ? n : 0;
160138
+ } catch {
160139
+ return 0;
160140
+ }
160141
+ };
160142
+ const elemAt = (i) => {
160143
+ try {
160144
+ return _wrapForHost(getFn(vec, i), exports$1);
160145
+ } catch {
160146
+ return void 0;
160147
+ }
160148
+ };
160149
+ const target = [];
160150
+ const handler = {
160151
+ get(_t, key) {
160152
+ if (key === "length") return liveLen();
160153
+ if (typeof key === "string") {
160154
+ const idx = _asArrayIndex(key);
160155
+ if (idx !== void 0) return idx < liveLen() ? elemAt(idx) : void 0;
160156
+ }
160157
+ return target[key];
160158
+ },
160159
+ has(_t, key) {
160160
+ if (key === "length") return true;
160161
+ if (typeof key === "string") {
160162
+ const idx = _asArrayIndex(key);
160163
+ if (idx !== void 0) return idx < liveLen();
160164
+ }
160165
+ return key in target;
160166
+ },
160167
+ ownKeys() {
160168
+ const n = liveLen();
160169
+ const keys = [];
160170
+ for (let i = 0; i < n; i++) keys.push(String(i));
160171
+ keys.push("length");
160172
+ return keys;
160173
+ },
160174
+ getOwnPropertyDescriptor(_t, key) {
160175
+ if (key === "length") {
160176
+ return { value: liveLen(), writable: true, enumerable: false, configurable: false };
160177
+ }
160178
+ if (typeof key === "string") {
160179
+ const idx = _asArrayIndex(key);
160180
+ if (idx !== void 0 && idx < liveLen()) {
160181
+ return { value: elemAt(idx), writable: true, enumerable: true, configurable: true };
160182
+ }
160183
+ }
160184
+ return void 0;
160185
+ },
160186
+ // Host-side writes are not part of the AST-read contract and the vec has no
160187
+ // general element-setter export; accept silently (keep the target clean) so
160188
+ // a stray host write neither throws nor leaves a phantom element. acorn's
160189
+ // own mutations go through `__extern_method_call` (unwrap → `__vec_push`).
160190
+ set() {
160191
+ return true;
160192
+ }
160193
+ };
160194
+ const proxy = new Proxy(target, handler);
160195
+ _hostProxyCache.set(vec, proxy);
160196
+ _hostProxyReverse.set(proxy, vec);
160197
+ return proxy;
160198
+ }
159373
160199
  function _wrapForHost(obj, exports$1) {
159374
160200
  if (obj == null || typeof obj !== "object") return obj;
159375
160201
  if (!_isWasmStruct(obj)) return obj;
160202
+ if (exports$1) {
160203
+ try {
160204
+ const isVecFn = exports$1.__is_vec;
160205
+ if (typeof isVecFn === "function" && isVecFn(obj) === 1) {
160206
+ const vecView = _wrapVecForHost(obj, exports$1);
160207
+ if (vecView !== void 0) return vecView;
160208
+ }
160209
+ } catch {
160210
+ }
160211
+ }
159376
160212
  const cached = _hostProxyCache.get(obj);
159377
160213
  if (cached) return cached;
159378
160214
  const target = /* @__PURE__ */ Object.create(null);
@@ -159418,6 +160254,13 @@ function _wrapForHost(obj, exports$1) {
159418
160254
  }
159419
160255
  } catch {
159420
160256
  }
160257
+ try {
160258
+ const isDataFn = exports$1.__is_data_struct;
160259
+ if (typeof isDataFn === "function" && isDataFn(val) === 1) {
160260
+ return _wrapForHost(val, exports$1);
160261
+ }
160262
+ } catch {
160263
+ }
159421
160264
  const exportKey = typeof key === "string" ? key : typeof key === "symbol" ? _symbolToWasm.get(key) : void 0;
159422
160265
  if (exportKey !== void 0) {
159423
160266
  const callFn = exports$1[`__call_${exportKey}`];
@@ -162305,6 +163148,27 @@ if (__fail) throw new Test262Error('eval harness assertion ' + __fail + ' failed
162305
163148
  return exports$1.__vec_pop(rawVec);
162306
163149
  }
162307
163150
  }
163151
+ if (_VEC_PRIMITIVE_READ_METHODS.has(method) && typeof exports$1.__vec_len === "function" && typeof exports$1.__vec_get === "function") {
163152
+ const isVecFn = exports$1.__is_vec;
163153
+ let isVec = false;
163154
+ try {
163155
+ isVec = typeof isVecFn === "function" && isVecFn(rawVec) === 1;
163156
+ } catch {
163157
+ isVec = false;
163158
+ }
163159
+ if (isVec) {
163160
+ const len = exports$1.__vec_len(rawVec);
163161
+ if (typeof len === "number" && len >= 0) {
163162
+ const getFn = exports$1.__vec_get;
163163
+ const arr = new Array(len);
163164
+ for (let i = 0; i < len; i++) arr[i] = wrapHostValue(getFn(rawVec, i));
163165
+ const nativeFn = Array.prototype[method];
163166
+ if (typeof nativeFn === "function") {
163167
+ return nativeFn.apply(arr, wrappedArgs);
163168
+ }
163169
+ }
163170
+ }
163171
+ }
162308
163172
  }
162309
163173
  }
162310
163174
  if ((method === "getOrInsert" || method === "getOrInsertComputed") && (wrappedObj instanceof Map || wrappedObj instanceof WeakMap)) {
@@ -162504,6 +163368,31 @@ if (__fail) throw new Test262Error('eval harness assertion ' + __fail + ' failed
162504
163368
  const wrappedTarget = _wrapForHost(target, exports$1);
162505
163369
  const wrappedSources2 = (sources ?? []).map((s) => _isWasmStruct(s) ? _wrapForHost(s, exports$1) : s);
162506
163370
  Object.assign(wrappedTarget, ...wrappedSources2);
163371
+ const targetDescs = _getSidecarDescs(target);
163372
+ const staticFieldNames = new Set(_getStructFieldNames(target, exports$1) ?? []);
163373
+ for (const ws of wrappedSources2) {
163374
+ if (ws == null || typeof ws !== "object" && typeof ws !== "function") continue;
163375
+ let keys;
163376
+ try {
163377
+ keys = Reflect.ownKeys(ws);
163378
+ } catch {
163379
+ continue;
163380
+ }
163381
+ for (const k of keys) {
163382
+ let enumerable;
163383
+ try {
163384
+ enumerable = Object.getOwnPropertyDescriptor(ws, k)?.enumerable === true;
163385
+ } catch {
163386
+ enumerable = false;
163387
+ }
163388
+ if (!enumerable) continue;
163389
+ if (typeof k === "string" && staticFieldNames.has(k)) continue;
163390
+ const nk = _normalizeDescKey(k);
163391
+ if (!targetDescs.has(nk)) {
163392
+ targetDescs.set(nk, _SC_WRITABLE | _SC_ENUMERABLE | _SC_CONFIGURABLE | _SC_DEFINED);
163393
+ }
163394
+ }
163395
+ }
162507
163396
  return target;
162508
163397
  }
162509
163398
  const wrappedSources = (sources ?? []).map((s) => _isWasmStruct(s) ? _wrapForHost(s, exports$1) : s);