Skip to content

Commit ac3869b

Browse files
committed
fix bug from using one apply function
1 parent 1acc9ee commit ac3869b

File tree

2 files changed

+69
-53
lines changed

2 files changed

+69
-53
lines changed

src/wasm-compiler/builderGenerator.ts

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ import {
2929
SET_LEX_ADDR_FX,
3030
SET_PAIR_HEAD_FX,
3131
SET_PAIR_TAIL_FX,
32+
SET_PARAM_FX,
3233
} from "./constants";
3334
import { f64, global, i32, i64, local, mut, wasm } from "./wasm-util/builder";
34-
import { WasmCall, WasmInstruction } from "./wasm-util/types";
35+
import { WasmCall, WasmInstruction, WasmRaw } from "./wasm-util/types";
3536

3637
const builtInFunctions: {
3738
name: string;
@@ -102,8 +103,11 @@ type Binding = { name: string; tag: "local" | "nonlocal" };
102103

103104
// all expressions compile to a call to a function like makeX, get/setLexAddress, arithOp, etc.
104105
// so expressions return WasmCalls. (every expression results in i32 i64)
106+
// WasmRaw is for function calls
105107
export class BuilderGenerator
106-
implements StmtNS.Visitor<WasmInstruction>, ExprNS.Visitor<WasmCall>
108+
implements
109+
StmtNS.Visitor<WasmInstruction>,
110+
ExprNS.Visitor<WasmCall | WasmRaw>
107111
{
108112
private strings: [string, number][] = [];
109113
private heapPointer = 0;
@@ -256,9 +260,12 @@ export class BuilderGenerator
256260
.func("$main")
257261
.results(...(undroppedInstr ? [i32, i64] : []))
258262
.body(
259-
wasm
260-
.call(ALLOC_ENV_FX)
261-
.args(i32.const(globalEnvLength), i32.const(0)),
263+
global.set(
264+
CURR_ENV,
265+
wasm
266+
.call(ALLOC_ENV_FX)
267+
.args(i32.const(globalEnvLength), i32.const(0), i32.const(0))
268+
),
262269

263270
...builtInFuncsDeclarations,
264271

@@ -408,42 +415,35 @@ export class BuilderGenerator
408415
);
409416
}
410417

411-
visitCallExpr(expr: ExprNS.Call): WasmCall {
418+
visitCallExpr(expr: ExprNS.Call): WasmRaw {
412419
const callee = this.visit(expr.callee);
420+
const args = expr.args.map((arg) => this.visit(arg));
413421

414-
// because we're not actually passing in arguments to apply, the lex addresses from the args
415-
// are not accurate.
416-
// they assume that we're not yet in the new function call's environment, because that's how it is
417-
// from the compiler's perspective.
418-
// but here, we're already in the new environment because PRE_APPLY was called. so we have to
419-
// increment the depth from each GET_LEX_ADDRESS call from each arg by 1.
420-
const args: WasmCall[] = expr.args
421-
.map((arg) => this.visit(arg))
422-
.map((arg) => ({
423-
...arg,
424-
...(arg.function === GET_LEX_ADDR_FX.name && {
425-
arguments: arg.arguments.map((a, i) => ({
426-
...a,
427-
428-
// first argument is depth
429-
...(i === 0 &&
430-
a.op === "i32.const" && { value: a.value + BigInt(1) }),
431-
})),
432-
}),
433-
}));
434-
435-
return wasm.call(APPLY_FX_NAME).args(
436-
global.get(CURR_ENV),
437-
wasm.call(PRE_APPLY_FX).args(callee, i32.const(args.length)),
438-
439-
// these are not arguments, but they don't produce values, so it's ok to insert them here
440-
// this is to maintain the return type of WasmCall
441-
// this is equivalent to setting lex addresses after calling PRE_APPLY, but before APPLY
442-
443-
...[...Array(args.length).keys()].map((i) =>
444-
wasm.call(SET_LEX_ADDR_FX).args(i32.const(0), i32.const(i), args[i])
445-
)
446-
);
422+
// PRE_APPLY returns (1, 2) callee tag and value, (3) pointer to new environment
423+
// APPLY expects (1) pointer to return environment, (2, 3) callee tag and value
424+
425+
// we call PRE_APPLY first, which verifies the callee is a closure and arity matches
426+
// AND creates a new environment for the function call, but does not set CURR_ENV yet
427+
// this is so that we can set the arguments in the new environment first
428+
429+
// this means we can't use SET_LEX_ADDR_FX because it uses CURR_ENV internally
430+
// so we manually set the arguments in the new environment using SET_PARAM_FX
431+
432+
// the SET_PARAM function returns the env address after setting the parameter
433+
// so we can chain the calls together
434+
return wasm.raw`
435+
(global.get ${CURR_ENV})
436+
(call ${PRE_APPLY_FX.name} ${callee} (i32.const ${args.length}))
437+
438+
${args.map(
439+
(arg, i) =>
440+
wasm.raw`
441+
(i32.const ${i * 12}) (i32.add) ${arg} (call ${SET_PARAM_FX.name})`
442+
)}
443+
444+
(global.set ${CURR_ENV})
445+
(call ${APPLY_FX_NAME})
446+
`;
447447
}
448448

449449
visitReturnStmt(stmt: StmtNS.Return): WasmInstruction {

src/wasm-compiler/constants.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -605,22 +605,29 @@ export const COMPARISON_OP_FX = wasm
605605
);
606606

607607
// *3*4 because each variable has a tag and payload = 3 words = 12 bytes; +4 because parentEnv is stored at start of env
608+
// we initialise only local variables to UNBOUND, NOT parameters.
609+
// this is because have already set parameters in the new environment before calling this function.
608610
export const ALLOC_ENV_FX = wasm
609611
.func("$_alloc_env")
610-
.params({ $size: i32, $parent: i32 })
612+
.params({ $size: i32, $parent: i32, $arity: i32 })
613+
.results(i32)
611614
.body(
612-
global.set(CURR_ENV, global.get(HEAP_PTR)),
613-
i32.store(global.get(CURR_ENV), local.get("$parent")),
615+
global.get(HEAP_PTR), // return the start of the new env, set CURR_ENV AFTER
616+
i32.store(global.get(HEAP_PTR), local.get("$parent")),
614617
global.set(HEAP_PTR, i32.add(global.get(HEAP_PTR), i32.const(4))),
615618

616-
memory.fill(global.get(HEAP_PTR), i32.const(TYPE_TAG.UNBOUND), i32.mul(local.get("$size"), i32.const(12))),
619+
memory.fill(
620+
i32.add(global.get(HEAP_PTR), i32.mul(local.get("$arity"), i32.const(12))),
621+
i32.const(TYPE_TAG.UNBOUND),
622+
i32.mul(i32.sub(local.get("$size"), local.get("$arity")), i32.const(12))
623+
),
617624
global.set(HEAP_PTR, i32.add(global.get(HEAP_PTR), i32.mul(local.get("$size"), i32.const(12))))
618625
);
619626

620627
export const PRE_APPLY_FX = wasm
621628
.func("$_pre_apply")
622629
.params({ $tag: i32, $val: i64, $arity: i32 })
623-
.results(i32, i64)
630+
.results(i32, i64, i32)
624631
.body(
625632
wasm
626633
.if(i32.ne(local.get("$tag"), i32.const(TYPE_TAG.CLOSURE)))
@@ -632,14 +639,15 @@ export const PRE_APPLY_FX = wasm
632639
)
633640
.then(wasm.call("$_log_error").args(i32.const(ERROR_MAP.FUNC_WRONG_ARITY[0])), wasm.unreachable()),
634641

642+
local.get("$tag"),
643+
local.get("$val"),
635644
wasm
636645
.call(ALLOC_ENV_FX)
637646
.args(
638647
i32.and(i32.wrap_i64(i64.shr_u(local.get("$val"), i64.const(32))), i32.const(255)),
639-
i32.wrap_i64(local.get("$val"))
640-
),
641-
local.get("$tag"),
642-
local.get("$val")
648+
i32.wrap_i64(local.get("$val")),
649+
local.get("$arity")
650+
)
643651
);
644652

