(existing: &mut FrameState, incoming: &FrameState, live_locals: &[bool])
| 1091 | let Some(&block) = block_by_instruction.get(target) else { |
| 1092 | return Ok(()); |
| 1093 | }; |
| 1094 | if block_starts[block] != target { |
| 1095 | return Err(jvm::Error::VerificationError { |
| 1096 | context: context.to_string(), |
| 1097 | message: format!("Control flow targets the middle of bytecode block at {target}"), |
| 1098 | }); |
| 1099 | } |
| 1100 | let changed = match &mut entry_states[block] { |
| 1101 | Some(existing) => merge_state(existing, &incoming), |
| 1102 | slot @ None => { |
| 1103 | *slot = Some(incoming); |
| 1104 | true |
| 1105 | } |
| 1106 | }; |
| 1107 | if changed && !queued[block] { |
| 1108 | queued[block] = true; |
| 1109 | worklist.push_back(block); |
| 1110 | } |
| 1111 | Ok(()) |
| 1112 | } |
| 1113 | |
| 1114 | fn describe_instruction(instruction: &Instruction, constant_pool: &ConstantPool) -> String { |
| 1115 | let method = match instruction { |
| 1116 | Instruction::Invokevirtual(index) | Instruction::Invokespecial(index) => { |
| 1117 | method_ref_info(constant_pool, *index, false).ok() |
| 1118 | } |
| 1119 | Instruction::Invokestatic(index) => static_method_ref_info(constant_pool, *index).ok(), |
| 1120 | Instruction::Invokeinterface(index, _) => method_ref_info(constant_pool, *index, true).ok(), |
| 1121 | _ => None, |
| 1122 | }; |
| 1123 | method.map_or_else( |
| 1124 | || format!("{instruction:?}"), |
| 1125 | |method| { |
| 1126 | format!( |
| 1127 | "{instruction:?} => {}.{}{}", |
| 1128 | method.class_name, method.method_name, method.descriptor |
no test coverage detected