2025-08-29 02:05:39 +09:00
//! Handle-based extern thunks used by the JIT runtime path.
//! Moved out of builder.rs to keep files small and responsibilities clear.
#[ cfg(feature = " cranelift-jit " ) ]
use crate ::jit ::events ;
#[ cfg(feature = " cranelift-jit " ) ]
use crate ::jit ::r#extern ::collections as c ;
2025-08-30 08:54:15 +09:00
#[ cfg(feature = " cranelift-jit " ) ]
2025-09-03 09:12:39 +09:00
use crate ::jit ::r#extern ::host_bridge as hb ;
#[ cfg(feature = " cranelift-jit " ) ]
2025-08-30 08:54:15 +09:00
use crate ::runtime ::plugin_loader_unified ;
#[ cfg(feature = " cranelift-jit " ) ]
use crate ::runtime ::plugin_loader_v2 ::PluginBoxV2 ;
2025-08-29 02:05:39 +09:00
2025-08-30 22:52:16 +09:00
// ---- Generic Birth (handle) ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_box_birth_h ( type_id : i64 ) -> i64 {
// Map type_id -> type name and create via plugin host; return runtime handle
if type_id < = 0 { return 0 ; }
let tid = type_id as u32 ;
let name_opt = crate ::runtime ::plugin_loader_unified ::get_global_plugin_host ( )
. read ( ) . ok ( )
. and_then ( | h | h . config_ref ( ) . map ( | cfg | cfg . box_types . clone ( ) ) )
. and_then ( | m | m . into_iter ( ) . find ( | ( _k , v ) | * v = = tid ) . map ( | ( k , _v ) | k ) ) ;
if let Some ( box_type ) = name_opt {
if let Ok ( host ) = crate ::runtime ::get_global_plugin_host ( ) . read ( ) {
if let Ok ( b ) = host . create_box ( & box_type , & [ ] ) {
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::from ( b ) ;
let h = crate ::jit ::rt ::handles ::to_handle ( arc ) ;
events ::emit_runtime ( serde_json ::json! ( { " id " : " nyash.box.birth_h " , " box_type " : box_type , " type_id " : tid , " handle " : h } ) , " hostcall " , " <jit> " ) ;
return h as i64 ;
} else {
events ::emit_runtime ( serde_json ::json! ( { " id " : " nyash.box.birth_h " , " error " : " create_failed " , " box_type " : box_type , " type_id " : tid } ) , " hostcall " , " <jit> " ) ;
}
}
} else {
events ::emit_runtime ( serde_json ::json! ( { " id " : " nyash.box.birth_h " , " error " : " type_map_failed " , " type_id " : tid } ) , " hostcall " , " <jit> " ) ;
}
0
}
// Generic birth with args on JIT side: (type_id, argc, a1, a2) -> handle
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_box_birth_i64 ( type_id : i64 , argc : i64 , a1 : i64 , a2 : i64 ) -> i64 {
use crate ::runtime ::plugin_loader_v2 ::PluginBoxV2 ;
if type_id < = 0 { return 0 ; }
// Resolve invoke for the type by creating a temp instance
let mut invoke : Option < unsafe extern " C " fn ( u32 , u32 , u32 , * const u8 , usize , * mut u8 , * mut usize ) ->i32 > = None ;
let mut box_type = String ::new ( ) ;
if let Some ( name ) = crate ::runtime ::plugin_loader_unified ::get_global_plugin_host ( )
. read ( ) . ok ( )
. and_then ( | h | h . config_ref ( ) . map ( | cfg | cfg . box_types . clone ( ) ) )
. and_then ( | m | m . into_iter ( ) . find ( | ( _k , v ) | * v = = ( type_id as u32 ) ) . map ( | ( k , _v ) | k ) )
{
box_type = name ;
if let Ok ( host ) = crate ::runtime ::get_global_plugin_host ( ) . read ( ) {
if let Ok ( b ) = host . create_box ( & box_type , & [ ] ) {
if let Some ( p ) = b . as_any ( ) . downcast_ref ::< PluginBoxV2 > ( ) { invoke = Some ( p . inner . invoke_fn ) ; }
}
}
}
if invoke . is_none ( ) {
events ::emit_runtime ( serde_json ::json! ( { " id " : " nyash.box.birth_i64 " , " error " : " no_invoke " , " type_id " : type_id } ) , " hostcall " , " <jit> " ) ;
return 0 ;
}
let method_id : u32 = 0 ; let instance_id : u32 = 0 ;
// Build TLV from a1/a2
let nargs = argc . max ( 0 ) as usize ;
let mut buf = crate ::runtime ::plugin_ffi_common ::encode_tlv_header ( nargs as u16 ) ;
let mut encode_val = | h : i64 | {
if h > 0 {
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( h as u64 ) {
if let Some ( p ) = obj . as_any ( ) . downcast_ref ::< PluginBoxV2 > ( ) {
let host = crate ::runtime ::get_global_plugin_host ( ) ;
if let Ok ( hg ) = host . read ( ) {
if p . box_type = = " StringBox " {
if let Ok ( Some ( sb ) ) = hg . invoke_instance_method ( " StringBox " , " toUtf8 " , p . instance_id ( ) , & [ ] ) {
if let Some ( s ) = sb . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) { crate ::runtime ::plugin_ffi_common ::encode ::string ( & mut buf , & s . value ) ; return ; }
}
} else if p . box_type = = " IntegerBox " {
if let Ok ( Some ( ibx ) ) = hg . invoke_instance_method ( " IntegerBox " , " get " , p . instance_id ( ) , & [ ] ) {
if let Some ( i ) = ibx . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { crate ::runtime ::plugin_ffi_common ::encode ::i64 ( & mut buf , i . value ) ; return ; }
}
}
}
crate ::runtime ::plugin_ffi_common ::encode ::plugin_handle ( & mut buf , p . inner . type_id , p . instance_id ( ) ) ;
return ;
}
}
}
crate ::runtime ::plugin_ffi_common ::encode ::i64 ( & mut buf , h ) ;
} ;
if nargs > = 1 { encode_val ( a1 ) ; }
if nargs > = 2 { encode_val ( a2 ) ; }
// Invoke
let mut out = vec! [ 0 u8 ; 1024 ] ; let mut out_len : usize = out . len ( ) ;
let rc = unsafe { invoke . unwrap ( ) ( type_id as u32 , method_id , instance_id , buf . as_ptr ( ) , buf . len ( ) , out . as_mut_ptr ( ) , & mut out_len ) } ;
if rc ! = 0 { events ::emit_runtime ( serde_json ::json! ( { " id " : " nyash.box.birth_i64 " , " error " : " invoke_failed " , " type_id " : type_id } ) , " hostcall " , " <jit> " ) ; return 0 ; }
if let Some ( ( tag , _sz , payload ) ) = crate ::runtime ::plugin_ffi_common ::decode ::tlv_first ( & out [ .. out_len ] ) {
if tag = = 8 & & payload . len ( ) = = 8 {
let mut t = [ 0 u8 ; 4 ] ; t . copy_from_slice ( & payload [ 0 .. 4 ] ) ; let mut i = [ 0 u8 ; 4 ] ; i . copy_from_slice ( & payload [ 4 .. 8 ] ) ;
let r_type = u32 ::from_le_bytes ( t ) ; let r_inst = u32 ::from_le_bytes ( i ) ;
let pb = crate ::runtime ::plugin_loader_v2 ::make_plugin_box_v2 ( box_type . clone ( ) , r_type , r_inst , invoke . unwrap ( ) ) ;
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::new ( pb ) ;
let h = crate ::jit ::rt ::handles ::to_handle ( arc ) ;
events ::emit_runtime ( serde_json ::json! ( { " id " : " nyash.box.birth_i64 " , " box_type " : box_type , " type_id " : type_id , " argc " : nargs , " handle " : h } ) , " hostcall " , " <jit> " ) ;
return h as i64 ;
}
}
events ::emit_runtime ( serde_json ::json! ( { " id " : " nyash.box.birth_i64 " , " error " : " decode_failed " , " type_id " : type_id } ) , " hostcall " , " <jit> " ) ;
0
}
// ---- Handle helpers ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_handle_of ( v : i64 ) -> i64 {
// If already a positive handle, pass through
2025-09-06 10:59:33 +09:00
if std ::env ::var ( " NYASH_JIT_TRACE_LEN " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! ( " [JIT-HANDLE_OF] in v= {} " , v ) ;
}
2025-08-30 22:52:16 +09:00
if v > 0 { return v ; }
// Otherwise interpret as legacy param index and convert BoxRef -> handle
if v > = 0 {
let idx = v as usize ;
let mut out : i64 = 0 ;
crate ::jit ::rt ::with_legacy_vm_args ( | args | {
if let Some ( crate ::backend ::vm ::VMValue ::BoxRef ( b ) ) = args . get ( idx ) {
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::from ( b . clone ( ) ) ;
out = crate ::jit ::rt ::handles ::to_handle ( arc ) as i64 ;
}
} ) ;
2025-09-06 10:59:33 +09:00
if std ::env ::var ( " NYASH_JIT_TRACE_LEN " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! ( " [JIT-HANDLE_OF] param_idx= {} out_handle= {} " , idx , out ) ;
}
2025-08-30 22:52:16 +09:00
return out ;
}
0
}
2025-08-29 02:05:39 +09:00
// ---- Math (native f64) ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_math_sin_f64 ( x : f64 ) -> f64 { x . sin ( ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_math_cos_f64 ( x : f64 ) -> f64 { x . cos ( ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_math_abs_f64 ( x : f64 ) -> f64 { x . abs ( ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_math_min_f64 ( a : f64 , b : f64 ) -> f64 { a . min ( b ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_math_max_f64 ( a : f64 , b : f64 ) -> f64 { a . max ( b ) }
2025-08-31 03:03:04 +09:00
// ---- Console (handle) ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_console_birth_h ( ) -> i64 {
if let Ok ( host_g ) = crate ::runtime ::get_global_plugin_host ( ) . read ( ) {
if let Ok ( b ) = host_g . create_box ( " ConsoleBox " , & [ ] ) {
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::from ( b ) ;
let h = crate ::jit ::rt ::handles ::to_handle ( arc ) ;
return h as i64 ;
}
}
0
}
// ---- Runtime/GC stubs ----
// Minimal no-op checkpoints and barriers for reservation. They optionally trace when envs are set.
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_rt_checkpoint ( ) -> i64 {
2025-09-03 05:04:56 +09:00
if crate ::config ::env ::runtime_checkpoint_trace ( ) {
2025-08-31 03:03:04 +09:00
eprintln! ( " [nyash.rt.checkpoint] reached " ) ;
}
2025-09-01 23:44:34 +09:00
// Bridge to GC/scheduler if configured
crate ::runtime ::global_hooks ::safepoint_and_poll ( ) ;
2025-08-31 03:03:04 +09:00
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_gc_barrier_write ( handle_or_ptr : u64 ) -> i64 {
let _ = handle_or_ptr ; // reserved; currently unused
2025-09-03 05:04:56 +09:00
if crate ::config ::env ::gc_barrier_trace ( ) {
2025-08-31 03:03:04 +09:00
eprintln! ( " [nyash.gc.barrier_write] h=0x {:x} " , handle_or_ptr ) ;
}
0
}
2025-08-29 02:05:39 +09:00
// ---- Array (handle) ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_array_len_h ( handle : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_ARRAY_LEN_H , " decision " :" allow " , " argc " :1 , " arg_types " :[ " Handle " ] } ) , " hostcall " , " <jit> " ) ;
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( arr ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::array ::ArrayBox > ( ) {
if let Some ( ib ) = arr . length ( ) . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { return ib . value ; }
}
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_array_get_h ( handle : u64 , idx : i64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_ARRAY_GET_H , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " I64 " ] } ) , " hostcall " , " <jit> " ) ;
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( arr ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::array ::ArrayBox > ( ) {
let val = arr . get ( Box ::new ( crate ::box_trait ::IntegerBox ::new ( idx ) ) ) ;
if let Some ( ib ) = val . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { return ib . value ; }
}
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_array_last_h ( handle : u64 ) -> i64 {
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( arr ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::array ::ArrayBox > ( ) {
if let Ok ( items ) = arr . items . read ( ) {
if let Some ( last ) = items . last ( ) {
if let Some ( ib ) = last . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { return ib . value ; }
}
}
}
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_array_set_h ( handle : u64 , idx : i64 , val : i64 ) -> i64 {
use crate ::jit ::hostcall_registry ::{ classify , HostcallKind } ;
let sym = c ::SYM_ARRAY_SET_H ;
let pol = crate ::jit ::policy ::current ( ) ;
let wh = pol . hostcall_whitelist ;
if classify ( sym ) = = HostcallKind ::Mutating & & pol . read_only & & ! wh . iter ( ) . any ( | s | s = = sym ) {
events ::emit_runtime ( serde_json ::json! ( { " id " : sym , " decision " :" fallback " , " reason " :" policy_denied_mutating " } ) , " hostcall " , " <jit> " ) ;
return 0 ;
}
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( arr ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::array ::ArrayBox > ( ) {
let _ = arr . set ( Box ::new ( crate ::box_trait ::IntegerBox ::new ( idx ) ) , Box ::new ( crate ::box_trait ::IntegerBox ::new ( val ) ) ) ;
events ::emit_runtime ( serde_json ::json! ( { " id " : sym , " decision " :" allow " , " argc " :3 , " arg_types " :[ " Handle " , " I64 " , " I64 " ] } ) , " hostcall " , " <jit> " ) ;
return 0 ;
}
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_array_push_h ( handle : u64 , val : i64 ) -> i64 {
use crate ::jit ::hostcall_registry ::{ classify , HostcallKind } ;
let sym = c ::SYM_ARRAY_PUSH_H ;
let pol = crate ::jit ::policy ::current ( ) ;
let wh = pol . hostcall_whitelist ;
if classify ( sym ) = = HostcallKind ::Mutating & & pol . read_only & & ! wh . iter ( ) . any ( | s | s = = sym ) {
events ::emit_runtime ( serde_json ::json! ( { " id " : sym , " decision " :" fallback " , " reason " :" policy_denied_mutating " } ) , " hostcall " , " <jit> " ) ;
return 0 ;
}
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( arr ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::array ::ArrayBox > ( ) {
let ib = crate ::box_trait ::IntegerBox ::new ( val ) ;
let _ = arr . push ( Box ::new ( ib ) ) ;
events ::emit_runtime ( serde_json ::json! ( { " id " : sym , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " I64 " ] } ) , " hostcall " , " <jit> " ) ;
return 0 ;
}
}
0
}
// ---- Map (handle) ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_map_size_h ( handle : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_MAP_SIZE_H , " decision " :" allow " , " argc " :1 , " arg_types " :[ " Handle " ] } ) , " hostcall " , " <jit> " ) ;
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( map ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::map_box ::MapBox > ( ) {
if let Some ( ib ) = map . size ( ) . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { return ib . value ; }
}
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_map_get_h ( handle : u64 , key : i64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_MAP_GET_H , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " I64 " ] } ) , " hostcall " , " <jit> " ) ;
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( map ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::map_box ::MapBox > ( ) {
let key_box = Box ::new ( crate ::box_trait ::IntegerBox ::new ( key ) ) ;
let val = map . get ( key_box ) ;
if let Some ( ib ) = val . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { return ib . value ; }
}
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_map_get_hh ( map_h : u64 , key_h : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_MAP_GET_HH , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " Handle " ] } ) , " hostcall " , " <jit> " ) ;
let map_arc = crate ::jit ::rt ::handles ::get ( map_h ) ;
let key_arc = crate ::jit ::rt ::handles ::get ( key_h ) ;
if let ( Some ( mobj ) , Some ( kobj ) ) = ( map_arc , key_arc ) {
if let Some ( map ) = mobj . as_any ( ) . downcast_ref ::< crate ::boxes ::map_box ::MapBox > ( ) {
let key_box : Box < dyn crate ::box_trait ::NyashBox > = kobj . share_box ( ) ;
let val = map . get ( key_box ) ;
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::from ( val ) ;
let h = crate ::jit ::rt ::handles ::to_handle ( arc ) ;
return h as i64 ;
}
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_map_set_h ( handle : u64 , key : i64 , val : i64 ) -> i64 {
use crate ::jit ::hostcall_registry ::{ classify , HostcallKind } ;
let sym = c ::SYM_MAP_SET_H ;
let pol = crate ::jit ::policy ::current ( ) ;
let wh = pol . hostcall_whitelist ;
if classify ( sym ) = = HostcallKind ::Mutating & & pol . read_only & & ! wh . iter ( ) . any ( | s | s = = sym ) {
events ::emit_runtime ( serde_json ::json! ( { " id " : sym , " decision " :" fallback " , " reason " :" policy_denied_mutating " } ) , " hostcall " , " <jit> " ) ;
return 0 ;
}
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( map ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::map_box ::MapBox > ( ) {
let key_box = Box ::new ( crate ::box_trait ::IntegerBox ::new ( key ) ) ;
let val_box = Box ::new ( crate ::box_trait ::IntegerBox ::new ( val ) ) ;
let _ = map . set ( key_box , val_box ) ;
events ::emit_runtime ( serde_json ::json! ( { " id " : sym , " decision " :" allow " , " argc " :3 , " arg_types " :[ " Handle " , " I64 " , " I64 " ] } ) , " hostcall " , " <jit> " ) ;
return 0 ;
}
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_map_has_h ( handle : u64 , key : i64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_MAP_HAS_H , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " I64 " ] } ) , " hostcall " , " <jit> " ) ;
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( map ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::map_box ::MapBox > ( ) {
let key_box = Box ::new ( crate ::box_trait ::IntegerBox ::new ( key ) ) ;
let val = map . get ( key_box ) ;
let is_present = ! val . as_any ( ) . is ::< crate ::box_trait ::VoidBox > ( ) ;
return if is_present { 1 } else { 0 } ;
}
}
0
}
// ---- Any helpers ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_any_length_h ( handle : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_ANY_LEN_H , " decision " :" allow " , " argc " :1 , " arg_types " :[ " Handle " ] } ) , " hostcall " , " <jit> " ) ;
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( arr ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::array ::ArrayBox > ( ) {
if let Some ( ib ) = arr . length ( ) . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { return ib . value ; }
}
if let Some ( sb ) = obj . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) {
return sb . value . len ( ) as i64 ;
}
2025-08-29 21:39:47 +09:00
} else {
// Fallback: some call sites may still pass a parameter index instead of a handle (legacy path)
// Try to interpret small values as param index and read from legacy VM args
if handle < = 16 {
let idx = handle as usize ;
let val = crate ::jit ::rt ::with_legacy_vm_args ( | args | args . get ( idx ) . cloned ( ) ) ;
if let Some ( v ) = val {
match v {
crate ::backend ::vm ::VMValue ::BoxRef ( b ) = > {
if let Some ( arr ) = b . as_any ( ) . downcast_ref ::< crate ::boxes ::array ::ArrayBox > ( ) {
if let Some ( ib ) = arr . length ( ) . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { return ib . value ; }
}
if let Some ( sb ) = b . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) {
return sb . value . len ( ) as i64 ;
}
}
crate ::backend ::vm ::VMValue ::String ( s ) = > { return s . len ( ) as i64 ; }
_ = > { }
}
}
}
2025-08-29 02:05:39 +09:00
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_any_is_empty_h ( handle : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_ANY_IS_EMPTY_H , " decision " :" allow " , " argc " :1 , " arg_types " :[ " Handle " ] } ) , " hostcall " , " <jit> " ) ;
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( arr ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::array ::ArrayBox > ( ) {
if let Ok ( items ) = arr . items . read ( ) { return if items . is_empty ( ) { 1 } else { 0 } ; }
}
if let Some ( sb ) = obj . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) {
return if sb . value . is_empty ( ) { 1 } else { 0 } ;
}
if let Some ( map ) = obj . as_any ( ) . downcast_ref ::< crate ::boxes ::map_box ::MapBox > ( ) {
if let Some ( ib ) = map . size ( ) . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { return if ib . value = = 0 { 1 } else { 0 } ; }
}
}
0
}
2025-08-30 08:54:15 +09:00
// ---- By-name plugin invoke (generic receiver; resolves method_id at runtime) ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_plugin_invoke_name_getattr_i64 ( argc : i64 , a0 : i64 , a1 : i64 , a2 : i64 ) -> i64 {
nyash_plugin_invoke_name_common_i64 ( " getattr " , argc , a0 , a1 , a2 )
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_plugin_invoke_name_call_i64 ( argc : i64 , a0 : i64 , a1 : i64 , a2 : i64 ) -> i64 {
nyash_plugin_invoke_name_common_i64 ( " call " , argc , a0 , a1 , a2 )
}
#[ cfg(feature = " cranelift-jit " ) ]
2025-08-30 22:52:16 +09:00
fn nyash_plugin_invoke_name_common_i64 ( method : & str , argc : i64 , a0 : i64 , a1 : i64 , a2 : i64 ) -> i64 {
2025-08-30 08:54:15 +09:00
// Resolve receiver
let mut instance_id : u32 = 0 ;
let mut type_id : u32 = 0 ;
let mut box_type : Option < String > = None ;
let mut invoke : Option < unsafe extern " C " fn ( u32 , u32 , u32 , * const u8 , usize , * mut u8 , * mut usize ) ->i32 > = None ;
if a0 > 0 {
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( a0 as u64 ) {
if let Some ( p ) = obj . as_any ( ) . downcast_ref ::< PluginBoxV2 > ( ) {
instance_id = p . instance_id ( ) ; type_id = p . inner . type_id ; box_type = Some ( p . box_type . clone ( ) ) ;
invoke = Some ( p . inner . invoke_fn ) ;
}
}
}
if invoke . is_none ( ) & & std ::env ::var ( " NYASH_JIT_ARGS_HANDLE_ONLY " ) . ok ( ) . as_deref ( ) ! = Some ( " 1 " ) {
crate ::jit ::rt ::with_legacy_vm_args ( | args | {
let idx = a0 . max ( 0 ) as usize ;
if let Some ( crate ::backend ::vm ::VMValue ::BoxRef ( b ) ) = args . get ( idx ) {
if let Some ( p ) = b . as_any ( ) . downcast_ref ::< PluginBoxV2 > ( ) {
instance_id = p . instance_id ( ) ; type_id = p . inner . type_id ; box_type = Some ( p . box_type . clone ( ) ) ;
invoke = Some ( p . inner . invoke_fn ) ;
}
}
} ) ;
}
if invoke . is_none ( ) {
crate ::jit ::rt ::with_legacy_vm_args ( | args | {
for v in args . iter ( ) {
if let crate ::backend ::vm ::VMValue ::BoxRef ( b ) = v {
if let Some ( p ) = b . as_any ( ) . downcast_ref ::< PluginBoxV2 > ( ) {
instance_id = p . instance_id ( ) ; type_id = p . inner . type_id ; box_type = Some ( p . box_type . clone ( ) ) ;
invoke = Some ( p . inner . invoke_fn ) ; break ;
}
}
}
} ) ;
}
2025-08-30 22:52:16 +09:00
if invoke . is_none ( ) { events ::emit_runtime ( serde_json ::json! ( { " id " : " plugin_invoke_by_name " , " method " : method , " error " : " no_invoke " } ) , " hostcall " , " <jit> " ) ; return 0 ; }
2025-08-30 08:54:15 +09:00
let box_type = box_type . unwrap_or_default ( ) ;
// Resolve method_id via PluginHost
2025-08-30 22:52:16 +09:00
let mh = if let Ok ( host ) = plugin_loader_unified ::get_global_plugin_host ( ) . read ( ) { host . resolve_method ( & box_type , method ) } else { events ::emit_runtime ( serde_json ::json! ( { " id " : " plugin_invoke_by_name " , " method " : method , " box_type " : box_type , " error " : " host_read_failed " } ) , " hostcall " , " <jit> " ) ; return 0 } ;
let method_id = match mh { Ok ( h ) = > h . method_id , Err ( _ ) = > { events ::emit_runtime ( serde_json ::json! ( { " id " : " plugin_invoke_by_name " , " method " : method , " box_type " : box_type , " error " : " resolve_failed " } ) , " hostcall " , " <jit> " ) ; return 0 } } as u32 ;
// Build TLV args from a1/a2 preferring handles; fallback to legacy (skip receiver=pos0)
let mut buf = crate ::runtime ::plugin_ffi_common ::encode_tlv_header ( argc . saturating_sub ( 1 ) . max ( 0 ) as u16 ) ;
let mut encode_arg = | val : i64 , pos : usize | {
let mut appended = false ;
if val > 0 {
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( val as u64 ) {
if let Some ( p ) = obj . as_any ( ) . downcast_ref ::< PluginBoxV2 > ( ) {
let host = crate ::runtime ::get_global_plugin_host ( ) ;
if let Ok ( hg ) = host . read ( ) {
if p . box_type = = " StringBox " {
if let Ok ( Some ( sb ) ) = hg . invoke_instance_method ( " StringBox " , " toUtf8 " , p . instance_id ( ) , & [ ] ) {
if let Some ( s ) = sb . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) { crate ::runtime ::plugin_ffi_common ::encode ::string ( & mut buf , & s . value ) ; appended = true ; }
}
} else if p . box_type = = " IntegerBox " {
if let Ok ( Some ( ibx ) ) = hg . invoke_instance_method ( " IntegerBox " , " get " , p . instance_id ( ) , & [ ] ) {
if let Some ( i ) = ibx . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { crate ::runtime ::plugin_ffi_common ::encode ::i64 ( & mut buf , i . value ) ; appended = true ; }
}
}
}
if ! appended { crate ::runtime ::plugin_ffi_common ::encode ::plugin_handle ( & mut buf , p . inner . type_id , p . instance_id ( ) ) ; appended = true ; }
2025-09-03 05:04:56 +09:00
} else {
// HostHandle for user/builtin boxes
let h = crate ::runtime ::host_handles ::to_handle_arc ( obj ) ;
crate ::runtime ::plugin_ffi_common ::encode ::host_handle ( & mut buf , h ) ; appended = true ;
2025-08-30 22:52:16 +09:00
}
}
}
if ! appended {
// Fallback: encode from legacy VM args at position
crate ::jit ::rt ::with_legacy_vm_args ( | args | {
if let Some ( v ) = args . get ( pos ) {
use crate ::backend ::vm ::VMValue as V ;
match v {
V ::String ( s ) = > crate ::runtime ::plugin_ffi_common ::encode ::string ( & mut buf , s ) ,
V ::Integer ( i ) = > crate ::runtime ::plugin_ffi_common ::encode ::i64 ( & mut buf , * i ) ,
V ::Float ( f ) = > crate ::runtime ::plugin_ffi_common ::encode ::f64 ( & mut buf , * f ) ,
V ::Bool ( b ) = > crate ::runtime ::plugin_ffi_common ::encode ::bool ( & mut buf , * b ) ,
V ::BoxRef ( b ) = > {
if let Some ( p ) = b . as_any ( ) . downcast_ref ::< PluginBoxV2 > ( ) {
let host = crate ::runtime ::get_global_plugin_host ( ) ;
if let Ok ( hg ) = host . read ( ) {
if p . box_type = = " StringBox " {
if let Ok ( Some ( sb ) ) = hg . invoke_instance_method ( " StringBox " , " toUtf8 " , p . instance_id ( ) , & [ ] ) {
if let Some ( s ) = sb . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) { crate ::runtime ::plugin_ffi_common ::encode ::string ( & mut buf , & s . value ) ; return ; }
}
} else if p . box_type = = " IntegerBox " {
if let Ok ( Some ( ibx ) ) = hg . invoke_instance_method ( " IntegerBox " , " get " , p . instance_id ( ) , & [ ] ) {
if let Some ( i ) = ibx . as_any ( ) . downcast_ref ::< crate ::box_trait ::IntegerBox > ( ) { crate ::runtime ::plugin_ffi_common ::encode ::i64 ( & mut buf , i . value ) ; return ; }
}
2025-08-30 08:54:15 +09:00
}
}
2025-08-30 22:52:16 +09:00
crate ::runtime ::plugin_ffi_common ::encode ::plugin_handle ( & mut buf , p . inner . type_id , p . instance_id ( ) ) ;
} else {
2025-09-03 05:04:56 +09:00
// HostHandle fallback
let h = crate ::runtime ::host_handles ::to_handle_arc ( b . clone ( ) ) ;
crate ::runtime ::plugin_ffi_common ::encode ::host_handle ( & mut buf , h ) ;
2025-08-30 08:54:15 +09:00
}
}
2025-08-30 22:52:16 +09:00
_ = > { }
2025-08-30 08:54:15 +09:00
}
2025-08-30 22:52:16 +09:00
} else {
// No legacy arg: encode raw i64 as last resort
crate ::runtime ::plugin_ffi_common ::encode ::i64 ( & mut buf , val ) ;
2025-08-30 08:54:15 +09:00
}
2025-08-30 22:52:16 +09:00
} ) ;
}
2025-08-30 08:54:15 +09:00
} ;
2025-08-30 22:52:16 +09:00
if argc > = 2 { encode_arg ( a1 , 1 ) ; }
if argc > = 3 { encode_arg ( a2 , 2 ) ; }
2025-08-30 08:54:15 +09:00
let mut out = vec! [ 0 u8 ; 4096 ] ; let mut out_len : usize = out . len ( ) ;
let rc = unsafe { invoke . unwrap ( ) ( type_id as u32 , method_id , instance_id , buf . as_ptr ( ) , buf . len ( ) , out . as_mut_ptr ( ) , & mut out_len ) } ;
2025-08-30 22:52:16 +09:00
if rc ! = 0 { events ::emit_runtime ( serde_json ::json! ( { " id " : " plugin_invoke_by_name " , " method " : method , " box_type " : box_type , " error " : " invoke_failed " } ) , " hostcall " , " <jit> " ) ; return 0 ; }
2025-08-30 08:54:15 +09:00
let out_slice = & out [ .. out_len ] ;
if let Some ( ( tag , _sz , payload ) ) = crate ::runtime ::plugin_ffi_common ::decode ::tlv_first ( out_slice ) {
match tag {
3 = > { if payload . len ( ) = = 8 { let mut b = [ 0 u8 ; 8 ] ; b . copy_from_slice ( payload ) ; return i64 ::from_le_bytes ( b ) ; } }
1 = > { return if crate ::runtime ::plugin_ffi_common ::decode ::bool ( payload ) . unwrap_or ( false ) { 1 } else { 0 } ; }
5 = > { if std ::env ::var ( " NYASH_JIT_NATIVE_F64 " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) { if payload . len ( ) = = 8 { let mut b = [ 0 u8 ; 8 ] ; b . copy_from_slice ( payload ) ; let f = f64 ::from_le_bytes ( b ) ; return f as i64 ; } } }
2025-08-30 22:52:16 +09:00
_ = > { events ::emit_runtime ( serde_json ::json! ( { " id " : " plugin_invoke_by_name " , " method " : method , " box_type " : box_type , " warn " : " first_tlv_not_primitive_or_handle " , " tag " : tag } ) , " hostcall " , " <jit> " ) ; }
2025-08-30 08:54:15 +09:00
}
}
2025-08-30 22:52:16 +09:00
events ::emit_runtime ( serde_json ::json! ( { " id " : " plugin_invoke_by_name " , " method " : method , " box_type " : box_type , " error " : " decode_failed " } ) , " hostcall " , " <jit> " ) ;
2025-08-30 08:54:15 +09:00
0
}
2025-08-29 02:05:39 +09:00
// ---- String ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_string_charcode_at_h ( handle : u64 , idx : i64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_STRING_CHARCODE_AT_H , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " I64 " ] } ) , " hostcall " , " <jit> " ) ;
if idx < 0 { return - 1 ; }
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( sb ) = obj . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) {
let s = & sb . value ;
let i = idx as usize ;
if i < s . len ( ) { return s . as_bytes ( ) [ i ] as i64 ; } else { return - 1 ; }
}
}
- 1
}
2025-09-06 06:46:04 +09:00
// String.len_h(handle) -> i64 with param-index fallback (JIT bridge)
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_string_len_h ( handle : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_STRING_LEN_H , " decision " :" allow " , " argc " :1 , " arg_types " :[ " Handle " ] } ) , " hostcall " , " <jit> " ) ;
2025-09-06 07:45:20 +09:00
if std ::env ::var ( " NYASH_JIT_TRACE_LEN " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) { eprintln! ( " [JIT-LEN_H] handle= {} " , handle ) ; }
2025-09-06 06:46:04 +09:00
if handle > 0 {
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( sb ) = obj . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) { return sb . value . len ( ) as i64 ; }
}
// Fallback to any.length_h for non-string handles
2025-09-06 07:45:20 +09:00
let v = nyash_any_length_h ( handle ) ;
if std ::env ::var ( " NYASH_JIT_TRACE_LEN " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) { eprintln! ( " [JIT-LEN_H] any.length_h(handle= {} ) -> {} " , handle , v ) ; }
return v ;
2025-09-06 06:46:04 +09:00
}
// Legacy param index fallback (0..16): read from VM args
if handle < = 16 {
let idx = handle as usize ;
let val = crate ::jit ::rt ::with_legacy_vm_args ( | args | args . get ( idx ) . cloned ( ) ) ;
if let Some ( v ) = val {
match v {
crate ::backend ::vm ::VMValue ::BoxRef ( b ) = > {
if let Some ( sb ) = b . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) { return sb . value . len ( ) as i64 ; }
}
crate ::backend ::vm ::VMValue ::String ( s ) = > { return s . len ( ) as i64 ; }
_ = > { }
}
}
}
0
}
2025-08-29 08:36:07 +09:00
// ---- Birth (handle) ----
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_string_birth_h ( ) -> i64 {
// Create a new StringBox via unified plugin host (or builtin fallback), store as handle
if let Ok ( host_g ) = crate ::runtime ::get_global_plugin_host ( ) . read ( ) {
if let Ok ( b ) = host_g . create_box ( " StringBox " , & [ ] ) {
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::from ( b ) ;
let h = crate ::jit ::rt ::handles ::to_handle ( arc ) ;
return h as i64 ;
}
}
0
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_integer_birth_h ( ) -> i64 {
if let Ok ( host_g ) = crate ::runtime ::get_global_plugin_host ( ) . read ( ) {
if let Ok ( b ) = host_g . create_box ( " IntegerBox " , & [ ] ) {
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::from ( b ) ;
let h = crate ::jit ::rt ::handles ::to_handle ( arc ) ;
return h as i64 ;
}
}
0
}
2025-08-31 03:03:04 +09:00
// ---- String-like helpers and ops (handle, handle) ----
#[ cfg(feature = " cranelift-jit " ) ]
fn handle_to_string_like ( handle : u64 ) -> Option < String > {
// Prefer runtime handle registry
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( handle ) {
if let Some ( sb ) = obj . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) {
return Some ( sb . value . clone ( ) ) ;
}
if let Some ( pb ) = obj . as_any ( ) . downcast_ref ::< PluginBoxV2 > ( ) {
if pb . box_type = = " StringBox " {
if let Ok ( host ) = crate ::runtime ::get_global_plugin_host ( ) . read ( ) {
if let Ok ( val_opt ) = host . invoke_instance_method ( " StringBox " , " toUtf8 " , pb . instance_id ( ) , & [ ] ) {
if let Some ( vb ) = val_opt { if let Some ( sbb ) = vb . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) { return Some ( sbb . value . clone ( ) ) ; } }
}
}
}
}
// Fallback for any NyashBox
return Some ( obj . to_string_box ( ) . value ) ;
}
// Legacy fallback: treat small values as VM arg index
if handle < = 16 {
let idx = handle as usize ;
let val = crate ::jit ::rt ::with_legacy_vm_args ( | args | args . get ( idx ) . cloned ( ) ) ;
if let Some ( v ) = val {
use crate ::backend ::vm ::VMValue as V ;
return match v {
V ::String ( s ) = > Some ( s ) ,
V ::BoxRef ( b ) = > Some ( b . to_string_box ( ) . value ) ,
V ::Integer ( i ) = > Some ( i . to_string ( ) ) ,
V ::Float ( f ) = > Some ( f . to_string ( ) ) ,
V ::Bool ( b ) = > Some ( b . to_string ( ) ) ,
_ = > None ,
} ;
}
}
None
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_string_concat_hh ( a_h : u64 , b_h : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_STRING_CONCAT_HH , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " Handle " ] } ) , " hostcall " , " <jit> " ) ;
let a = handle_to_string_like ( a_h ) . unwrap_or_default ( ) ;
let b = handle_to_string_like ( b_h ) . unwrap_or_default ( ) ;
let s = format! ( " {} {} " , a , b ) ;
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::new ( crate ::box_trait ::StringBox ::new ( s ) ) ;
let h = crate ::jit ::rt ::handles ::to_handle ( arc ) ;
h as i64
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_string_eq_hh ( a_h : u64 , b_h : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_STRING_EQ_HH , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " Handle " ] } ) , " hostcall " , " <jit> " ) ;
let a = handle_to_string_like ( a_h ) . unwrap_or_default ( ) ;
let b = handle_to_string_like ( b_h ) . unwrap_or_default ( ) ;
if a = = b { 1 } else { 0 }
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_string_lt_hh ( a_h : u64 , b_h : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : c ::SYM_STRING_LT_HH , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " Handle " ] } ) , " hostcall " , " <jit> " ) ;
let a = handle_to_string_like ( a_h ) . unwrap_or_default ( ) ;
let b = handle_to_string_like ( b_h ) . unwrap_or_default ( ) ;
if a < b { 1 } else { 0 }
}
2025-09-01 23:44:34 +09:00
// Unified semantics: addition for dynamic boxes via shared coercions
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_semantics_add_hh ( lhs_h : u64 , rhs_h : u64 ) -> i64 {
events ::emit_runtime ( serde_json ::json! ( { " id " : crate ::jit ::r#extern ::collections ::SYM_SEMANTICS_ADD_HH , " decision " :" allow " , " argc " :2 , " arg_types " :[ " Handle " , " Handle " ] } ) , " hostcall " , " <jit> " ) ;
use crate ::runtime ::semantics ;
use crate ::box_trait ::{ StringBox , IntegerBox } ;
use crate ::jit ::rt ::handles ;
let lhs = if let Some ( o ) = handles ::get ( lhs_h ) { o } else { return 0 } ;
let rhs = if let Some ( o ) = handles ::get ( rhs_h ) { o } else { return 0 } ;
let ls_opt = semantics ::coerce_to_string ( lhs . as_ref ( ) ) ;
let rs_opt = semantics ::coerce_to_string ( rhs . as_ref ( ) ) ;
if ls_opt . is_some ( ) | | rs_opt . is_some ( ) {
let ls = ls_opt . unwrap_or_else ( | | lhs . to_string_box ( ) . value ) ;
let rs = rs_opt . unwrap_or_else ( | | rhs . to_string_box ( ) . value ) ;
let s = format! ( " {} {} " , ls , rs ) ;
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::new ( StringBox ::new ( s ) ) ;
return handles ::to_handle ( arc ) as i64 ;
}
if let ( Some ( li ) , Some ( ri ) ) = ( semantics ::coerce_to_i64 ( lhs . as_ref ( ) ) , semantics ::coerce_to_i64 ( rhs . as_ref ( ) ) ) {
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::new ( IntegerBox ::new ( li + ri ) ) ;
return handles ::to_handle ( arc ) as i64 ;
}
// Fallback stringify concat
let s = format! ( " {} {} " , lhs . to_string_box ( ) . value , rhs . to_string_box ( ) . value ) ;
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::new ( StringBox ::new ( s ) ) ;
handles ::to_handle ( arc ) as i64
}
2025-09-03 09:12:39 +09:00
// ==== Host-bridge (by-slot) external thunks ====
// These thunks adapt JIT runtime handles and primitive args into VMValue vectors
// and call the host-bridge helpers, which TLV-encode and invoke NyRT C-ABI by slot.
#[ cfg(feature = " cranelift-jit " ) ]
fn vmvalue_from_jit_arg_i64 ( v : i64 ) -> crate ::backend ::vm ::VMValue {
use crate ::backend ::vm ::VMValue as V ;
if v < = 0 { return V ::Integer ( v ) ; }
if let Some ( obj ) = crate ::jit ::rt ::handles ::get ( v as u64 ) {
return V ::BoxRef ( obj ) ;
}
// Legacy fallback: allow small indices to refer into legacy VM args for string/name lookups
if ( v as u64 ) < = 16 {
return crate ::jit ::rt ::with_legacy_vm_args ( | args | args . get ( v as usize ) . cloned ( ) ) . unwrap_or ( V ::Integer ( v ) ) ;
}
V ::Integer ( v )
}
#[ cfg(feature = " cranelift-jit " ) ]
fn i64_from_vmvalue ( v : crate ::backend ::vm ::VMValue ) -> i64 {
use crate ::backend ::vm ::VMValue as V ;
match v {
V ::Integer ( i ) = > i ,
V ::Bool ( b ) = > if b { 1 } else { 0 } ,
V ::Float ( f ) = > f as i64 ,
V ::String ( s ) = > {
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::new ( crate ::box_trait ::StringBox ::new ( & s ) ) ;
crate ::jit ::rt ::handles ::to_handle ( arc ) as i64
}
V ::BoxRef ( b ) = > crate ::jit ::rt ::handles ::to_handle ( b ) as i64 ,
V ::Future ( fu ) = > {
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::new ( fu ) ;
crate ::jit ::rt ::handles ::to_handle ( arc ) as i64
}
V ::Void = > 0 ,
}
}
// nyash.host.instance.getField(recv, name)
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_host_instance_getfield ( recv_h : u64 , name_i : i64 ) -> i64 {
use crate ::backend ::vm ::VMValue as V ;
let recv = match crate ::jit ::rt ::handles ::get ( recv_h ) { Some ( a ) = > a , None = > return 0 } ;
let name_v = vmvalue_from_jit_arg_i64 ( name_i ) ;
if std ::env ::var ( " NYASH_JIT_TRACE_BRIDGE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
eprintln! ( " [HB|getField] name_i= {} kind= {} " , name_i , match & name_v { V ::String ( _ ) = > " String " , V ::BoxRef ( b ) = > if b . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) . is_some ( ) { " StringBox " } else { " BoxRef " } , V ::Integer ( _ ) = > " Integer " , V ::Bool ( _ ) = > " Bool " , V ::Float ( _ ) = > " Float " , V ::Void = > " Void " , V ::Future ( _ ) = > " Future " } ) ;
}
let out = hb ::instance_getfield ( & [ V ::BoxRef ( recv ) , name_v ] ) ;
i64_from_vmvalue ( out )
}
// nyash.host.instance.setField(recv, name, value)
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_host_instance_setfield ( recv_h : u64 , name_i : i64 , val_i : i64 ) -> i64 {
use crate ::backend ::vm ::VMValue as V ;
let recv = match crate ::jit ::rt ::handles ::get ( recv_h ) { Some ( a ) = > a , None = > return 0 } ;
let name_v = vmvalue_from_jit_arg_i64 ( name_i ) ;
let val_v = vmvalue_from_jit_arg_i64 ( val_i ) ;
let out = hb ::instance_setfield ( & [ V ::BoxRef ( recv ) , name_v , val_v ] ) ;
i64_from_vmvalue ( out )
}
2025-09-03 09:55:25 +09:00
// Unified instance field op: (recv, name, val_or_sentinel) → getField if val == -1, else setField
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_host_instance_field3 ( recv_h : u64 , name_i : i64 , val_i : i64 ) -> i64 {
use crate ::backend ::vm ::VMValue as V ;
let recv = match crate ::jit ::rt ::handles ::get ( recv_h ) { Some ( a ) = > a , None = > return 0 } ;
let name_v = vmvalue_from_jit_arg_i64 ( name_i ) ;
if val_i = = - 1 { // getField
let out = hb ::instance_getfield ( & [ V ::BoxRef ( recv ) , name_v ] ) ;
return i64_from_vmvalue ( out ) ;
}
// setField
let val_v = vmvalue_from_jit_arg_i64 ( val_i ) ;
let _ = hb ::instance_setfield ( & [ V ::BoxRef ( recv ) , name_v , val_v ] ) ;
0
}
2025-09-03 09:12:39 +09:00
// nyash.host.string.len(recv)
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_host_string_len ( recv_h : u64 ) -> i64 {
use crate ::backend ::vm ::VMValue as V ;
if std ::env ::var ( " NYASH_JIT_TRACE_BRIDGE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) { eprintln! ( " [HB|string.len] recv_h= {} " , recv_h ) ; }
let recv = match crate ::jit ::rt ::handles ::get ( recv_h ) { Some ( a ) = > a , None = > { if std ::env ::var ( " NYASH_JIT_TRACE_BRIDGE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) { eprintln! ( " [HB|string.len] recv handle not found " ) ; } return 0 } } ;
let out = hb ::string_len ( & [ V ::BoxRef ( recv ) ] ) ;
let ret = i64_from_vmvalue ( out ) ;
if std ::env ::var ( " NYASH_JIT_TRACE_BRIDGE " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) { eprintln! ( " [HB|string.len] ret_i64= {} " , ret ) ; }
ret
}
2025-09-06 12:05:35 +09:00
// nyash.host.console.log(value)
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_host_console_log_i64 ( val_i : i64 ) -> i64 {
use crate ::backend ::vm ::VMValue as V ;
let v = vmvalue_from_jit_arg_i64 ( val_i ) ;
let _ = crate ::jit ::r#extern ::host_bridge ::console_log ( & [ v ] ) ;
0
}
// nyash.host.console.warn(value)
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_host_console_warn_i64 ( val_i : i64 ) -> i64 {
use crate ::backend ::vm ::VMValue as V ;
let v = vmvalue_from_jit_arg_i64 ( val_i ) ;
let _ = crate ::jit ::r#extern ::host_bridge ::console_warn ( & [ v ] ) ;
0
}
// nyash.host.console.error(value)
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_host_console_error_i64 ( val_i : i64 ) -> i64 {
use crate ::backend ::vm ::VMValue as V ;
let v = vmvalue_from_jit_arg_i64 ( val_i ) ;
let _ = crate ::jit ::r#extern ::host_bridge ::console_error ( & [ v ] ) ;
0
}
2025-09-03 09:12:39 +09:00
// Build a StringBox handle from raw bytes pointer and length
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_string_from_ptr ( ptr : u64 , len : u64 ) -> i64 {
if ptr = = 0 | | len = = 0 { return 0 ; }
unsafe {
let slice = std ::slice ::from_raw_parts ( ptr as * const u8 , len as usize ) ;
let s = match std ::str ::from_utf8 ( slice ) { Ok ( t ) = > t . to_string ( ) , Err ( _ ) = > String ::from_utf8_lossy ( slice ) . to_string ( ) } ;
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::new ( crate ::box_trait ::StringBox ::new ( s ) ) ;
return crate ::jit ::rt ::handles ::to_handle ( arc ) as i64 ;
}
}
2025-09-04 03:41:02 +09:00
// ===== FunctionBox call shims (by arity, up to 4) =====
#[ cfg(feature = " cranelift-jit " ) ]
fn fn_call_impl ( func_h : u64 , args : & [ i64 ] ) -> i64 {
use crate ::box_trait ::NyashBox ;
let f_arc = match crate ::jit ::rt ::handles ::get ( func_h ) { Some ( a ) = > a , None = > return 0 } ;
if let Some ( fun ) = f_arc . as_any ( ) . downcast_ref ::< crate ::boxes ::function_box ::FunctionBox > ( ) {
let mut ny_args : Vec < Box < dyn NyashBox > > = Vec ::new ( ) ;
for & ai in args {
let v = vmvalue_from_jit_arg_i64 ( ai ) ;
ny_args . push ( v . to_nyash_box ( ) ) ;
}
match crate ::interpreter ::run_function_box ( fun , ny_args ) {
Ok ( out ) = > {
let vmv = crate ::backend ::vm ::VMValue ::from_nyash_box ( out ) ;
i64_from_vmvalue ( vmv )
}
Err ( _ ) = > 0 ,
}
} else { 0 }
}
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_fn_call0 ( func_h : u64 ) -> i64 { fn_call_impl ( func_h , & [ ] ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_fn_call1 ( func_h : u64 , a0 : i64 ) -> i64 { fn_call_impl ( func_h , & [ a0 ] ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_fn_call2 ( func_h : u64 , a0 : i64 , a1 : i64 ) -> i64 { fn_call_impl ( func_h , & [ a0 , a1 ] ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_fn_call3 ( func_h : u64 , a0 : i64 , a1 : i64 , a2 : i64 ) -> i64 { fn_call_impl ( func_h , & [ a0 , a1 , a2 ] ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_fn_call4 ( func_h : u64 , a0 : i64 , a1 : i64 , a2 : i64 , a3 : i64 ) -> i64 { fn_call_impl ( func_h , & [ a0 , a1 , a2 , a3 ] ) }
// extended arities (5..8)
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_fn_call5 ( func_h : u64 , a0 : i64 , a1 : i64 , a2 : i64 , a3 : i64 , a4 : i64 ) -> i64 { fn_call_impl ( func_h , & [ a0 , a1 , a2 , a3 , a4 ] ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_fn_call6 ( func_h : u64 , a0 : i64 , a1 : i64 , a2 : i64 , a3 : i64 , a4 : i64 , a5 : i64 ) -> i64 { fn_call_impl ( func_h , & [ a0 , a1 , a2 , a3 , a4 , a5 ] ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_fn_call7 ( func_h : u64 , a0 : i64 , a1 : i64 , a2 : i64 , a3 : i64 , a4 : i64 , a5 : i64 , a6 : i64 ) -> i64 { fn_call_impl ( func_h , & [ a0 , a1 , a2 , a3 , a4 , a5 , a6 ] ) }
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_fn_call8 ( func_h : u64 , a0 : i64 , a1 : i64 , a2 : i64 , a3 : i64 , a4 : i64 , a5 : i64 , a6 : i64 , a7 : i64 ) -> i64 { fn_call_impl ( func_h , & [ a0 , a1 , a2 , a3 , a4 , a5 , a6 , a7 ] ) }
2025-09-03 09:12:39 +09:00
// Build a StringBox handle from two u64 chunks (little-endian) and length (<=16)
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_string_from_u64x2 ( lo : u64 , hi : u64 , len : i64 ) -> i64 {
let n = if len < = 0 { 0 usize } else { core ::cmp ::min ( len as usize , 16 usize ) } ;
let mut buf = [ 0 u8 ; 16 ] ;
for i in 0 .. core ::cmp ::min ( 8 , n ) { buf [ i ] = ( ( lo > > ( 8 * i ) ) & 0xFF ) as u8 ; }
if n > 8 { for i in 0 .. ( n - 8 ) { buf [ 8 + i ] = ( ( hi > > ( 8 * i ) ) & 0xFF ) as u8 ; } }
let s = match std ::str ::from_utf8 ( & buf [ .. n ] ) { Ok ( t ) = > t . to_string ( ) , Err ( _ ) = > String ::from_utf8_lossy ( & buf [ .. n ] ) . to_string ( ) } ;
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::new ( crate ::box_trait ::StringBox ::new ( s ) ) ;
2025-09-06 10:59:33 +09:00
let h = crate ::jit ::rt ::handles ::to_handle ( arc . clone ( ) ) as i64 ;
if std ::env ::var ( " NYASH_JIT_TRACE_LEN " ) . ok ( ) . as_deref ( ) = = Some ( " 1 " ) {
if let Some ( sb ) = arc . as_any ( ) . downcast_ref ::< crate ::box_trait ::StringBox > ( ) { eprintln! ( " [JIT-STR_H] new handle= {} val=' {} ' len= {} " , h , sb . value , sb . value . len ( ) ) ; }
else { eprintln! ( " [JIT-STR_H] new handle= {} (non-StringBox) " , h ) ; }
}
h
2025-09-03 09:12:39 +09:00
}
2025-09-03 09:55:25 +09:00
// Create an instance by type name via global unified registry: birth(name) -> handle
#[ cfg(feature = " cranelift-jit " ) ]
pub ( super ) extern " C " fn nyash_instance_birth_name_u64x2 ( lo : u64 , hi : u64 , len : i64 ) -> i64 {
let n = if len < = 0 { 0 usize } else { core ::cmp ::min ( len as usize , 32 usize ) } ;
let mut buf = [ 0 u8 ; 32 ] ;
for i in 0 .. core ::cmp ::min ( 8 , n ) { buf [ i ] = ( ( lo > > ( 8 * i ) ) & 0xFF ) as u8 ; }
if n > 8 { for i in 0 .. core ::cmp ::min ( 8 , n - 8 ) { buf [ 8 + i ] = ( ( hi > > ( 8 * i ) ) & 0xFF ) as u8 ; } }
let name = match std ::str ::from_utf8 ( & buf [ .. n ] ) { Ok ( t ) = > t . to_string ( ) , Err ( _ ) = > String ::from_utf8_lossy ( & buf [ .. n ] ) . to_string ( ) } ;
let registry = crate ::runtime ::get_global_unified_registry ( ) ;
if let Ok ( reg ) = registry . lock ( ) {
match reg . create_box ( & name , & [ ] ) {
Ok ( b ) = > {
let arc : std ::sync ::Arc < dyn crate ::box_trait ::NyashBox > = std ::sync ::Arc ::from ( b ) ;
return crate ::jit ::rt ::handles ::to_handle ( arc ) as i64 ;
}
Err ( _ ) = > return 0 ,
}
}
0
}