@@ -281,11 +281,15 @@ 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}" ) ;
284+ if let Err ( last_snapshot ) = gen_insn ( cb, & mut jit, & mut asm, function, insn_id, & insn) {
285+ debug ! ( "ZJIT: gen_function: Failed to compile insn: {insn_id} {insn}. Generating side-exit. " ) ;
286286 incr_counter ! ( failed_gen_insn) ;
287- return None ;
288- }
287+ gen_side_exit ( & mut jit, & mut asm, & SideExitReason :: UnhandledInstruction ( insn_id) , & function. frame_state ( last_snapshot) ) ;
288+ // Don't bother generating code after a side-exit. We won't run it.
289+ // TODO(max): Generate ud2 or equivalent.
290+ break ;
291+ } ;
292+ // It's fine; we generated the instruction
289293 }
290294 // Make sure the last patch point has enough space to insert a jump
291295 asm. pad_patch_point ( ) ;
@@ -316,7 +320,7 @@ fn gen_function(cb: &mut CodeBlock, iseq: IseqPtr, function: &Function) -> Optio
316320}
317321
318322/// Compile an instruction
319- fn gen_insn ( cb : & mut CodeBlock , jit : & mut JITState , asm : & mut Assembler , function : & Function , insn_id : InsnId , insn : & Insn ) -> Option < ( ) > {
323+ fn gen_insn ( cb : & mut CodeBlock , jit : & mut JITState , asm : & mut Assembler , function : & Function , insn_id : InsnId , insn : & Insn ) -> Result < ( ) , InsnId > {
320324 // Convert InsnId to lir::Opnd
321325 macro_rules! opnd {
322326 ( $insn_id: ident) => {
@@ -334,7 +338,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
334338
335339 macro_rules! no_output {
336340 ( $call: expr) => {
337- { let ( ) = $call; return Some ( ( ) ) ; }
341+ { let ( ) = $call; return Ok ( ( ) ) ; }
338342 } ;
339343 }
340344
@@ -344,19 +348,20 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
344348
345349 let out_opnd = match insn {
346350 Insn :: Const { val : Const :: Value ( val) } => gen_const ( * val) ,
351+ Insn :: Const { .. } => panic ! ( "Unexpected Const in gen_insn: {insn}" ) ,
347352 Insn :: NewArray { elements, state } => gen_new_array ( asm, opnds ! ( elements) , & function. frame_state ( * state) ) ,
348353 Insn :: NewHash { elements, state } => gen_new_hash ( jit, asm, elements, & function. frame_state ( * state) ) ,
349354 Insn :: NewRange { low, high, flag, state } => gen_new_range ( jit, asm, opnd ! ( low) , opnd ! ( high) , * flag, & function. frame_state ( * state) ) ,
350355 Insn :: ArrayDup { val, state } => gen_array_dup ( asm, opnd ! ( val) , & function. frame_state ( * state) ) ,
351356 Insn :: StringCopy { val, chilled, state } => gen_string_copy ( asm, opnd ! ( val) , * chilled, & function. frame_state ( * state) ) ,
352357 // concatstrings shouldn't have 0 strings
353358 // If it happens we abort the compilation for now
354- Insn :: StringConcat { strings, .. } if strings. is_empty ( ) => return None ,
359+ Insn :: StringConcat { strings, state , .. } if strings. is_empty ( ) => return Err ( * state ) ,
355360 Insn :: StringConcat { strings, state } => gen_string_concat ( jit, asm, opnds ! ( strings) , & function. frame_state ( * state) ) ,
356361 Insn :: StringIntern { val, state } => gen_intern ( asm, opnd ! ( val) , & function. frame_state ( * state) ) ,
357362 Insn :: ToRegexp { opt, values, state } => gen_toregexp ( jit, asm, * opt, opnds ! ( values) , & function. frame_state ( * state) ) ,
358363 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
364+ Insn :: Snapshot { .. } => return Ok ( ( ) ) , // we don't need to do anything for this instruction at the moment
360365 Insn :: Jump ( branch) => no_output ! ( gen_jump( jit, asm, branch) ) ,
361366 Insn :: IfTrue { val, target } => no_output ! ( gen_if_true( jit, asm, opnd!( val) , target) ) ,
362367 Insn :: IfFalse { val, target } => no_output ! ( gen_if_false( jit, asm, opnd!( val) , target) ) ,
@@ -367,7 +372,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
367372 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) ) ,
368373 // Ensure we have enough room fit ec, self, and arguments
369374 // 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 ,
375+ Insn :: InvokeBuiltin { bf, state , .. } if bf. argc + 2 > ( C_ARG_OPNDS . len ( ) as i32 ) => return Err ( * state ) ,
371376 Insn :: InvokeBuiltin { bf, args, state, .. } => gen_invokebuiltin ( jit, asm, & function. frame_state ( * state) , bf, opnds ! ( args) ) ,
372377 Insn :: Return { val } => no_output ! ( gen_return( asm, opnd!( val) ) ) ,
373378 Insn :: FixnumAdd { left, right, state } => gen_fixnum_add ( jit, asm, opnd ! ( left) , opnd ! ( right) , & function. frame_state ( * state) ) ,
@@ -403,22 +408,20 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
403408 & Insn :: IncrCounter ( counter) => no_output ! ( gen_incr_counter( asm, counter) ) ,
404409 Insn :: ObjToString { val, cd, state, .. } => gen_objtostring ( jit, asm, opnd ! ( val) , * cd, & function. frame_state ( * state) ) ,
405410 & 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 { .. }
411+ & Insn :: ArrayExtend { state, .. }
412+ | & Insn :: ArrayMax { state, .. }
413+ | & Insn :: ArrayPush { state, .. }
414+ | & Insn :: DefinedIvar { state, .. }
415+ | & Insn :: FixnumDiv { state, .. }
416+ | & Insn :: FixnumMod { state, .. }
417+ | & Insn :: HashDup { state, .. }
418+ | & Insn :: Send { state, .. }
419+ | & Insn :: Throw { state, .. }
420+ | & Insn :: ToArray { state, .. }
421+ | & Insn :: ToNewArray { state, .. }
418422 => {
419- debug ! ( "ZJIT: gen_function: unexpected insn {insn}" ) ;
420423 incr_counter ! ( failed_gen_insn_unexpected) ;
421- return None ;
424+ return Err ( state ) ;
422425 }
423426 } ;
424427
@@ -427,7 +430,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
427430 // If the instruction has an output, remember it in jit.opnds
428431 jit. opnds [ insn_id. 0 ] = Some ( out_opnd) ;
429432
430- Some ( ( ) )
433+ Ok ( ( ) )
431434}
432435
433436/// Gets the EP of the ISeq of the containing method, or "local level".
0 commit comments