fn update_instructions()

in src/profiler/elastic_apm_profiler/src/cil/method.rs [431:564]


    fn update_instructions(&mut self, index: usize, offset: usize, len: i64) {
        // update the offsets of control flow instructions and expand any short instructions:
        //
        // 1. for control flow instructions before the target index,
        //    if the offset is positive and results in an index after the target index,
        //    add len to the offset
        // 2. for control flow instructions after the target index,
        //    if the offset is negative and results in an index before the target index,
        //    subtract len from the offset i.e. offset is further away
        let mut map: Vec<usize> = self.instructions.iter().map(|i| i.len()).collect();
        let mut updated_instructions = vec![];
        for (i, instruction) in self.instructions.iter_mut().enumerate() {
            if i < index {
                if let ShortInlineBrTarget(target_offset) = &mut instruction.operand {
                    if *target_offset >= 0 {
                        let mut sum_len = 0;
                        let mut j = 1;
                        while sum_len < *target_offset as usize {
                            sum_len += map[i + j];
                            j += 1;
                        }
                        if i + j > index {
                            let n = *target_offset as i32 + len as i32;
                            if n > i8::MAX as i32 {
                                let current_len = instruction.len();

                                // update the instruction
                                instruction.operand = InlineBrTarget(n);
                                instruction.opcode = Opcode::short_to_long_form(instruction.opcode);

                                // update the map with the new instruction len and record
                                // the original offset and len diff.
                                let new_len = instruction.len();
                                map[i] = new_len;
                                updated_instructions.push((offset, (new_len - current_len) as i64));
                            } else {
                                *target_offset = n as i8;
                            }
                        }
                    }
                } else if let InlineBrTarget(target_offset) = &mut instruction.operand {
                    if *target_offset >= 0 {
                        let mut sum_len = 0;
                        let mut j = 1;
                        while sum_len < *target_offset as usize {
                            sum_len += map[i + j];
                            j += 1;
                        }
                        if i + j > index {
                            let n = *target_offset + len as i32;
                            *target_offset = n;
                        }
                    }
                } else if let InlineSwitch(count, target_offsets) = &mut instruction.operand {
                    for target_offset in target_offsets {
                        if *target_offset >= 0 {
                            let mut sum_len = 0;
                            let mut j = 1;
                            while sum_len < *target_offset as usize {
                                sum_len += map[i + j];
                                j += 1;
                            }
                            if i + j > index {
                                *target_offset += len as i32;
                            }
                        }
                    }
                }
            } else {
                if let ShortInlineBrTarget(target_offset) = &mut instruction.operand {
                    if *target_offset < 0 {
                        let mut sum_len = 0;
                        let mut j = 0;
                        while *target_offset < sum_len {
                            sum_len -= map[i - j] as i8;
                            j += 1;
                        }
                        if i - j < index {
                            let n = *target_offset as i32 - len as i32;
                            if n < i8::MIN as i32 {
                                let current_len = instruction.len();

                                // update the instruction
                                instruction.operand = InlineBrTarget(n);
                                instruction.opcode = Opcode::short_to_long_form(instruction.opcode);

                                // update the map with the new instruction len and record
                                // the original offset and len diff.
                                let new_len = instruction.len();
                                map[i] = new_len;
                                updated_instructions.push((offset, (new_len - current_len) as i64));
                            } else {
                                *target_offset = n as i8;
                            }
                        }
                    }
                } else if let InlineBrTarget(target_offset) = &mut instruction.operand {
                    if *target_offset < 0 {
                        let mut sum_len = 0;
                        let mut j = 0;
                        while *target_offset < sum_len {
                            sum_len -= map[i - j] as i32;
                            j += 1;
                        }
                        if i - j < index {
                            let n = *target_offset - len as i32;
                            *target_offset = n;
                        }
                    }
                } else if let InlineSwitch(count, target_offsets) = &mut instruction.operand {
                    for target_offset in target_offsets {
                        if *target_offset < 0 {
                            let mut sum_len = 0;
                            let mut j = 0;
                            while *target_offset < sum_len {
                                sum_len -= map[i - j] as i32;
                                j += 1;
                            }
                            if i - j < index {
                                *target_offset -= len as i32;
                            }
                        }
                    }
                }
            }
        }

        if !updated_instructions.is_empty() {
            for (offset, len) in updated_instructions {
                self.update_header(len, None).unwrap();
                self.update_sections(offset, len).unwrap();
            }
        }
    }