Working around rust’s double borrow error in this pattern.

huangapple go评论54阅读模式
英文:

Working around rust's double borrow error in this pattern

问题

I am writing a gameboy emulator and I have this function:

pub fn execute_classic_instruction(&mut self, opcode: u8) -> u64 {
    match opcode {
        0x31 => self.load_word_immediate_into_reg(&mut self.registers.sp),
        _ => unimplemented!(
            "Unimplemented opcode: 0x{:X} at PC=0x{:X}",
            opcode,
            self.registers.pc.value() - 1
        ),
    }
}

When opcode 0x31 is next, it executes this:

pub fn load_word_immediate_into_reg<F>(&mut self, register: &mut Register) -> u64 {
    let value = self.mmu.read_word(self.registers.pc.value());
    self.registers.pc.add(2);

    register.set_value(value);

    12
}

The problem, of course, is the double borrow that happens due to &mut self.registers.sp. Is there any way around that without using unsafe, or maybe another way to do it without writing a separate function for each opcode that changes different registers?

英文:

I am writing a gameboy emulator and I have this function:

pub fn execute_classic_instruction(&amp;mut self, opcode: u8) -&gt; u64 {
    match opcode {
        0x31 =&gt; self.load_word_immediate_into_reg(&amp;mut self.registers.sp),
        _ =&gt; unimplemented!(
            &quot;Unimplemented opcode: 0x{:X} at PC=0x{:X}&quot;,
            opcode,
            self.registers.pc.value() - 1
        ),
    }
}

When opcode 0x31 is next it executes this:

pub fn load_word_immediate_into_reg&lt;F&gt;(&amp;mut self, register: &amp;mut Register) -&gt; u64 {
    let value = self.mmu.read_word(self.registers.pc.value());
    self.registers.pc.add(2);

    register.set_value(value);

    12
}

The problem of course is the double borrow that happens due to '&mut self.registers.sp'. Is there any way around that without using unsafe, or maybe another way to do it without writing a separate function for each opcode that changes different registers?

答案1

得分: 1

以下是您要翻译的内容:

"You can take an identifying value instead of a reference.

Or you can make this an unassociated function.

The second one may be slightly more easily optimized since pc and reg are guaranteed to be separate variables. But these should be inlined enough for it not to matter. The first one is necessary if you want to pass pc as the register."

英文:

You can take an identifying value instead of a reference.

enum RegisterId {
    Sp,
    Pc,
    ...
}

pub fn execute_classic_instruction(&amp;mut self, opcode: u8) -&gt; u64 {
    match opcode {
        0x31 =&gt; self.load_word_immediate_into_reg(RegisterId::Sp),
        _ =&gt; unimplemented!(
            &quot;Unimplemented opcode: 0x{:X} at PC=0x{:X}&quot;,
            opcode,
            self.registers.pc.value() - 1
        ),
    }
}

pub fn load_word_immediate_into_reg(&amp;mut self, register: RegisterId) -&gt; u64 {
    let value = self.mmu.read_word(self.registers.pc.value());
    self.registers.pc.add(2);

    // Implement Index&lt;RegisterId&gt; so you don&#39;t need to match every time
    self.registers[RegisterId].set_value(value);

    12
}

Or you can make this an unassociated function.

pub fn execute_classic_instruction(&amp;mut self, opcode: u8) -&gt; u64 {
    match opcode {
        0x31 =&gt; load_word_immediate_into_reg(&amp;mut self.mmu, &amp;mut self.registers.pc, &amp;mut self.registers.sp),
        _ =&gt; unimplemented!(
            &quot;Unimplemented opcode: 0x{:X} at PC=0x{:X}&quot;,
            opcode,
            self.registers.pc.value() - 1
        ),
    }
}

pub fn load_word_immediate_into_reg(mmu: &amp;mut Mmu, pc: &amp;mut Pc, reg: &amp;mut Reg) -&gt; u64 {
    let value = mmu.read_word(pc.value());
    pc.add(2);

    reg.set_value(value);

    12
}

The second one may be slightly more easily optimized since pc and reg are guaranteed to be separate variables. But these should be inlined enough for it not to matter. The first one is necessary if you want to pass pc as the register.

huangapple
  • 本文由 发表于 2023年5月14日 01:11:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76244011.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定