Skip to content

Commit f7a1301

Browse files
committed
Retrieve SourceLocation of caller when an Appl has signature mismatch
1 parent 8fa5295 commit f7a1301

File tree

9 files changed

+143
-54
lines changed

9 files changed

+143
-54
lines changed

lib-backend-wasm/src/func.rs

+43-20
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use boolinator::*;
2121

2222
use std::collections::HashMap;
2323

24-
struct EncodeContext<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, Heap: HeapManager> {
24+
struct EncodeContext<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, Heap: HeapManager> {
2525
// Local to this function
2626
return_type: Option<ir::VarType>,
2727

@@ -38,19 +38,20 @@ struct EncodeContext<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, Heap: HeapManager> {
3838
stackptr: wasmgen::GlobalIdx,
3939
memidx: wasmgen::MemIdx,
4040
thunk_map: &'f HashMap<Box<[ir::OverloadEntry]>, u32>, // map from overloads to elemidx
41-
heap: &'g Heap,
42-
string_pool: &'h ShiftedStringPool,
41+
appl_data_encoder: &'g HashMap<ir::SourceLocation, u32>, // map from source location to the location in memory of the args
42+
heap: &'h Heap,
43+
string_pool: &'i ShiftedStringPool,
4344
error_func: wasmgen::FuncIdx, // imported function to call to error out (e.g. runtime type errors)
4445
options: Options, // Compilation options (it implements Copy)
4546
}
4647

4748
// Have to implement Copy and Clone manually, because #[derive(Copy, Clone)] doesn't work for generic types like Heap
48-
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, Heap: HeapManager> Copy
49-
for EncodeContext<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, Heap>
49+
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, Heap: HeapManager> Copy
50+
for EncodeContext<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, Heap>
5051
{
5152
}
52-
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, Heap: HeapManager> Clone
53-
for EncodeContext<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, Heap>
53+
impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, Heap: HeapManager> Clone
54+
for EncodeContext<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, Heap>
5455
{
5556
fn clone(&self) -> Self {
5657
*self
@@ -106,14 +107,14 @@ pub fn encode_funcs<'a, Heap: HeapManager>(
106107
globalidx_stackptr: wasmgen::GlobalIdx,
107108
memidx: wasmgen::MemIdx,
108109
thunk_sv: SearchableVec<Box<[ir::OverloadEntry]>>,
110+
appl_data_encoder: HashMap<ir::SourceLocation, u32>,
109111
heap: &Heap,
110112
string_pool: &ShiftedStringPool,
111113
error_func: wasmgen::FuncIdx,
112114
options: Options,
113115
wasm_module: &mut wasmgen::WasmModule,
114116
) {
115117
struct WasmRegistry {
116-
typeidx: wasmgen::TypeIdx,
117118
funcidx: wasmgen::FuncIdx,
118119
wasm_param_map: Box<[wasmgen::LocalIdx]>, // map converts wasm_param_map index to actual wasm param index
119120
param_map: Box<[usize]>, // map converts ir param index to wasm_param_map index
@@ -140,11 +141,10 @@ pub fn encode_funcs<'a, Heap: HeapManager>(
140141
wasm_param_valtypes,
141142
encode_result(ir_func.result, options.wasm_multi_value),
142143
);
143-
let (wasm_typeidx, wasm_funcidx) = wasm_module.register_func(&wasm_functype);
144+
let (_, wasm_funcidx) = wasm_module.register_func(&wasm_functype);
144145
let code_builder = wasmgen::CodeBuilder::new(wasm_functype);
145146
(
146147
WasmRegistry {
147-
typeidx: wasm_typeidx,
148148
funcidx: wasm_funcidx,
149149
wasm_param_map: wasm_param_map,
150150
param_map: param_map,
@@ -194,6 +194,7 @@ pub fn encode_funcs<'a, Heap: HeapManager>(
194194
memidx: memidx,
195195
heap: heap,
196196
thunk_map: &new_thunk_map,
197+
appl_data_encoder: &appl_data_encoder,
197198
string_pool: string_pool,
198199
error_func: error_func,
199200
options: options,
@@ -240,6 +241,7 @@ pub fn encode_funcs<'a, Heap: HeapManager>(
240241
memidx: memidx,
241242
heap: heap,
242243
thunk_map: &new_thunk_map,
244+
appl_data_encoder: &appl_data_encoder,
243245
string_pool: string_pool,
244246
error_func: error_func,
245247
options: options,
@@ -757,9 +759,21 @@ fn encode_expr<H: HeapManager>(
757759
encode_prim_inst(expr.vartype, *prim_inst, args, ctx, mutctx, expr_builder);
758760
true
759761
}
760-
ir::ExprKind::Appl { func, args } => {
762+
ir::ExprKind::Appl {
763+
func,
764+
args,
765+
location,
766+
} => {
761767
// encodes an indirect function call
762-
encode_appl(expr.vartype, func, args, ctx, mutctx, expr_builder);
768+
encode_appl(
769+
expr.vartype,
770+
func,
771+
args,
772+
location,
773+
ctx,
774+
mutctx,
775+
expr_builder,
776+
);
763777
true
764778
}
765779
ir::ExprKind::DirectAppl { funcidx, args } => {
@@ -1227,6 +1241,7 @@ fn encode_appl<H: HeapManager>(
12271241
return_type: Option<ir::VarType>,
12281242
func_expr: &ir::Expr,
12291243
args: &[ir::Expr],
1244+
location: &ir::SourceLocation,
12301245
ctx: EncodeContext<H>,
12311246
mutctx: &mut MutContext,
12321247
expr_builder: &mut wasmgen::ExprBuilder,
@@ -1269,10 +1284,9 @@ fn encode_appl<H: HeapManager>(
12691284
expr_builder,
12701285
);
12711286

1272-
// TODO: encode the proper caller id
1273-
// for now just use zero
1287+
// encode the proper caller id (which is the memory location of the SourceLocation)
12741288
// net wasm stack: [] -> [i32(callerid)]
1275-
expr_builder.i32_const(0);
1289+
expr_builder.i32_const(*ctx.appl_data_encoder.get(location).unwrap() as i32);
12761290

12771291
// push the tableidx onto the stack
12781292
// net wasm stack: [] -> [tableidx]
@@ -1921,14 +1935,23 @@ fn encode_thunk<H: HeapManager>(
19211935
sourceloc_ref: wasmgen::LocalIdx,
19221936
expr_builder: &mut wasmgen::ExprBuilder,
19231937
) {
1938+
// we need to fetch the actual source location from the static memory to set as arguments of the error_func
19241939
expr_builder.i32_const(ir::error::ERROR_CODE_FUNCTION_PARAM_TYPE as i32);
19251940
expr_builder.i32_const(0);
1926-
expr_builder.i32_const(0); // todo!(add actual source location)
1927-
expr_builder.i32_const(0);
1928-
expr_builder.i32_const(0);
1929-
expr_builder.i32_const(0);
1930-
expr_builder.i32_const(0);
1941+
// the source location is 5 of u32s
1942+
expr_builder.local_get(sourceloc_ref);
1943+
expr_builder.i32_load(wasmgen::MemArg::new4(0));
1944+
expr_builder.local_get(sourceloc_ref);
1945+
expr_builder.i32_load(wasmgen::MemArg::new4(4));
1946+
expr_builder.local_get(sourceloc_ref);
1947+
expr_builder.i32_load(wasmgen::MemArg::new4(8));
1948+
expr_builder.local_get(sourceloc_ref);
1949+
expr_builder.i32_load(wasmgen::MemArg::new4(12));
1950+
expr_builder.local_get(sourceloc_ref);
1951+
expr_builder.i32_load(wasmgen::MemArg::new4(16));
1952+
// call the error_func with 7 arguments
19311953
expr_builder.call(error_func);
1954+
// the error func is noreturn, so we want to tell wasm that it is indeed noreturn
19321955
expr_builder.unreachable();
19331956
}
19341957
}

lib-backend-wasm/src/lib.rs

+27-9
Original file line numberDiff line numberDiff line change
@@ -189,16 +189,25 @@ fn encode_program(ir_program: &ir::Program, options: Options) -> wasmgen::WasmMo
189189
let pre_traverse::TraverseResult {
190190
string_pool,
191191
thunk_sv,
192+
appl_location_sv,
192193
} = pre_traverse::pre_traverse_funcs(&ir_program.funcs);
193194

194-
let (shifted_string_pool, mut pool_data) =
195+
let (shifted_string_pool, pool_data) =
195196
string_pool.into_shifted_and_buffer(MEM_STACK_SIZE << WASM_PAGE_BITS);
196-
// round up to multiple of WASM_PAGE_SIZE
197-
let required_data_size =
198-
((pool_data.len() as u32) + (WASM_PAGE_SIZE - 1)) & (!(WASM_PAGE_SIZE - 1));
199-
pool_data.resize(required_data_size as usize, 0);
200-
// in terms of WASM_PAGE_SIZE
201-
let globals_num_pages: u32 = required_data_size >> WASM_PAGE_BITS;
197+
198+
assert!(pool_data.len() & 3 == 0); // assert that it is at 4-byte boundary
199+
200+
// make static data for appl locations
201+
let (appl_data, appl_data_encoder) = pre_traverse::make_appl_location_static_data(
202+
appl_location_sv,
203+
(MEM_STACK_SIZE << WASM_PAGE_BITS) + pool_data.len() as u32,
204+
);
205+
206+
assert!(appl_data.len() & 3 == 0); // assert that it is at 4-byte boundary
207+
208+
// in terms of WASM_PAGE_SIZE (rounded up to nearest page boundary)
209+
let globals_num_pages: u32 =
210+
((pool_data.len() + appl_data.len()) as u32 + (WASM_PAGE_SIZE - 1)) >> WASM_PAGE_BITS;
202211

203212
// add linear memory
204213
let memidx: wasmgen::MemIdx = encode_mem(
@@ -214,13 +223,21 @@ fn encode_program(ir_program: &ir::Program, options: Options) -> wasmgen::WasmMo
214223
wasm_module.export_mem(memidx, "linear_memory".to_string());
215224

216225
// initialize pool data
217-
encode_pool_data(
226+
encode_static_data(
218227
&pool_data,
219228
MEM_STACK_SIZE << WASM_PAGE_BITS,
220229
memidx,
221230
&mut wasm_module,
222231
);
223232

233+
// initialize appl data
234+
encode_static_data(
235+
&appl_data,
236+
(MEM_STACK_SIZE << WASM_PAGE_BITS) + pool_data.len() as u32,
237+
memidx,
238+
&mut wasm_module,
239+
);
240+
224241
// garbage collector
225242
let heap = Cheney::new(
226243
&ir_program.struct_types,
@@ -259,6 +276,7 @@ fn encode_program(ir_program: &ir::Program, options: Options) -> wasmgen::WasmMo
259276
globalidx_stackptr,
260277
memidx,
261278
thunk_sv,
279+
appl_data_encoder,
262280
&heap,
263281
&shifted_string_pool,
264282
error_func,
@@ -306,7 +324,7 @@ fn encode_mem(num_pages: u32, wasm_module: &mut wasmgen::WasmModule) -> wasmgen:
306324
wasm_module.add_unbounded_memory(num_pages)
307325
}
308326

309-
fn encode_pool_data(
327+
fn encode_static_data(
310328
pool_data: &[u8],
311329
offset: u32,
312330
memidx: wasmgen::MemIdx,

lib-backend-wasm/src/pre_traverse.rs

+35-3
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,17 @@ pub struct ShiftedStringPool {
2323
#[derive(Default)]
2424
pub struct TraverseResult {
2525
pub string_pool: StringPool,
26-
//pub addressed_funcs: SearchableVec<ir::FuncIdx>, // list of functions called by PrimFunc
2726
// map from [FuncIdx] to tableidx, since [FuncIdx] uniquely determines the thunk content
2827
// (note: we can know the signature from the funcidx)
2928
pub thunk_sv: SearchableVec<Box<[ir::OverloadEntry]>>,
29+
pub appl_location_sv: SearchableVec<ir::SourceLocation>,
3030
}
3131

3232
/*
3333
Traverses the IR to:
3434
- put all string constants in a string pool, and encodes the static data buffer
35-
- put all addressed functions in a vector
35+
- put all overload sets (thunks) in a SearchableVec
36+
- extract all SourceLocations in Appls into a SearchableVec
3637
*/
3738
pub fn pre_traverse_funcs(funcs: &[ir::Func]) -> TraverseResult {
3839
let mut res = TraverseResult::default();
@@ -80,9 +81,14 @@ fn pre_traverse_expr_kind(expr_kind: &ir::ExprKind, res: &mut TraverseResult) {
8081
}
8182
ir::ExprKind::VarName { source: _ } => {}
8283
ir::ExprKind::PrimAppl { prim_inst: _, args } => pre_traverse_exprs(args, res),
83-
ir::ExprKind::Appl { func, args } => {
84+
ir::ExprKind::Appl {
85+
func,
86+
args,
87+
location,
88+
} => {
8489
pre_traverse_expr(func, res);
8590
pre_traverse_exprs(args, res);
91+
res.appl_location_sv.insert_copy(location);
8692
}
8793
ir::ExprKind::DirectAppl { funcidx: _, args } => pre_traverse_exprs(args, res),
8894
ir::ExprKind::Conditional {
@@ -172,3 +178,29 @@ impl ShiftedStringPool {
172178
*self.map.get(str).unwrap()
173179
}
174180
}
181+
182+
// encodes the appl_location_sv into static data
183+
// returns the data and the map from the SourceLocation to the index in memory (using the given `offset` to adjust this index)
184+
pub fn make_appl_location_static_data(
185+
appl_location_sv: SearchableVec<ir::SourceLocation>,
186+
offset: u32,
187+
) -> (Box<[u8]>, HashMap<ir::SourceLocation, u32>) {
188+
let (v, hm) = appl_location_sv.into_parts();
189+
let mut ret_bytes = Vec::new();
190+
// 4 bytes per u32, and 5 u32 to specify the location, so 20 bytes per iterm
191+
let ret_len = v.len() * 20;
192+
ret_bytes.reserve_exact(ret_len);
193+
for sl in v {
194+
ret_bytes.extend_from_slice(&sl.file.to_le_bytes());
195+
ret_bytes.extend_from_slice(&sl.start.line.to_le_bytes());
196+
ret_bytes.extend_from_slice(&sl.start.column.to_le_bytes());
197+
ret_bytes.extend_from_slice(&sl.end.line.to_le_bytes());
198+
ret_bytes.extend_from_slice(&sl.end.column.to_le_bytes());
199+
}
200+
assert!(ret_bytes.len() == ret_len);
201+
let ret_hm: HashMap<ir::SourceLocation, u32> = hm
202+
.into_iter()
203+
.map(|(sl, idx)| (sl, offset + (idx as u32) * 20))
204+
.collect();
205+
(ret_bytes.into_boxed_slice(), ret_hm)
206+
}

lib-frontend-estree/src/func/post_parse.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1695,7 +1695,6 @@ fn post_parse_varname(
16951695
// it's a direct, so we have to synthesise a wrapper func for it
16961696
post_parse_direct_varname(
16971697
es_id.name.as_str(),
1698-
loc,
16991698
parse_ctx,
17001699
depth,
17011700
num_locals,
@@ -1708,7 +1707,6 @@ fn post_parse_varname(
17081707

17091708
fn post_parse_direct_varname(
17101709
name: &str,
1711-
_loc: Option<esSL>,
17121710
parse_ctx: &mut ParseState,
17131711
_depth: usize,
17141712
_num_locals: usize, // current number of IR locals
@@ -2012,6 +2010,7 @@ fn post_parse_call_expr(
20122010
};
20132011
post_parse_call_func_with_params_helper(
20142012
func,
2013+
loc,
20152014
es_call_expr.arguments.into_iter(),
20162015
parse_ctx,
20172016
depth,
@@ -2023,6 +2022,7 @@ fn post_parse_call_expr(
20232022

20242023
fn post_parse_call_func_with_params_helper(
20252024
func_expr: ir::Expr,
2025+
loc: Option<esSL>,
20262026
args_iter: impl ExactSizeIterator<Item = Node> + DoubleEndedIterator<Item = Node>,
20272027
parse_ctx: &mut ParseState,
20282028
depth: usize,
@@ -2038,6 +2038,7 @@ fn post_parse_call_func_with_params_helper(
20382038
kind: ir::ExprKind::Appl {
20392039
func: Box::new(func_expr),
20402040
args: args,
2041+
location: as_ir_sl(&loc, 0 /*FILE*/),
20412042
},
20422043
})
20432044
}
@@ -2056,11 +2057,12 @@ fn post_parse_direct_call_helper(
20562057
// IR should propage constants in order to convert this to a real direct call (perhaps by considering cases based on the param types here)
20572058

20582059
let primfunc_expr: ir::Expr = post_parse_direct_varname(
2059-
func_name, loc, parse_ctx, depth, num_locals, filename, ir_program,
2060+
func_name, parse_ctx, depth, num_locals, filename, ir_program,
20602061
)?;
20612062

20622063
post_parse_call_func_with_params_helper(
20632064
primfunc_expr,
2065+
loc,
20642066
Vec::from(params).into_iter(),
20652067
parse_ctx,
20662068
depth,
@@ -2169,7 +2171,7 @@ fn as_ir_sl(opt_es_sl: &Option<SourceLocation>, fileidx: u32) -> ir::SourceLocat
21692171
},
21702172
ir::Position {
21712173
line: es_sl.end.line as u32,
2172-
column: es_sl.start.column as u32,
2174+
column: es_sl.end.column as u32,
21732175
},
21742176
),
21752177
None => (

lib-ir/src/lib.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ pub enum ExprKind {
191191
Appl {
192192
func: Box<Expr>,
193193
args: Box<[Expr]>,
194+
location: SourceLocation, // will be displayed in the error message if the signature mismatches
194195
}, // function application (operators are functions too). Closure parameter is implicitly prepended to the argument list. Called using Source indirect calling convention (closure, length, and callerid as i32 params; others are Any and on unprotected stack). Static type of func must be func.
195196
DirectAppl {
196197
funcidx: FuncIdx,
@@ -225,7 +226,7 @@ pub enum ExprKind {
225226
}, // returns the value of the last expression, or `undefined` if there are zero expressions
226227
Trap {
227228
code: u32,
228-
location: SourceLocation,
229+
location: SourceLocation, // will be displayed in the error message
229230
}, // has Void type
230231
}
231232

@@ -285,7 +286,7 @@ pub enum Builtin {
285286
}
286287
pub const NUM_BUILTINS: u8 = Builtin::UnaryMinus as u8 + 1;
287288

288-
#[derive(Default, Debug, Copy, Clone)]
289+
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
289290
pub struct Position {
290291
pub line: u32,
291292
pub column: u32,
@@ -294,7 +295,7 @@ pub struct Position {
294295
/*
295296
Represents a location in a source file.
296297
*/
297-
#[derive(Default, Debug, Copy, Clone)]
298+
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash)]
298299
pub struct SourceLocation {
299300
pub file: u32,
300301
pub start: Position,

0 commit comments

Comments
 (0)