@@ -78,6 +78,106 @@ fn type_tag_to_cranelift_type(tag: &crate::zrtl::TypeTag) -> types::Type {
7878 }
7979}
8080
81+ /// Deterministically derive a non-zero opaque sub-id from a type name.
82+ ///
83+ /// We reserve `0` for unknown/legacy opaque values and keep `0xFFFF` for
84+ /// DynamicBox signature markers, so generated IDs stay in a safe range.
85+ fn stable_opaque_type_sub_id ( type_name : & str ) -> u16 {
86+ let clean_name = type_name. trim_start_matches ( '$' ) ;
87+ if clean_name. is_empty ( ) {
88+ return 1 ;
89+ }
90+
91+ // FNV-1a (32-bit), deterministic across processes/platforms.
92+ let mut hash: u32 = 0x811C_9DC5 ;
93+ for byte in clean_name. as_bytes ( ) {
94+ hash ^= * byte as u32 ;
95+ hash = hash. wrapping_mul ( 0x0100_0193 ) ;
96+ }
97+
98+ let mut id = ( hash as u16 ) & 0x7FFF ;
99+ if id == 0 {
100+ id = 1 ;
101+ }
102+ id
103+ }
104+
105+ fn dynamic_box_opaque_tag ( opaque_name : & str ) -> u32 {
106+ crate :: zrtl:: TypeTag :: new (
107+ crate :: zrtl:: TypeCategory :: Opaque ,
108+ stable_opaque_type_sub_id ( opaque_name) ,
109+ crate :: zrtl:: TypeFlags :: NONE ,
110+ )
111+ . 0
112+ }
113+
114+ fn dynamic_box_tag_and_size_for_hir_type ( ty : & HirType ) -> ( u32 , u32 ) {
115+ match ty {
116+ HirType :: I8 => ( crate :: zrtl:: TypeTag :: I8 . 0 , 1 ) ,
117+ HirType :: I16 => ( crate :: zrtl:: TypeTag :: I16 . 0 , 2 ) ,
118+ HirType :: I32 => ( crate :: zrtl:: TypeTag :: I32 . 0 , 4 ) ,
119+ HirType :: I64 => ( crate :: zrtl:: TypeTag :: I64 . 0 , 8 ) ,
120+ HirType :: U8 => ( crate :: zrtl:: TypeTag :: U8 . 0 , 1 ) ,
121+ HirType :: U16 => ( crate :: zrtl:: TypeTag :: U16 . 0 , 2 ) ,
122+ HirType :: U32 => ( crate :: zrtl:: TypeTag :: U32 . 0 , 4 ) ,
123+ HirType :: U64 => ( crate :: zrtl:: TypeTag :: U64 . 0 , 8 ) ,
124+ HirType :: F32 => ( crate :: zrtl:: TypeTag :: F32 . 0 , 4 ) ,
125+ HirType :: F64 => ( crate :: zrtl:: TypeTag :: F64 . 0 , 8 ) ,
126+ HirType :: Bool => ( crate :: zrtl:: TypeTag :: BOOL . 0 , 1 ) ,
127+ HirType :: Ptr ( inner) if matches ! ( inner. as_ref( ) , HirType :: I8 ) => {
128+ ( crate :: zrtl:: TypeTag :: STRING . 0 , 8 )
129+ }
130+ HirType :: Opaque ( type_name) => {
131+ let type_name_str = type_name. resolve_global ( ) . unwrap_or_default ( ) ;
132+ ( dynamic_box_opaque_tag ( & type_name_str) , 8 )
133+ }
134+ HirType :: Ptr ( inner) if matches ! ( inner. as_ref( ) , HirType :: Opaque ( _) ) => {
135+ if let HirType :: Opaque ( type_name) = inner. as_ref ( ) {
136+ let type_name_str = type_name. resolve_global ( ) . unwrap_or_default ( ) ;
137+ ( dynamic_box_opaque_tag ( & type_name_str) , 8 )
138+ } else {
139+ unreachable ! ( "checked by match guard" ) ;
140+ }
141+ }
142+ HirType :: Ptr ( _) => (
143+ crate :: zrtl:: TypeTag :: new (
144+ crate :: zrtl:: TypeCategory :: Pointer ,
145+ crate :: zrtl:: PrimitiveSize :: Pointer as u16 ,
146+ crate :: zrtl:: TypeFlags :: NONE ,
147+ )
148+ . 0 ,
149+ 8 ,
150+ ) ,
151+ other => {
152+ log:: warn!(
153+ "[Boxing] Unhandled type: {:?}, defaulting to opaque tag" ,
154+ other
155+ ) ;
156+ default_dynamic_box_opaque_tag_and_size ( )
157+ }
158+ }
159+ }
160+
161+ fn default_dynamic_box_opaque_tag_and_size ( ) -> ( u32 , u32 ) {
162+ (
163+ crate :: zrtl:: TypeTag :: new (
164+ crate :: zrtl:: TypeCategory :: Opaque ,
165+ 1 ,
166+ crate :: zrtl:: TypeFlags :: NONE ,
167+ )
168+ . 0 ,
169+ 8 ,
170+ )
171+ }
172+
173+ fn dynamic_box_uses_direct_pointer ( ty : & HirType ) -> bool {
174+ match ty {
175+ HirType :: Opaque ( _) => true ,
176+ HirType :: Ptr ( inner) => matches ! ( inner. as_ref( ) , HirType :: Opaque ( _) | HirType :: I8 ) ,
177+ _ => false ,
178+ }
179+ }
180+
81181/// Cranelift backend for JIT compilation
82182pub struct CraneliftBackend {
83183 /// JIT module for code generation
@@ -1402,65 +1502,27 @@ impl CraneliftBackend {
14021502 if needs_boxing {
14031503 // Apply DynamicBox wrapping - same logic as HirCallable::Symbol
14041504 let arg_hir_id = args[ param_index] ;
1405- // Check if this is a pointer type (opaque or string) - pass value directly
1406- let is_pointer_type = if let Some ( hir_value) =
1407- function. values . get ( & arg_hir_id)
1408- {
1409- match & hir_value. ty {
1410- HirType :: Opaque ( _) => true ,
1411- HirType :: Ptr ( inner) => matches ! (
1412- inner. as_ref( ) ,
1413- HirType :: Opaque ( _) | HirType :: I8
1414- ) ,
1415- _ => false ,
1416- }
1417- } else {
1418- false
1419- } ;
1420-
1421- let ( tag_value, size_value) =
1422- if let Some ( hir_value) =
1423- function. values . get ( & arg_hir_id)
1424- {
1425- // TypeTag format: (type_id << 8) | category
1426- // PrimitiveSize: Bits8=1, Bits16=2, Bits32=3, Bits64=4
1427- match & hir_value. ty {
1428- HirType :: I8 => ( 0x0102u32 , 1u32 ) , // Int(Bits8)
1429- HirType :: I16 => ( 0x0202u32 , 2u32 ) , // Int(Bits16)
1430- HirType :: I32 => ( 0x0302u32 , 4u32 ) , // Int(Bits32)
1431- HirType :: I64 => ( 0x0402u32 , 8u32 ) , // Int(Bits64)
1432- HirType :: U8 => ( 0x0103u32 , 1u32 ) , // UInt(Bits8)
1433- HirType :: U16 => ( 0x0203u32 , 2u32 ) , // UInt(Bits16)
1434- HirType :: U32 => ( 0x0303u32 , 4u32 ) , // UInt(Bits32)
1435- HirType :: U64 => ( 0x0403u32 , 8u32 ) , // UInt(Bits64)
1436- HirType :: F32 => ( 0x0304u32 , 4u32 ) , // Float(Bits32)
1437- HirType :: F64 => ( 0x0404u32 , 8u32 ) , // Float(Bits64)
1438- HirType :: Bool => ( 0x0001u32 , 1u32 ) , // Bool
1439- HirType :: Ptr ( inner)
1440- if matches ! (
1441- inner. as_ref( ) ,
1442- HirType :: I8
1443- ) =>
1444- {
1445- ( 0x0005u32 , 8u32 )
1446- } // String
1447- HirType :: Opaque ( _) => ( 0x0012u32 , 8u32 ) , // Opaque
1448- HirType :: Ptr ( inner)
1449- if matches ! (
1450- inner. as_ref( ) ,
1451- HirType :: Opaque ( _)
1452- ) =>
1453- {
1454- ( 0x0012u32 , 8u32 )
1455- }
1456- other => {
1457- ( 0x0012u32 , 8u32 )
1458- // Opaque
1459- }
1460- }
1461- } else {
1462- ( 0x0012u32 , 8u32 ) // Opaque
1463- } ;
1505+ let is_pointer_type = function
1506+ . values
1507+ . get ( & arg_hir_id)
1508+ . map ( |hir_value| {
1509+ dynamic_box_uses_direct_pointer (
1510+ & hir_value. ty ,
1511+ )
1512+ } )
1513+ . unwrap_or ( false ) ;
1514+
1515+ let ( tag_value, size_value) = function
1516+ . values
1517+ . get ( & arg_hir_id)
1518+ . map ( |hir_value| {
1519+ dynamic_box_tag_and_size_for_hir_type (
1520+ & hir_value. ty ,
1521+ )
1522+ } )
1523+ . unwrap_or_else (
1524+ default_dynamic_box_opaque_tag_and_size,
1525+ ) ;
14641526
14651527 let data_ptr_value = if is_pointer_type {
14661528 // Pointer types (opaque, string): value IS the pointer
@@ -1776,65 +1838,30 @@ impl CraneliftBackend {
17761838 // Allocate stack space for DynamicBox (32 bytes on 64-bit)
17771839 // Determine TypeTag and size based on HIR type
17781840 let arg_hir_id = args[ param_index] ;
1779- let ( tag_value, size_value) = if let Some ( hir_value) =
1780- function. values . get ( & arg_hir_id)
1781- {
1782- // TypeTag format: (type_id << 8) | category
1783- // PrimitiveSize: Bits8=1, Bits16=2, Bits32=3, Bits64=4
1784- match & hir_value. ty {
1785- HirType :: I8 => ( 0x0102u32 , 1u32 ) , // Int(Bits8)
1786- HirType :: I16 => ( 0x0202u32 , 2u32 ) , // Int(Bits16)
1787- HirType :: I32 => ( 0x0302u32 , 4u32 ) , // Int(Bits32)
1788- HirType :: I64 => ( 0x0402u32 , 8u32 ) , // Int(Bits64)
1789- HirType :: U8 => ( 0x0103u32 , 1u32 ) , // UInt(Bits8)
1790- HirType :: U16 => ( 0x0203u32 , 2u32 ) , // UInt(Bits16)
1791- HirType :: U32 => ( 0x0303u32 , 4u32 ) , // UInt(Bits32)
1792- HirType :: U64 => ( 0x0403u32 , 8u32 ) , // UInt(Bits64)
1793- HirType :: F32 => ( 0x0304u32 , 4u32 ) , // Float(Bits32)
1794- HirType :: F64 => ( 0x0404u32 , 8u32 ) , // Float(Bits64)
1795- HirType :: Bool => ( 0x0001u32 , 1u32 ) , // Bool
1796- HirType :: Ptr ( inner)
1797- if matches ! (
1798- inner. as_ref( ) ,
1799- HirType :: I8
1800- ) =>
1801- {
1802- ( 0x0005u32 , 8u32 ) // String
1803- }
1804- HirType :: Opaque ( _) => ( 0x0012u32 , 8u32 ) , // Opaque
1805- HirType :: Ptr ( inner)
1806- if matches ! (
1807- inner. as_ref( ) ,
1808- HirType :: Opaque ( _)
1809- ) =>
1810- {
1811- ( 0x0012u32 , 8u32 ) // Ptr to Opaque
1812- }
1813- other => {
1814- log:: warn!( "[Boxing] Unhandled type: {:?}, defaulting to Opaque" , other) ;
1815- ( 0x0012u32 , 8u32 ) // Opaque
1816- }
1817- }
1818- } else {
1819- log:: warn!( "[Boxing] No HirValue found for arg_hir_id {:?}" , arg_hir_id) ;
1820- ( 0x0012u32 , 8u32 ) // Opaque
1821- } ;
1841+ let ( tag_value, size_value) = function
1842+ . values
1843+ . get ( & arg_hir_id)
1844+ . map ( |hir_value| {
1845+ dynamic_box_tag_and_size_for_hir_type (
1846+ & hir_value. ty ,
1847+ )
1848+ } )
1849+ . unwrap_or_else ( || {
1850+ log:: warn!(
1851+ "[Boxing] No HirValue found for arg_hir_id {:?}" ,
1852+ arg_hir_id
1853+ ) ;
1854+ default_dynamic_box_opaque_tag_and_size ( )
1855+ } ) ;
18221856
18231857 // Check if this is a pointer type (opaque types or strings that should be passed directly)
1824- let is_pointer_type = if let Some ( hir_value) =
1825- function. values . get ( & args[ param_index] )
1826- {
1827- match & hir_value. ty {
1828- HirType :: Opaque ( _) => true ,
1829- HirType :: Ptr ( inner) => matches ! (
1830- inner. as_ref( ) ,
1831- HirType :: Opaque ( _) | HirType :: I8
1832- ) ,
1833- _ => false ,
1834- }
1835- } else {
1836- false
1837- } ;
1858+ let is_pointer_type = function
1859+ . values
1860+ . get ( & args[ param_index] )
1861+ . map ( |hir_value| {
1862+ dynamic_box_uses_direct_pointer ( & hir_value. ty )
1863+ } )
1864+ . unwrap_or ( false ) ;
18381865
18391866 // For pointer types, the value IS already a pointer - store directly
18401867 // For primitives, allocate stack space and store a pointer to the value
0 commit comments