@@ -57,6 +57,7 @@ type TaggedConstants = (Box<[Value]>, HashMap<SsaValueId, usize>);
5757
5858pub ( crate ) struct CompiledTrace {
5959 pub ( crate ) entry : * const u8 ,
60+ pub ( crate ) tail_entry : * const u8 ,
6061 pub ( crate ) keepalive : TraceKeepAlive ,
6162 pub ( crate ) code : Vec < u8 > ,
6263 pub ( crate ) lowering_kind : TraceLoweringKind ,
@@ -65,13 +66,15 @@ pub(crate) struct CompiledTrace {
6566pub ( crate ) struct TraceKeepAlive {
6667 exec : ExecutableBuffer ,
6768 _tagged_constants : Box < [ Value ] > ,
69+ dependencies : Vec < TraceKeepAlive > ,
6870}
6971
7072impl TraceKeepAlive {
7173 fn from_code ( code : & [ u8 ] , tagged_constants : Box < [ Value ] > ) -> VmResult < Self > {
7274 Ok ( Self {
7375 exec : ExecutableBuffer :: new ( code) ?,
7476 _tagged_constants : tagged_constants,
77+ dependencies : Vec :: new ( ) ,
7578 } )
7679 }
7780
@@ -94,6 +97,10 @@ impl CompiledTailFunction {
9497 pub ( crate ) fn code_len ( & self ) -> usize {
9598 self . code . len ( )
9699 }
100+
101+ pub ( crate ) fn into_parts ( self ) -> ( * const u8 , TraceKeepAlive , Vec < u8 > ) {
102+ ( self . entry , self . _keepalive , self . code )
103+ }
97104}
98105
99106fn tail_entry_signature ( pointer_type : cranelift_codegen:: ir:: Type ) -> Signature {
@@ -222,6 +229,89 @@ pub(crate) fn compile_system_tail_wrapper(root_entry: *const u8) -> VmResult<Com
222229 )
223230}
224231
232+ pub ( crate ) fn compile_tail_trace_dispatcher (
233+ trace_entry : * const u8 ,
234+ trace_id : usize ,
235+ links : & [ ( i32 , usize ) ] ,
236+ ) -> VmResult < CompiledTailFunction > {
237+ let trace_entry = trace_entry as usize ;
238+ let links = links. to_vec ( ) ;
239+ let direct_link_offset = detect_native_stack_layout ( ) ?. vm_jit_native_direct_link_count_offset ;
240+ let active_trace_offset =
241+ detect_native_stack_layout ( ) ?. vm_jit_native_active_direct_trace_id_offset ;
242+ compile_standalone_native_function (
243+ "pd_vm_tail_trace_dispatch" ,
244+ |pointer_type, _| tail_entry_signature ( pointer_type) ,
245+ move |builder, pointer_type, default_call_conv| {
246+ let entry = builder. create_block ( ) ;
247+ let return_status = builder. create_block ( ) ;
248+ builder. append_block_params_for_function_params ( entry) ;
249+ builder. append_block_param ( return_status, types:: I32 ) ;
250+ builder. switch_to_block ( entry) ;
251+ let vm_ptr = builder. block_params ( entry) [ 0 ] ;
252+ let trace_id = i64:: try_from ( trace_id)
253+ . map_err ( |_| VmError :: JitNative ( "native trace id exceeds i64" . to_string ( ) ) ) ?;
254+ let trace_id = builder. ins ( ) . iconst ( pointer_type, trace_id) ;
255+ builder
256+ . ins ( )
257+ . store ( MemFlags :: new ( ) , trace_id, vm_ptr, active_trace_offset) ;
258+ let trace_entry = iconst_ptr_from_addr ( builder, pointer_type, trace_entry) ?;
259+ let trace_signature =
260+ builder. import_signature ( entry_signature ( pointer_type, default_call_conv) ) ;
261+ let call = builder
262+ . ins ( )
263+ . call_indirect ( trace_signature, trace_entry, & [ vm_ptr] ) ;
264+ let status = builder. inst_results ( call) [ 0 ] ;
265+
266+ for ( linked_status, slot_address) in links {
267+ let slot_check = builder. create_block ( ) ;
268+ let next = builder. create_block ( ) ;
269+ let linked = builder. create_block ( ) ;
270+ builder. append_block_param ( next, types:: I32 ) ;
271+ let matches =
272+ builder
273+ . ins ( )
274+ . icmp_imm ( IntCC :: Equal , status, i64:: from ( linked_status) ) ;
275+ builder
276+ . ins ( )
277+ . brif ( matches, slot_check, & [ ] , next, & [ status. into ( ) ] ) ;
278+
279+ builder. switch_to_block ( slot_check) ;
280+ let slot_address = iconst_ptr_from_addr ( builder, pointer_type, slot_address) ?;
281+ let target = builder
282+ . ins ( )
283+ . load ( pointer_type, MemFlags :: new ( ) , slot_address, 0 ) ;
284+ let is_null = builder. ins ( ) . icmp_imm ( IntCC :: Equal , target, 0 ) ;
285+ builder
286+ . ins ( )
287+ . brif ( is_null, return_status, & [ status. into ( ) ] , linked, & [ ] ) ;
288+
289+ builder. switch_to_block ( linked) ;
290+ let direct_count =
291+ builder
292+ . ins ( )
293+ . load ( types:: I64 , MemFlags :: new ( ) , vm_ptr, direct_link_offset) ;
294+ let direct_count = builder. ins ( ) . iadd_imm ( direct_count, 1 ) ;
295+ builder
296+ . ins ( )
297+ . store ( MemFlags :: new ( ) , direct_count, vm_ptr, direct_link_offset) ;
298+ let tail_signature = builder. import_signature ( tail_entry_signature ( pointer_type) ) ;
299+ builder
300+ . ins ( )
301+ . return_call_indirect ( tail_signature, target, & [ vm_ptr] ) ;
302+
303+ builder. switch_to_block ( next) ;
304+ }
305+
306+ builder. ins ( ) . jump ( return_status, & [ status. into ( ) ] ) ;
307+ builder. switch_to_block ( return_status) ;
308+ let status = builder. block_params ( return_status) [ 0 ] ;
309+ builder. ins ( ) . return_ ( & [ status] ) ;
310+ Ok ( ( ) )
311+ } ,
312+ )
313+ }
314+
225315fn tail_owned_entry_signature ( pointer_type : cranelift_codegen:: ir:: Type ) -> Signature {
226316 let mut signature = tail_entry_signature ( pointer_type) ;
227317 signature. params . push ( AbiParam :: new ( pointer_type) ) ;
@@ -343,7 +433,7 @@ fn try_compile_ssa_trace(
343433 ssa : & SsaTrace ,
344434 internal_links : & [ FusedRegionLink ] ,
345435 interrupt_settings : Option < NativeInterruptSettings > ,
346- profile : NativeCompileProfile ,
436+ _profile : NativeCompileProfile ,
347437 drop_contract_events_enabled : bool ,
348438) -> VmResult < Option < CompiledTrace > > {
349439 if drop_contract_events_enabled {
@@ -355,15 +445,15 @@ fn try_compile_ssa_trace(
355445
356446 let layout = detect_native_stack_layout ( ) ?;
357447 let offsets = resolve_offsets ( layout) ?;
358- let isa = native_isa ( profile ) ?;
448+ let isa = native_tail_isa ( ) ?;
359449
360450 let jit_builder = JITBuilder :: with_isa ( isa, cranelift_module:: default_libcall_names ( ) ) ;
361451 let mut module = JITModule :: new ( jit_builder) ;
362452 let pointer_type = module. target_config ( ) . pointer_type ( ) ;
363453 let call_conv = module. target_config ( ) . default_call_conv ;
364454
365455 let mut ctx = module. make_context ( ) ;
366- ctx. func . signature = entry_signature ( pointer_type, call_conv ) ;
456+ ctx. func . signature = tail_entry_signature ( pointer_type) ;
367457 let clone_value_sig = clone_value_signature ( pointer_type, call_conv) ;
368458 let non_yielding_host_call_sig = non_yielding_host_call_signature ( pointer_type, call_conv) ;
369459 let value_slot_sig = value_slot_signature ( pointer_type, call_conv) ;
@@ -762,6 +852,7 @@ fn try_compile_ssa_trace(
762852
763853 Ok ( Some ( CompiledTrace {
764854 entry,
855+ tail_entry : entry,
765856 keepalive,
766857 code,
767858 lowering_kind : TraceLoweringKind :: Ssa ,
@@ -5194,7 +5285,7 @@ pub(crate) fn compile_trace(
51945285 return Err ( VmError :: InvalidFuelCheckInterval ( 0 ) ) ;
51955286 }
51965287
5197- try_compile_ssa_trace (
5288+ let body = try_compile_ssa_trace (
51985289 trace,
51995290 & trace. ssa ,
52005291 internal_links,
@@ -5207,6 +5298,19 @@ pub(crate) fn compile_trace(
52075298 "SSA native lowering does not support trace {} at root_ip {}" ,
52085299 trace. id, trace. root_ip
52095300 ) )
5301+ } ) ?;
5302+ let tail_entry = body. tail_entry ;
5303+ let lowering_kind = body. lowering_kind ;
5304+ let mut code = body. code ;
5305+ let mut wrapper = compile_system_tail_wrapper ( tail_entry) ?;
5306+ code. extend_from_slice ( & wrapper. code ) ;
5307+ wrapper. _keepalive . dependencies . push ( body. keepalive ) ;
5308+ Ok ( CompiledTrace {
5309+ entry : wrapper. entry ,
5310+ tail_entry,
5311+ keepalive : wrapper. _keepalive ,
5312+ code,
5313+ lowering_kind,
52105314 } )
52115315}
52125316
0 commit comments