(
&mut self,
func_ref: FuncRef,
bytecode: &CodeObject<C>,
)
| 205 | } |
| 206 | |
| 207 | pub fn compile<C: bytecode::Constant>( |
| 208 | &mut self, |
| 209 | func_ref: FuncRef, |
| 210 | bytecode: &CodeObject<C>, |
| 211 | ) -> Result<(), JitCompileError> { |
| 212 | // JIT should consume a stable instruction stream: de-specialized opcodes |
| 213 | // with zeroed CACHE entries, not runtime-mutated quickened code. |
| 214 | let clean_instructions: bytecode::CodeUnits = bytecode |
| 215 | .instructions |
| 216 | .original_bytes() |
| 217 | .as_slice() |
| 218 | .try_into() |
| 219 | .map_err(|_| JitCompileError::BadBytecode)?; |
| 220 | |
| 221 | let mut label_targets = BTreeSet::new(); |
| 222 | let mut target_arg_state = OpArgState::default(); |
| 223 | for (offset, &raw_instr) in clean_instructions.iter().enumerate() { |
| 224 | let (instruction, arg) = target_arg_state.get(raw_instr); |
| 225 | if let Some(target) = Self::instruction_target(offset as u32, instruction, arg)? { |
| 226 | label_targets.insert(target); |
| 227 | } |
| 228 | } |
| 229 | let mut arg_state = OpArgState::default(); |
| 230 | |
| 231 | // Track whether we have "returned" in the current block |
| 232 | let mut in_unreachable_code = false; |
| 233 | |
| 234 | for (offset, &raw_instr) in clean_instructions.iter().enumerate() { |
| 235 | let label = Label::from_u32(offset as u32); |
| 236 | let (instruction, arg) = arg_state.get(raw_instr); |
| 237 | |
| 238 | // If this is a label that some earlier jump can target, |
| 239 | // treat it as the start of a new reachable block: |
| 240 | if label_targets.contains(&label) { |
| 241 | // Create or get the block for this label: |
| 242 | let target_block = self.get_or_create_block(label); |
| 243 | |
| 244 | // If the current block isn't terminated, add a fallthrough jump |
| 245 | if let Some(cur) = self.builder.current_block() |
| 246 | && cur != target_block |
| 247 | { |
| 248 | // Check if the block needs a terminator by examining the last instruction |
| 249 | let needs_terminator = match self.builder.func.layout.last_inst(cur) { |
| 250 | None => true, // Empty block needs terminator |
| 251 | Some(inst) => { |
| 252 | // Check if the last instruction is a terminator |
| 253 | !self.builder.func.dfg.insts[inst].opcode().is_terminator() |
| 254 | } |
| 255 | }; |
| 256 | if needs_terminator { |
| 257 | self.builder.ins().jump(target_block, &[]); |
| 258 | } |
| 259 | } |
| 260 | // Switch to the target block |
| 261 | if self.builder.current_block() != Some(target_block) { |
| 262 | self.builder.switch_to_block(target_block); |
| 263 | } |
| 264 |
no test coverage detected