645653
export const APPLY_FX_NAME = "$_apply";
@@ -673,10 +681,6 @@ export const GET_LEX_ADDR_FX = wasm
673681
i32.load(i32.add(i32.add(local.get("$env"), i32.const(4)), i32.mul(local.get("$index"), i32.const(12))))
674682
),
675683

676-
wasm.call("$_log_int").args(i64.extend_i32_u(local.get("$depth"))),
677-
wasm.call("$_log_int").args(i64.extend_i32_u(local.get("$index"))),
678-
wasm.call("$_log_int").args(i64.extend_i32_u(local.get("$tag"))),
679-
680684
wasm
681685
.if(i32.eq(local.get("$tag"), i32.const(TYPE_TAG.UNBOUND)))
682686
.then(wasm.call("$_log_error").args(i32.const(ERROR_MAP.UNBOUND[0])), wasm.unreachable()),
@@ -725,6 +729,17 @@ export const SET_LEX_ADDR_FX = wasm
725729
wasm.unreachable()
726730
);
727731

732+
export const SET_PARAM_FX = wasm
733+
.func("$_set_param")
734+
.params({ $addr: i32, $tag: i32, $value: i64 })
735+
.results(i32)
736+
.body(
737+
i32.store(i32.add(local.get("$addr"), i32.const(4)), local.get("$tag")),
738+
i64.store(i32.add(local.get("$addr"), i32.const(8)), local.get("$value")),
739+
740+
local.get("$addr")
741+
);
742+
728743
export const nativeFunctions = [
729744
MAKE_INT_FX,
730745
MAKE_FLOAT_FX,
@@ -738,6 +753,7 @@ export const nativeFunctions = [
738753
GET_PAIR_TAIL_FX,
739754
SET_PAIR_HEAD_FX,
740755
SET_PAIR_TAIL_FX,
756+
LOG_FX,
741757
NEG_FX,
742758
ARITHMETIC_OP_FX,
743759
STRING_COMPARE_FX,
@@ -746,5 +762,5 @@ export const nativeFunctions = [
746762
PRE_APPLY_FX,
747763
GET_LEX_ADDR_FX,
748764
SET_LEX_ADDR_FX,
749-
LOG_FX,
765+
SET_PARAM_FX,
750766
];

0 commit comments

Comments
 (0)