11use cranelift_codegen:: cursor:: FuncCursor ;
22use cranelift_codegen:: ir;
3- use cranelift_codegen:: ir:: immediates:: Offset32 ;
3+ use cranelift_codegen:: ir:: immediates:: { Imm64 , Offset32 } ;
44use cranelift_codegen:: ir:: types:: * ;
55use cranelift_codegen:: ir:: {
66 AbiParam , ArgumentPurpose , ExtFuncData , ExternalName , FuncRef , Function , InstBuilder , Signature ,
@@ -312,8 +312,29 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
312312 } )
313313 }
314314
315- fn make_table ( & mut self , _func : & mut ir:: Function , _index : TableIndex ) -> ir:: Table {
316- unimplemented ! ( "make_table" ) ;
315+ fn make_table ( & mut self , func : & mut ir:: Function , _index : TableIndex ) -> ir:: Table {
316+ let pointer_bytes = self . pointer_bytes ( ) ;
317+ let base_gv_addr = func. create_global_value ( ir:: GlobalValueData :: VMContext {
318+ offset : Offset32 :: new ( pointer_bytes as i32 * 2 ) ,
319+ } ) ;
320+ let base_gv = func. create_global_value ( ir:: GlobalValueData :: Deref {
321+ base : base_gv_addr,
322+ offset : 0 . into ( ) ,
323+ } ) ;
324+ let bound_gv_addr = func. create_global_value ( ir:: GlobalValueData :: VMContext {
325+ offset : Offset32 :: new ( pointer_bytes as i32 * 3 ) ,
326+ } ) ;
327+ let bound_gv = func. create_global_value ( ir:: GlobalValueData :: Deref {
328+ base : bound_gv_addr,
329+ offset : 0 . into ( ) ,
330+ } ) ;
331+
332+ func. create_table ( ir:: TableData {
333+ base_gv,
334+ min_size : Imm64 :: new ( 0 ) ,
335+ bound_gv,
336+ element_size : Imm64 :: new ( i64:: from ( self . pointer_bytes ( ) as i64 ) ) ,
337+ } )
317338 }
318339
319340 fn make_indirect_sig ( & mut self , func : & mut ir:: Function , index : SignatureIndex ) -> ir:: SigRef {
@@ -338,17 +359,31 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
338359 & mut self ,
339360 mut pos : FuncCursor ,
340361 table_index : TableIndex ,
341- _table : ir:: Table ,
362+ table : ir:: Table ,
342363 _sig_index : SignatureIndex ,
343364 sig_ref : ir:: SigRef ,
344365 callee : ir:: Value ,
345366 call_args : & [ ir:: Value ] ,
346367 ) -> WasmResult < ir:: Inst > {
347- // TODO: Cranelift's call_indirect doesn't implement bounds checking
348- // or signature checking, so we need to implement it ourselves.
349368 debug_assert_eq ! ( table_index, 0 , "non-default tables not supported yet" ) ;
369+
370+ let callee_ty = pos. func . dfg . value_type ( callee) ;
371+ debug_assert_eq ! ( callee_ty, I32 ) ;
372+
373+ // For some reason table_addr only works with I64.
374+ let callee_i64 = pos. ins ( ) . uextend ( I64 , callee) ;
375+ let table_entry_addr = pos. ins ( ) . table_addr ( I64 , table, callee_i64, 0 ) ;
376+
377+ // Dereference table_entry_addr to get the function address.
378+ let mut mem_flags = ir:: MemFlags :: new ( ) ;
379+ mem_flags. set_notrap ( ) ;
380+ mem_flags. set_aligned ( ) ;
381+ let func_addr = pos
382+ . ins ( )
383+ . load ( self . pointer_type ( ) , mem_flags, table_entry_addr, 0 ) ;
384+
350385 let real_call_args = FuncEnvironment :: get_real_call_args ( pos. func , call_args) ;
351- Ok ( pos. ins ( ) . call_indirect ( sig_ref, callee , & real_call_args) )
386+ Ok ( pos. ins ( ) . call_indirect ( sig_ref, func_addr , & real_call_args) )
352387 }
353388
354389 fn translate_call (
0 commit comments