[READ-ONLY] Mirror of https://github.com/CanadaHonk/porffor. An ahead-of-time JavaScript compiler porffor.dev
9

Configure Feed

Select the types of activity you want to include in your feed.

codegen: minor dedups

Oliver Medhurst (Jul 21, 2026, 2:51 AM +0100) 677a2316 a607ce39

+28 -54
+28 -54
compiler/codegen.js
··· 360 360 _skipClosureOwnLocals: true 361 361 }); 362 362 363 + // mirror a binding into the scope's own closure env 364 + const mirrorToClosureEnv = (scope, name, right = closureLocalReadNode(name)) => 365 + genStmt(scope, { type: 'AssignmentExpression', operator: '=', 366 + left: closureMemberNode(scope, name, scope.ast), right }); 367 + 363 368 const closureOwnLocalReadIsLocal = (scope, name) => 364 369 name in scope.locals && 365 370 !scope.closureOwnLocals?.[name]?.node?._writes; ··· 1754 1759 return out; 1755 1760 }; 1756 1761 1762 + // runtime check: can this jsval hold a GC reference? (not undefined/number/boolean or their objects) 1763 + const canReferenceCheck = (scope, v) => { 1764 + const t = reuse(scope, JvType(v)); 1765 + return Bin('&&', T.i32, 1766 + Bin('&&', T.i32, 1767 + Bin('!=', T.i32, t, Const(T.i32, TYPES.undefined)), 1768 + Bin('!=', T.i32, t, Const(T.i32, TYPES.number))), 1769 + Bin('&&', T.i32, 1770 + Bin('!=', T.i32, t, Const(T.i32, TYPES.boolean)), 1771 + Bin('&&', T.i32, 1772 + Bin('!=', T.i32, t, Const(T.i32, TYPES.numberobject)), 1773 + Bin('!=', T.i32, t, Const(T.i32, TYPES.booleanobject))))); 1774 + }; 1775 + 1757 1776 const generateIRIntrinsic = (scope, op, args) => { 1758 1777 const a = i => { 1759 1778 const v = knownValue(scope, args[i]); ··· 1765 1784 : ctype === 'f64' || ctype === 'f32' ? numValue(v) 1766 1785 : ctype === 'u64' || ctype === 'i64' ? Convert(T.i64, numValue(v), ctype === 'i64' ? CONVERT_SIGNED : 0) 1767 1786 : Convert(T.i32, numValue(v), ctype[0] === 'i' ? CONVERT_SIGNED : 0); 1768 - const canReferenceCheck = v => { 1769 - const t = reuse(scope, JvType(v)); 1770 - return Bin('&&', T.i32, 1771 - Bin('&&', T.i32, 1772 - Bin('!=', T.i32, t, Const(T.i32, TYPES.undefined)), 1773 - Bin('!=', T.i32, t, Const(T.i32, TYPES.number))), 1774 - Bin('&&', T.i32, 1775 - Bin('!=', T.i32, t, Const(T.i32, TYPES.boolean)), 1776 - Bin('&&', T.i32, 1777 - Bin('!=', T.i32, t, Const(T.i32, TYPES.numberobject)), 1778 - Bin('!=', T.i32, t, Const(T.i32, TYPES.booleanobject))))); 1779 - }; 1780 1787 let m; 1781 1788 if (m = /^(load|store)(\w+)$/.exec(op)) { 1782 1789 const ct = m[2] === 'Jv' ? 'jsval' : m[2].toLowerCase(); ··· 1804 1811 if (known != null) return GcBarrier(ptr, type); 1805 1812 const value = a(2); 1806 1813 const jv = value[N_TYPE] === T.jsval ? value : valNumber(value); 1807 - return If(canReferenceCheck(jv), [ GcBarrier(ptr, type) ]); 1814 + return If(canReferenceCheck(scope, jv), [ GcBarrier(ptr, type) ]); 1808 1815 } 1809 1816 throw new Error(`unknown Porffor.IR.${op}`); 1810 1817 }; ··· 2500 2507 } 2501 2508 2502 2509 // mirror the binding into the closure env when an inner closure captures it 2503 - if (scope.closureOwnLocals?.[name]) { 2504 - genStmt(scope, { 2505 - type: 'AssignmentExpression', 2506 - operator: '=', 2507 - left: closureMemberNode(scope, name, scope.ast), 2508 - right: closureLocalReadNode(name) 2509 - }); 2510 - } 2510 + if (scope.closureOwnLocals?.[name]) mirrorToClosureEnv(scope, name); 2511 2511 2512 2512 return valUndefined(); 2513 2513 } ··· 2575 2575 } 2576 2576 2577 2577 if (scope.closureOwnLocals?.[name] && (!redecl || init)) { 2578 - genStmt(scope, { 2579 - type: 'AssignmentExpression', 2580 - operator: '=', 2581 - left: closureMemberNode(scope, name, scope.ast), 2582 - right: init ? closureLocalReadNode(name) : DEFAULT_VALUE 2583 - }); 2578 + mirrorToClosureEnv(scope, name, init ? closureLocalReadNode(name) : DEFAULT_VALUE); 2584 2579 } 2585 2580 2586 2581 return valUndefined(); ··· 2836 2831 const entries = Load('u32', JvPtr(env), 12); 2837 2832 stmt(scope, Store('f64', entries, closureSlot * 20 + 8, JvNum(value))); 2838 2833 stmt(scope, Store('u8', entries, closureSlot * 20 + 17, JvType(value))); 2839 - const type = reuse(scope, JvType(value)); 2840 - stmt(scope, If(Bin('&&', T.i32, 2841 - Bin('&&', T.i32, 2842 - Bin('!=', T.i32, type, Const(T.i32, TYPES.undefined)), 2843 - Bin('!=', T.i32, type, Const(T.i32, TYPES.number))), 2844 - Bin('&&', T.i32, 2845 - Bin('!=', T.i32, type, Const(T.i32, TYPES.boolean)), 2846 - Bin('&&', T.i32, 2847 - Bin('!=', T.i32, type, Const(T.i32, TYPES.numberobject)), 2848 - Bin('!=', T.i32, type, Const(T.i32, TYPES.booleanobject))))), [ 2834 + stmt(scope, If(canReferenceCheck(scope, value), [ 2849 2835 GcBarrier(JvPtr(env), Const(T.i32, TYPES.object)) 2850 2836 ])); 2851 2837 return valueUnused ? valUndefined() : value; ··· 4336 4322 else func.body.unshift(...fieldInits); 4337 4323 func.body.unshift(...guard); 4338 4324 4339 - if (!expr && scope.closureOwnLocals?.[name]) { 4340 - genStmt(scope, { type: 'AssignmentExpression', operator: '=', 4341 - left: closureMemberNode(scope, name, scope.ast), right: closureLocalReadNode(name) }); 4342 - } 4325 + if (!expr && scope.closureOwnLocals?.[name]) mirrorToClosureEnv(scope, name); 4343 4326 4344 4327 return expr ? classRoot : valUndefined(); 4345 4328 }; ··· 4725 4708 if (hasClosureOwnEnv(func)) { 4726 4709 for (const { name: argName } of args) { 4727 4710 if (!func.closureOwnLocals?.[argName]) continue; 4728 - genStmt(func, { type: 'AssignmentExpression', operator: '=', 4729 - left: closureMemberNode(func, argName, func.ast), right: closureLocalReadNode(argName) }); 4711 + mirrorToClosureEnv(func, argName); 4730 4712 } 4731 4713 4732 - if (func.closureOwnLocals?.[func.name]) { 4733 - genStmt(func, { type: 'AssignmentExpression', operator: '=', 4734 - left: closureMemberNode(func, func.name, func.ast), right: closureLocalReadNode(func.name) }); 4735 - } 4736 - 4737 - if (func.closureOwnThis) { 4738 - genStmt(func, { type: 'AssignmentExpression', operator: '=', 4739 - left: closureMemberNode(func, '#this', func.ast), right: { type: 'ThisExpression' } }); 4740 - } 4714 + if (func.closureOwnLocals?.[func.name]) mirrorToClosureEnv(func, func.name); 4715 + if (func.closureOwnThis) mirrorToClosureEnv(func, '#this', { type: 'ThisExpression' }); 4741 4716 4742 4717 if (body.type === 'BlockStatement') { 4743 4718 for (const node of body.body) { 4744 4719 if (node.type !== 'FunctionDeclaration') continue; 4745 4720 if (!func.closureOwnLocals?.[node.id?.name]) continue; 4746 4721 generateFunc(func, node, true); 4747 - genStmt(func, { type: 'AssignmentExpression', operator: '=', 4748 - left: closureMemberNode(func, node.id.name, func.ast), right: closureLocalReadNode(node.id.name) }); 4722 + mirrorToClosureEnv(func, node.id.name); 4749 4723 } 4750 4724 } 4751 4725 }