@@ -2118,10 +2118,11 @@ static void op_get_mem(jit_ctx *ctx, vreg *dst, vreg *base, int offset, int size
21182118 encode_ldr_str_imm (ctx , size_bits , 0 , 0x01 , imm12 , base_r , dst_r );
21192119 } else {
21202120 // Offset too large - compute effective address in RTMP, then load into dst_r
2121+ int size_bits = (size == 1 ) ? 0x00 : (size == 2 ) ? 0x01 : (size == 4 ) ? 0x02 : 0x03 ;
21212122 load_immediate (ctx , offset , RTMP , false); // Use RTMP for address computation
21222123 encode_add_sub_reg (ctx , 1 , 0 , 0 , 0 , RTMP , 0 , base_r , RTMP );
21232124 // LDR dst_r, [RTMP]
2124- encode_ldr_str_imm (ctx , ( size == 8 ) ? 0x03 : 0x02 , 0 , 0x01 , 0 , RTMP , dst_r );
2125+ encode_ldr_str_imm (ctx , size_bits , 0 , 0x01 , 0 , RTMP , dst_r );
21252126 }
21262127
21272128 // Always store to stack - it's the source of truth for later loads
@@ -2206,7 +2207,10 @@ static void op_set_mem(jit_ctx *ctx, vreg *base, int offset, vreg *value, int si
22062207 encode_add_sub_reg (ctx , 1 , 0 , 0 , 0 , RTMP2 , 0 , base_r , RTMP );
22072208 }
22082209 // STR value_r, [RTMP]
2209- encode_ldr_str_imm (ctx , (size == 8 ) ? 0x03 : 0x02 , 0 , 0x00 , 0 , RTMP , value_r );
2210+ {
2211+ int size_bits = (size == 1 ) ? 0x00 : (size == 2 ) ? 0x01 : (size == 4 ) ? 0x02 : 0x03 ;
2212+ encode_ldr_str_imm (ctx , size_bits , 0 , 0x00 , 0 , RTMP , value_r );
2213+ }
22102214 }
22112215 }
22122216
@@ -4136,14 +4140,22 @@ void hl_jit_free(jit_ctx *ctx, h_bool can_reset) {
41364140 if (ctx == NULL )
41374141 return ;
41384142
4139- if (ctx -> startBuf )
4140- free (ctx -> startBuf );
4141- if (ctx -> vregs )
4142- free (ctx -> vregs );
4143- if (ctx -> opsPos )
4144- free (ctx -> opsPos );
4145-
4146- free (ctx );
4143+ free (ctx -> vregs );
4144+ free (ctx -> opsPos );
4145+ free (ctx -> startBuf );
4146+ ctx -> maxRegs = 0 ;
4147+ ctx -> vregs = NULL ;
4148+ ctx -> maxOps = 0 ;
4149+ ctx -> opsPos = NULL ;
4150+ ctx -> startBuf = NULL ;
4151+ ctx -> bufSize = 0 ;
4152+ ctx -> buf .b = NULL ;
4153+ ctx -> calls = NULL ;
4154+ ctx -> switchs = NULL ;
4155+ ctx -> closure_list = NULL ;
4156+ hl_free (& ctx -> falloc );
4157+ hl_free (& ctx -> galloc );
4158+ if (!can_reset ) free (ctx );
41474159}
41484160
41494161void hl_jit_reset (jit_ctx * ctx , hl_module * m ) {
@@ -5765,32 +5777,48 @@ int hl_jit_function(jit_ctx *ctx, hl_module *m, hl_function *f) {
57655777 break ;
57665778
57675779 case OSwitch :
5768- // Switch statement - simplified linear search approach
5780+ // Switch statement - O(1) branch table dispatch
57695781 {
57705782 // Spill all registers before any conditional jumps.
57715783 // Jump targets will have discard_regs() via OLabel.
57725784 spill_regs (ctx );
57735785
57745786 // Fetch the switch value (this creates a new binding after spill)
57755787 preg * r_val = fetch (ctx , dst );
5788+ Arm64Reg val_r = (Arm64Reg )r_val -> id ;
5789+
5790+ // CMP value, #count (bounds check)
5791+ if (o -> p2 < 4096 ) {
5792+ encode_add_sub_imm (ctx , 0 , 1 , 1 , 0 , o -> p2 , val_r , XZR );
5793+ } else {
5794+ load_immediate (ctx , o -> p2 , RTMP , false);
5795+ encode_add_sub_reg (ctx , 0 , 1 , 1 , 0 , RTMP , 0 , val_r , XZR );
5796+ }
5797+
5798+ // B.HS default (unsigned >= count means out of range)
5799+ int jdefault = BUF_POS ();
5800+ encode_branch_cond (ctx , 0 , COND_HS );
5801+
5802+ // ADR RTMP, table_start (3 instructions ahead = +12 bytes)
5803+ // ADR encodes PC-relative: immhi = imm>>2, immlo = imm&3
5804+ EMIT32 (ctx , 0x10000000 | ((12 & 3 ) << 29 ) | ((12 >> 2 ) << 5 ) | RTMP );
5805+
5806+ // ADD RTMP, RTMP, Wn, UXTW #2 (index * 4 bytes per B instruction)
5807+ encode_add_sub_ext (ctx , 1 , 0 , 0 , val_r , 2 , 2 , RTMP , RTMP );
57765808
5777- // For each case, compare and branch
5809+ // BR RTMP
5810+ EMIT32 (ctx , 0xD61F0000 | (RTMP << 5 ));
5811+
5812+ // Branch table: one B instruction per case
57785813 for (int i = 0 ; i < o -> p2 ; i ++ ) {
5779- // CMP value, #i
5780- if (i < 256 ) {
5781- // SUBS XZR, Xn, #i
5782- encode_add_sub_imm (ctx , (dst -> size == 8 ) ? 1 : 0 , 1 , 1 , 0 , i , (Arm64Reg )r_val -> id , XZR );
5783- } else {
5784- load_immediate (ctx , i , RTMP , false);
5785- encode_add_sub_reg (ctx , (dst -> size == 8 ) ? 1 : 0 , 1 , 1 , 0 , RTMP , 0 , (Arm64Reg )r_val -> id , XZR );
5786- }
5787-
5788- // B.EQ to target
57895814 int jump_pos = BUF_POS ();
5790- encode_branch_cond (ctx , 0 , COND_EQ );
5815+ EMIT32 (ctx , 0x14000000 ); // B #0 (placeholder, patched by register_jump)
57915816 register_jump (ctx , jump_pos , (opCount + 1 ) + o -> extra [i ]);
5817+ if ((i & 15 ) == 0 ) jit_buf (ctx );
57925818 }
5793- // If no match, fall through (default case is next instruction)
5819+
5820+ // Default: patch B.HS to here
5821+ patch_jump (ctx , jdefault , BUF_POS ());
57945822 }
57955823 break ;
57965824
@@ -5875,13 +5903,37 @@ int hl_jit_function(jit_ctx *ctx, hl_module *m, hl_function *f) {
58755903 encode_ldr_str_reg (ctx , 0x03 , 0 , 0x00 , RTMP , 0x03 , 0 , X0 , X10 );
58765904 }
58775905
5878- // Step 4: Set tcheck = NULL (simplified - not doing type filtering yet)
5879- // STR XZR, [SP, #offset_tcheck]
5880- if (offset_tcheck < 4096 ) {
5881- encode_ldr_str_imm (ctx , 0x03 , 0 , 0x00 , offset_tcheck / 8 , X10 , XZR );
5882- } else {
5883- load_immediate (ctx , offset_tcheck , RTMP , true);
5884- encode_ldr_str_reg (ctx , 0x03 , 0 , 0x00 , RTMP , 0x03 , 0 , X10 , XZR );
5906+ // Step 4: Set tcheck for exception type filtering
5907+ // Look ahead at catch handler opcodes to determine the exception type
5908+ // (same pattern as x86 backend)
5909+ {
5910+ hl_opcode * cat = f -> ops + opCount + 1 ;
5911+ hl_opcode * next = f -> ops + opCount + 1 + o -> p2 ;
5912+ hl_opcode * next2 = f -> ops + opCount + 2 + o -> p2 ;
5913+ Arm64Reg tcheck_val = XZR ; // default: NULL = catch all
5914+
5915+ if (cat -> op == OCatch ||
5916+ (next -> op == OGetGlobal && next2 -> op == OCall2 &&
5917+ next2 -> p3 == next -> p1 && dst -> stack .id == (int )(int_val )next2 -> extra )) {
5918+ int gindex = cat -> op == OCatch ? cat -> p1 : next -> p2 ;
5919+ hl_type * gt = ctx -> m -> code -> globals [gindex ];
5920+ while (gt -> kind == HOBJ && gt -> obj -> super ) gt = gt -> obj -> super ;
5921+ if (gt -> kind == HOBJ && gt -> obj -> nfields && gt -> obj -> fields [0 ].t -> kind == HTYPE ) {
5922+ void * addr = ctx -> m -> globals_data + ctx -> m -> globals_indexes [gindex ];
5923+ // Load address of the global, then dereference to get the type object
5924+ load_immediate (ctx , (int64_t )addr , X9 , true);
5925+ encode_ldr_str_imm (ctx , 0x03 , 0 , 0x01 , 0 , X9 , X9 ); // LDR X9, [X9]
5926+ tcheck_val = X9 ;
5927+ }
5928+ }
5929+
5930+ // STR tcheck_val, [SP, #offset_tcheck]
5931+ if (offset_tcheck < 4096 ) {
5932+ encode_ldr_str_imm (ctx , 0x03 , 0 , 0x00 , offset_tcheck / 8 , X10 , tcheck_val );
5933+ } else {
5934+ load_immediate (ctx , offset_tcheck , RTMP , true);
5935+ encode_ldr_str_reg (ctx , 0x03 , 0 , 0x00 , RTMP , 0x03 , 0 , X10 , tcheck_val );
5936+ }
58855937 }
58865938
58875939 // Step 5: Call setjmp(trap_ctx)
@@ -6017,20 +6069,21 @@ int hl_jit_function(jit_ctx *ctx, hl_module *m, hl_function *f) {
60176069 break ;
60186070
60196071 case OAssert :
6020- // Call the assertion helper (static_functions[1])
6072+ // Call the assertion helper (hl_assert)
6073+ // Use same LDR+BLR+B+literal pattern as JIT function calls
60216074 {
6075+ EMIT32 (ctx , 0x58000071 ); // LDR X17, #12 (load from literal pool)
6076+ EMIT32 (ctx , 0xD63F0220 ); // BLR X17
6077+
60226078 jlist * j = (jlist * )hl_malloc (& ctx -> galloc , sizeof (jlist ));
6023- j -> pos = BUF_POS ();
6079+ j -> pos = BUF_POS () + 4 ; // Position of the 8-byte literal (after B)
60246080 j -> target = -2 ; // Special marker for assert function
60256081 j -> next = ctx -> calls ;
60266082 ctx -> calls = j ;
60276083
6028- // Load address placeholder and call
6029- // Will be patched to static_functions[1] in hl_jit_code
6030- EMIT32 (ctx , 0 ); // Placeholder for address (low)
6031- EMIT32 (ctx , 0 ); // Placeholder for address (high)
6032- // For now, emit a BL that will be patched
6033- EMIT32 (ctx , 0x94000000 ); // BL (will be patched)
6084+ EMIT32 (ctx , 0x14000003 ); // B #12 (skip over literal)
6085+ EMIT32 (ctx , 0 ); // Low 32 bits placeholder
6086+ EMIT32 (ctx , 0 ); // High 32 bits placeholder
60346087 }
60356088 break ;
60366089
0 commit comments