@@ -281,11 +281,16 @@ fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function) -> Optio
281281 // Compile all instructions
282282 for & insn_id in block. insns ( ) {
283283 let insn = function. find ( insn_id) ;
284- if gen_insn ( cb, & mut jit, & mut asm, function, insn_id, & insn) . is_none ( ) {
285- debug ! ( "Failed to compile insn: {insn_id} {insn}" ) ;
286- incr_counter ! ( failed_gen_insn) ;
287- return None ;
288- }
284+ let Err ( last_snapshot) = gen_insn ( cb, & mut jit, & mut asm, function, insn_id, & insn) else {
285+ // It's fine; we generated the instruction
286+ continue ;
287+ } ;
288+ debug ! ( "ZJIT: gen_function: Failed to compile insn: {insn_id} {insn}. Generating side-exit." ) ;
289+ incr_counter ! ( failed_gen_insn) ;
290+ gen_side_exit ( & mut jit, & mut asm, & SideExitReason :: UnhandledInstruction ( insn_id) , & function. frame_state ( last_snapshot) ) ;
291+ // Don't bother generating code after a side-exit. We won't run it.
292+ // TODO(max): Generate ud2 or equivalent.
293+ break ;
289294 }
290295 // Make sure the last patch point has enough space to insert a jump
291296 asm. pad_patch_point ( ) ;
@@ -316,7 +321,7 @@ fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function) -> Optio
316321}
317322
318323/// Compile an instruction
319- fn gen_insn ( cb : & mut CodeBlock , jit : & mut JITState , asm : & mut Assembler , function : & Function , insn_id : InsnId , insn : & Insn ) -> Option < ( ) > {
324+ fn gen_insn ( cb : & mut CodeBlock , jit : & mut JITState , asm : & mut Assembler , function : & Function , insn_id : InsnId , insn : & Insn ) -> Result < ( ) , InsnId > {
320325 // Convert InsnId to lir::Opnd
321326 macro_rules! opnd {
322327 ( $insn_id: ident) => {
@@ -334,7 +339,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
334339
335340 macro_rules! no_output {
336341 ( $call: expr) => {
337- { let ( ) = $call; return Some ( ( ) ) ; }
342+ { let ( ) = $call; return Ok ( ( ) ) ; }
338343 } ;
339344 }
340345
@@ -344,19 +349,20 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
344349
345350 let out_opnd = match insn {
346351 Insn :: Const { val : Const :: Value ( val) } => gen_const ( * val) ,
352+ Insn :: Const { .. } => panic ! ( "Unexpected Const in gen_insn: {insn}" ) ,
347353 Insn :: NewArray { elements, state } => gen_new_array ( asm, opnds ! ( elements) , & function. frame_state ( * state) ) ,
348354 Insn :: NewHash { elements, state } => gen_new_hash ( jit, asm, elements, & function. frame_state ( * state) ) ,
349355 Insn :: NewRange { low, high, flag, state } => gen_new_range ( jit, asm, opnd ! ( low) , opnd ! ( high) , * flag, & function. frame_state ( * state) ) ,
350356 Insn :: ArrayDup { val, state } => gen_array_dup ( asm, opnd ! ( val) , & function. frame_state ( * state) ) ,
351357 Insn :: StringCopy { val, chilled, state } => gen_string_copy ( asm, opnd ! ( val) , * chilled, & function. frame_state ( * state) ) ,
352358 // concatstrings shouldn't have 0 strings
353359 // If it happens we abort the compilation for now
354- Insn :: StringConcat { strings, .. } if strings. is_empty ( ) => return None ,
360+ Insn :: StringConcat { strings, state , .. } if strings. is_empty ( ) => return Err ( * state ) ,
355361 Insn :: StringConcat { strings, state } => gen_string_concat ( jit, asm, opnds ! ( strings) , & function. frame_state ( * state) ) ,
356362 Insn :: StringIntern { val, state } => gen_intern ( asm, opnd ! ( val) , & function. frame_state ( * state) ) ,
357363 Insn :: ToRegexp { opt, values, state } => gen_toregexp ( jit, asm, * opt, opnds ! ( values) , & function. frame_state ( * state) ) ,
358364 Insn :: Param { idx } => unreachable ! ( "block.insns should not have Insn::Param({idx})" ) ,
359- Insn :: Snapshot { .. } => return Some ( ( ) ) , // we don't need to do anything for this instruction at the moment
365+ Insn :: Snapshot { .. } => return Ok ( ( ) ) , // we don't need to do anything for this instruction at the moment
360366 Insn :: Jump ( branch) => no_output ! ( gen_jump( jit, asm, branch) ) ,
361367 Insn :: IfTrue { val, target } => no_output ! ( gen_if_true( jit, asm, opnd!( val) , target) ) ,
362368 Insn :: IfFalse { val, target } => no_output ! ( gen_if_false( jit, asm, opnd!( val) , target) ) ,
@@ -367,7 +373,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
367373 Insn :: SendWithoutBlockDirect { cme, iseq, self_val, args, state, .. } => gen_send_without_block_direct ( cb, jit, asm, * cme, * iseq, opnd ! ( self_val) , opnds ! ( args) , & function. frame_state ( * state) ) ,
368374 // Ensure we have enough room fit ec, self, and arguments
369375 // TODO remove this check when we have stack args (we can use Time.new to test it)
370- Insn :: InvokeBuiltin { bf, .. } if bf. argc + 2 > ( C_ARG_OPNDS . len ( ) as i32 ) => return None ,
376+ Insn :: InvokeBuiltin { bf, state , .. } if bf. argc + 2 > ( C_ARG_OPNDS . len ( ) as i32 ) => return Err ( * state ) ,
371377 Insn :: InvokeBuiltin { bf, args, state, .. } => gen_invokebuiltin ( jit, asm, & function. frame_state ( * state) , bf, opnds ! ( args) ) ,
372378 Insn :: Return { val } => no_output ! ( gen_return( asm, opnd!( val) ) ) ,
373379 Insn :: FixnumAdd { left, right, state } => gen_fixnum_add ( jit, asm, opnd ! ( left) , opnd ! ( right) , & function. frame_state ( * state) ) ,
@@ -403,22 +409,20 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
403409 & Insn :: IncrCounter ( counter) => no_output ! ( gen_incr_counter( asm, counter) ) ,
404410 Insn :: ObjToString { val, cd, state, .. } => gen_objtostring ( jit, asm, opnd ! ( val) , * cd, & function. frame_state ( * state) ) ,
405411 & Insn :: CheckInterrupts { state } => no_output ! ( gen_check_interrupts( jit, asm, & function. frame_state( state) ) ) ,
406- Insn :: ArrayExtend { .. }
407- | Insn :: ArrayMax { .. }
408- | Insn :: ArrayPush { .. }
409- | Insn :: DefinedIvar { .. }
410- | Insn :: FixnumDiv { .. }
411- | Insn :: FixnumMod { .. }
412- | Insn :: HashDup { .. }
413- | Insn :: Send { .. }
414- | Insn :: Throw { .. }
415- | Insn :: ToArray { .. }
416- | Insn :: ToNewArray { .. }
417- | Insn :: Const { .. }
412+ & Insn :: ArrayExtend { state, .. }
413+ | & Insn :: ArrayMax { state, .. }
414+ | & Insn :: ArrayPush { state, .. }
415+ | & Insn :: DefinedIvar { state, .. }
416+ | & Insn :: FixnumDiv { state, .. }
417+ | & Insn :: FixnumMod { state, .. }
418+ | & Insn :: HashDup { state, .. }
419+ | & Insn :: Send { state, .. }
420+ | & Insn :: Throw { state, .. }
421+ | & Insn :: ToArray { state, .. }
422+ | & Insn :: ToNewArray { state, .. }
418423 => {
419- debug ! ( "ZJIT: gen_function: unexpected insn {insn}" ) ;
420424 incr_counter ! ( failed_gen_insn_unexpected) ;
421- return None ;
425+ return Err ( state ) ;
422426 }
423427 } ;
424428
@@ -427,7 +431,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
427431 // If the instruction has an output, remember it in jit.opnds
428432 jit. opnds [ insn_id. 0 ] = Some ( out_opnd) ;
429433
430- Some ( ( ) )
434+ Ok ( ( ) )
431435}
432436
433437/// Gets the EP of the ISeq of the containing method, or "local level".
0 commit comments