@@ -2699,8 +2699,6 @@ impl<'a, 'b> Compiler<'a, 'b> {
26992699 dst_ty : & InterfaceType ,
27002700 dst : & Destination ,
27012701 ) {
2702- // Extract memory configuration for source and destination
2703- // Get linear memory options (32-bit vs 64-bit pointers, which memory, etc.)
27042702 let src_mem_opts = match & src. opts ( ) . data_model {
27052703 DataModel :: Gc { } => todo ! ( "CM+GC" ) ,
27062704 DataModel :: LinearMemory ( opts) => opts,
@@ -2710,84 +2708,66 @@ impl<'a, 'b> Compiler<'a, 'b> {
27102708 DataModel :: LinearMemory ( opts) => opts,
27112709 } ;
27122710
2713- // Get type information for source and destination maps
2714- // Look up the TypeMap structs which contain the key and value InterfaceTypes
27152711 let src_map_ty = & self . types [ src_ty] ;
27162712 let dst_map_ty = match dst_ty {
27172713 InterfaceType :: Map ( r) => & self . types [ * r] ,
27182714 _ => panic ! ( "expected a map" ) ,
27192715 } ;
27202716
2721- // Load the map's pointer and length into temporary locals
2722- // A map is represented as (ptr, len) - we need both values in locals
2723- // for later use in the translation loop.
27242717 match src {
27252718 Source :: Stack ( s) => {
2726- // If map descriptor is passed on the stack (as 2 locals: ptr, len)
27272719 assert_eq ! ( s. locals. len( ) , 2 ) ;
2728- self . stack_get ( & s. slice ( 0 ..1 ) , src_mem_opts. ptr ( ) ) ; // Push ptr to wasm stack
2729- self . stack_get ( & s. slice ( 1 ..2 ) , src_mem_opts. ptr ( ) ) ; // Push len to wasm stack
2720+ self . stack_get ( & s. slice ( 0 ..1 ) , src_mem_opts. ptr ( ) ) ;
2721+ self . stack_get ( & s. slice ( 1 ..2 ) , src_mem_opts. ptr ( ) ) ;
27302722 }
27312723 Source :: Memory ( mem) => {
2732- // If map descriptor is stored in memory, load ptr and len from there
2733- self . ptr_load ( mem) ; // Load ptr
2734- self . ptr_load ( & mem. bump ( src_mem_opts. ptr_size ( ) . into ( ) ) ) ; // Load len (next field)
2724+ self . ptr_load ( mem) ;
2725+ self . ptr_load ( & mem. bump ( src_mem_opts. ptr_size ( ) . into ( ) ) ) ;
27352726 }
27362727 Source :: Struct ( _) | Source :: Array ( _) => todo ! ( "CM+GC" ) ,
27372728 }
2738- // Pop values from wasm stack into named locals (note: len is on top, then ptr)
27392729 let src_len = self . local_set_new_tmp ( src_mem_opts. ptr ( ) ) ;
27402730 let src_ptr = self . local_set_new_tmp ( src_mem_opts. ptr ( ) ) ;
27412731
2742- // Calculate tuple sizes with proper alignment
2743- // Each map entry is a (key, value) tuple. We need to know:
2744- // - Size of key and value in bytes
2745- // - Alignment requirements
2746- // - Total tuple size including any padding
27472732 let src_opts = src. opts ( ) ;
27482733 let dst_opts = dst. opts ( ) ;
27492734
2750- // Source tuple layout
2735+ // Each map entry is a tuple<K, V> following record layout rules:
2736+ // key at offset 0, padding to value_align, value, trailing padding
2737+ // to entry_align.
27512738 let ( src_key_size, src_key_align) = self . types . size_align ( src_mem_opts, & src_map_ty. key ) ;
2752- let ( src_value_size, _) = self . types . size_align ( src_mem_opts, & src_map_ty. value ) ;
2753- // Total tuple size = key + value + padding to alignment
2754- // e.g., if key is 4 bytes, value is 8 bytes, align is 4:
2755- // tuple_size = (4 + 8 + 3) & ~3 = 12 bytes
2739+ let ( src_value_size, src_value_align) =
2740+ self . types . size_align ( src_mem_opts, & src_map_ty. value ) ;
2741+ let src_entry_align = src_key_align. max ( src_value_align) ;
2742+ let src_value_offset =
2743+ ( src_key_size + src_value_align - 1 ) & !( src_value_align - 1 ) ;
27562744 let src_tuple_size =
2757- ( src_key_size + src_value_size + src_key_align - 1 ) & !( src_key_align - 1 ) ;
2745+ ( src_value_offset + src_value_size + src_entry_align - 1 ) & !( src_entry_align - 1 ) ;
27582746
2759- // Destination tuple layout (may differ if types are converted)
27602747 let ( dst_key_size, dst_key_align) = self . types . size_align ( dst_mem_opts, & dst_map_ty. key ) ;
2761- let ( dst_value_size, _) = self . types . size_align ( dst_mem_opts, & dst_map_ty. value ) ;
2748+ let ( dst_value_size, dst_value_align) =
2749+ self . types . size_align ( dst_mem_opts, & dst_map_ty. value ) ;
2750+ let dst_entry_align = dst_key_align. max ( dst_value_align) ;
2751+ let dst_value_offset =
2752+ ( dst_key_size + dst_value_align - 1 ) & !( dst_value_align - 1 ) ;
27622753 let dst_tuple_size =
2763- ( dst_key_size + dst_value_size + dst_key_align - 1 ) & !( dst_key_align - 1 ) ;
2754+ ( dst_value_offset + dst_value_size + dst_entry_align - 1 ) & !( dst_entry_align - 1 ) ;
27642755
2765- // Create source memory operand and verify alignment
2766- // This creates a Memory operand and verifies the source pointer is properly aligned
2767- let src_mem = self . memory_operand ( src_opts, src_ptr, src_key_align) ;
2756+ let src_mem = self . memory_operand ( src_opts, src_ptr, src_entry_align) ;
27682757
2769- // Calculate total byte lengths for source and destination
2770- // total_bytes = count * tuple_size
2758+ // Calculate source/destination byte lengths and allocate destination.
2759+ self . instruction ( LocalGet ( src_len. idx ) ) ;
2760+ self . ptr_uconst ( src_mem_opts, src_tuple_size) ;
2761+ self . ptr_mul ( src_mem_opts) ;
27712762 let src_byte_len = self . local_set_new_tmp ( src_mem_opts. ptr ( ) ) ;
2772- self . instruction ( LocalGet ( src_len. idx ) ) ; // Push len
2773- self . ptr_uconst ( src_mem_opts, src_tuple_size) ; // Push tuple_size
2774- self . ptr_mul ( src_mem_opts) ; // len * tuple_size
2775- self . instruction ( LocalSet ( src_byte_len. idx ) ) ; // Save to local
27762763
2764+ self . instruction ( LocalGet ( src_len. idx ) ) ;
2765+ self . ptr_uconst ( dst_mem_opts, dst_tuple_size) ;
2766+ self . ptr_mul ( dst_mem_opts) ;
27772767 let dst_byte_len = self . local_set_new_tmp ( dst_mem_opts. ptr ( ) ) ;
2778- self . instruction ( LocalGet ( src_len. idx ) ) ; // Push len (same count)
2779- self . ptr_uconst ( dst_mem_opts, dst_tuple_size) ; // Push dst tuple_size
2780- self . ptr_mul ( dst_mem_opts) ; // len * tuple_size
2781- self . instruction ( LocalTee ( dst_byte_len. idx ) ) ; // Save AND keep on stack for malloc
2782-
2783- // Allocate destination buffer
2784- // Call realloc in the destination component to allocate space.
2785- // dst_byte_len is still on the stack from LocalTee above.
2786- let dst_mem = self . malloc ( dst_opts, MallocSize :: Local ( dst_byte_len. idx ) , dst_key_align) ;
2787-
2788- // Validate memory bounds
2789- // Verify that ptr + byte_len doesn't overflow or exceed memory bounds.
2790- // Trap if invalid.
2768+
2769+ let dst_mem = self . malloc ( dst_opts, MallocSize :: Local ( dst_byte_len. idx ) , dst_entry_align) ;
2770+
27912771 self . validate_memory_inbounds (
27922772 src_mem_opts,
27932773 src_mem. addr . idx ,
@@ -2801,37 +2781,25 @@ impl<'a, 'b> Compiler<'a, 'b> {
28012781 Trap :: ListOutOfBounds ,
28022782 ) ;
28032783
2804- // Done with byte length locals
28052784 self . free_temp_local ( src_byte_len) ;
28062785 self . free_temp_local ( dst_byte_len) ;
28072786
2808- // Main translation loop - copy each (key, value) tuple
2809- // Skip loop entirely if tuples are zero-sized (nothing to copy)
28102787 if src_tuple_size > 0 || dst_tuple_size > 0 {
2811- // Loop setup
2812- // Create counter for remaining elements
2813- let remaining = self . local_set_new_tmp ( src_mem_opts. ptr ( ) ) ;
2788+ self . instruction ( Block ( BlockType :: Empty ) ) ;
2789+
28142790 self . instruction ( LocalGet ( src_len. idx ) ) ;
2815- self . instruction ( LocalSet ( remaining. idx ) ) ;
2791+ let remaining = self . local_tee_new_tmp ( src_mem_opts. ptr ( ) ) ;
2792+ self . ptr_eqz ( src_mem_opts) ;
2793+ self . instruction ( BrIf ( 0 ) ) ;
28162794
2817- // Create pointer to current position in source
2818- let cur_src_ptr = self . local_set_new_tmp ( src_mem_opts. ptr ( ) ) ;
28192795 self . instruction ( LocalGet ( src_mem. addr . idx ) ) ;
2820- self . instruction ( LocalSet ( cur_src_ptr . idx ) ) ;
2796+ let cur_src_ptr = self . local_set_new_tmp ( src_mem_opts . ptr ( ) ) ;
28212797
2822- // Create pointer to current position in destination
2823- let cur_dst_ptr = self . local_set_new_tmp ( dst_mem_opts. ptr ( ) ) ;
28242798 self . instruction ( LocalGet ( dst_mem. addr . idx ) ) ;
2825- self . instruction ( LocalSet ( cur_dst_ptr . idx ) ) ;
2799+ let cur_dst_ptr = self . local_set_new_tmp ( dst_mem_opts . ptr ( ) ) ;
28262800
2827- // WebAssembly loop structure
2828- // Block is the outer container (to break out of loop)
2829- // Loop is what we branch back to for iteration
2830- self . instruction ( Block ( BlockType :: Empty ) ) ;
28312801 self . instruction ( Loop ( BlockType :: Empty ) ) ;
28322802
2833- // Translate the key
2834- // Create Source pointing to current key location
28352803 let key_src = Source :: Memory ( self . memory_operand (
28362804 src_opts,
28372805 TempLocal {
@@ -2841,7 +2809,6 @@ impl<'a, 'b> Compiler<'a, 'b> {
28412809 } ,
28422810 src_key_align,
28432811 ) ) ;
2844- // Create Destination pointing to where key should go
28452812 let key_dst = Destination :: Memory ( self . memory_operand (
28462813 dst_opts,
28472814 TempLocal {
@@ -2851,32 +2818,30 @@ impl<'a, 'b> Compiler<'a, 'b> {
28512818 } ,
28522819 dst_key_align,
28532820 ) ) ;
2854- // Recursively translate the key (handles any type: primitives, strings, etc.)
28552821 self . translate ( & src_map_ty. key , & key_src, & dst_map_ty. key , & key_dst) ;
28562822
2857- // Advance pointers past the key to point at value
2858- if src_key_size > 0 {
2823+ // Advance pointers from key start to value start
2824+ if src_value_offset > 0 {
28592825 self . instruction ( LocalGet ( cur_src_ptr. idx ) ) ;
2860- self . ptr_uconst ( src_mem_opts, src_key_size ) ;
2826+ self . ptr_uconst ( src_mem_opts, src_value_offset ) ;
28612827 self . ptr_add ( src_mem_opts) ;
28622828 self . instruction ( LocalSet ( cur_src_ptr. idx ) ) ;
28632829 }
2864- if dst_key_size > 0 {
2830+ if dst_value_offset > 0 {
28652831 self . instruction ( LocalGet ( cur_dst_ptr. idx ) ) ;
2866- self . ptr_uconst ( dst_mem_opts, dst_key_size ) ;
2832+ self . ptr_uconst ( dst_mem_opts, dst_value_offset ) ;
28672833 self . ptr_add ( dst_mem_opts) ;
28682834 self . instruction ( LocalSet ( cur_dst_ptr. idx ) ) ;
28692835 }
28702836
2871- // Translate the value
28722837 let value_src = Source :: Memory ( self . memory_operand (
28732838 src_opts,
28742839 TempLocal {
28752840 idx : cur_src_ptr. idx ,
28762841 ty : src_mem_opts. ptr ( ) ,
28772842 needs_free : false ,
28782843 } ,
2879- src_key_align ,
2844+ src_value_align ,
28802845 ) ) ;
28812846 let value_dst = Destination :: Memory ( self . memory_operand (
28822847 dst_opts,
@@ -2885,52 +2850,49 @@ impl<'a, 'b> Compiler<'a, 'b> {
28852850 ty : dst_mem_opts. ptr ( ) ,
28862851 needs_free : false ,
28872852 } ,
2888- dst_key_align ,
2853+ dst_value_align ,
28892854 ) ) ;
2890- // Recursively translate the value
28912855 self . translate ( & src_map_ty. value , & value_src, & dst_map_ty. value , & value_dst) ;
28922856
2893- // Advance pointers past the value (including any alignment padding)
2894- // If tuple_size > key_size + value_size, there's padding we need to skip
2895- if src_tuple_size > src_key_size + src_value_size {
2857+ // Advance pointers past the value and any trailing padding to
2858+ // reach the next entry. After value translation, cur_ptr still
2859+ // points at the value start, so advance by value_size + trailing
2860+ // padding (i.e. tuple_size - value_offset).
2861+ let src_advance_to_next = src_tuple_size - src_value_offset;
2862+ if src_advance_to_next > 0 {
28962863 self . instruction ( LocalGet ( cur_src_ptr. idx ) ) ;
2897- self . ptr_uconst ( src_mem_opts, src_tuple_size - src_key_size - src_value_size ) ;
2864+ self . ptr_uconst ( src_mem_opts, src_advance_to_next ) ;
28982865 self . ptr_add ( src_mem_opts) ;
28992866 self . instruction ( LocalSet ( cur_src_ptr. idx ) ) ;
29002867 }
2901- if dst_tuple_size > dst_key_size + dst_value_size {
2868+ let dst_advance_to_next = dst_tuple_size - dst_value_offset;
2869+ if dst_advance_to_next > 0 {
29022870 self . instruction ( LocalGet ( cur_dst_ptr. idx ) ) ;
2903- self . ptr_uconst ( dst_mem_opts, dst_tuple_size - dst_key_size - dst_value_size ) ;
2871+ self . ptr_uconst ( dst_mem_opts, dst_advance_to_next ) ;
29042872 self . ptr_add ( dst_mem_opts) ;
29052873 self . instruction ( LocalSet ( cur_dst_ptr. idx ) ) ;
29062874 }
29072875
2908- // Loop continuation: decrement counter and branch if not done
29092876 self . instruction ( LocalGet ( remaining. idx ) ) ;
2910- self . ptr_iconst ( src_mem_opts, -1 ) ; // Push -1
2911- self . ptr_add ( src_mem_opts) ; // remaining - 1
2912- self . instruction ( LocalTee ( remaining. idx ) ) ; // Save back AND keep on stack
2913- self . ptr_br_if ( src_mem_opts, 0 ) ; // If remaining != 0, branch back to Loop
2914- self . instruction ( End ) ; // End Loop
2915- self . instruction ( End ) ; // End Block
2916-
2917- // Release loop locals
2877+ self . ptr_iconst ( src_mem_opts, -1 ) ;
2878+ self . ptr_add ( src_mem_opts) ;
2879+ self . instruction ( LocalTee ( remaining. idx ) ) ;
2880+ self . ptr_br_if ( src_mem_opts, 0 ) ;
2881+ self . instruction ( End ) ; // end of loop
2882+ self . instruction ( End ) ; // end of block
29182883 self . free_temp_local ( cur_dst_ptr) ;
29192884 self . free_temp_local ( cur_src_ptr) ;
29202885 self . free_temp_local ( remaining) ;
29212886 }
29222887
2923- // Store the result (ptr, len) to the destination
29242888 match dst {
29252889 Destination :: Stack ( s, _) => {
2926- // Put ptr and len on the wasm stack for return
29272890 self . instruction ( LocalGet ( dst_mem. addr . idx ) ) ;
29282891 self . stack_set ( & s[ ..1 ] , dst_mem_opts. ptr ( ) ) ;
29292892 self . convert_src_len_to_dst ( src_len. idx , src_mem_opts. ptr ( ) , dst_mem_opts. ptr ( ) ) ;
29302893 self . stack_set ( & s[ 1 ..] , dst_mem_opts. ptr ( ) ) ;
29312894 }
29322895 Destination :: Memory ( mem) => {
2933- // Store ptr and len to destination memory location
29342896 self . instruction ( LocalGet ( mem. addr . idx ) ) ;
29352897 self . instruction ( LocalGet ( dst_mem. addr . idx ) ) ;
29362898 self . ptr_store ( mem) ;
@@ -2941,7 +2903,6 @@ impl<'a, 'b> Compiler<'a, 'b> {
29412903 Destination :: Struct ( _) | Destination :: Array ( _) => todo ! ( "CM+GC" ) ,
29422904 }
29432905
2944- // Cleanup - release all temporary locals
29452906 self . free_temp_local ( src_len) ;
29462907 self . free_temp_local ( src_mem. addr ) ;
29472908 self . free_temp_local ( dst_mem. addr ) ;
0 commit comments