12.9 步骤 3:CALL/RET 帧栈与故障。

- do_call:压新帧(nregs 分配、复制 r0..r7、记 ret_pc/ret_fn_id)→ pc=0;fn_id 越界 BadOp、深度≥64 StackOverflow
- do_ret:复制 r0..r7 回调用方(r0=结果)→ 弹栈 → pc=ret_pc;MAIN 的 RET = 周期结束
- 验证:用例 13 x=Add(3,4)=7、双周期帧保留;手拼自调用映像触发 StackOverflow(深度 64 后清栈)
This commit is contained in:
2026-08-21 20:17:55 +08:00
parent efe4dd1a2c
commit a84a1a62ce
+50 -3
View File
@@ -14,6 +14,8 @@
#include "vm/Machine.h"
#include <algorithm>
#include "isa/Encode.h"
#include "isa/Instr.h"
#include "isa/Op.h"
@@ -248,15 +250,60 @@ bool Machine::exec_one() {
}
return true;
}
case isa::Op::CALL:
fault_ = do_call(isa::imm16(w));
return fault_ == Fault::None;
case isa::Op::RET:
// MAIN 的 RET = 周期结束(步骤 3 处理非 MAIN 帧返回)
ended_ = true;
fault_ = do_ret();
if (fault_ != Fault::None) {
return false;
}
return !ended_; // MAIN 的 RET → 周期结束(返回 false)
default:
// CALL / CAL_TON / CAL_TOF / CAL_CTU(步骤 3 / 4 实现)
// CAL_TON / CAL_TOF / CAL_CTU(步骤 4 实现)
fault_ = Fault::BadOp;
return false;
}
}
Fault Machine::do_call(uint32_t fn_id) {
if (fn_id >= image_.header().n_funcs) {
return Fault::BadOp;
}
if (frames_.size() >= 64) {
return Fault::StackOverflow;
}
const isa::FuncRow row = image_.func_row(fn_id);
Frame f;
f.fn_id = fn_id;
f.regs.assign(row.nregs, 0);
f.ret_pc = pc_; // 已指向 CALL 的下一条
f.ret_fn_id = cur_frame().fn_id;
// 调用约定:复制当前帧 r0..r7 → 新帧(实参已由调用点 MOVE 进 r1..r7
const size_t n = std::min<size_t>(8, std::min(cur_frame().regs.size(), f.regs.size()));
for (size_t i = 0; i < n; ++i) {
f.regs[i] = cur_frame().regs[i];
}
frames_.push_back(std::move(f));
pc_ = 0;
return Fault::None;
}
Fault Machine::do_ret() {
if (frames_.size() <= 1) {
ended_ = true; // MAIN 的 RET:周期结束
return Fault::None;
}
Frame& cur = cur_frame();
Frame& caller = frames_[frames_.size() - 2];
// 调用约定:复制当前帧 r0..r7 → 调用方(r0 = 结果,r1..r7 原样返回)
const size_t n = std::min<size_t>(8, std::min(cur.regs.size(), caller.regs.size()));
for (size_t i = 0; i < n; ++i) {
caller.regs[i] = cur.regs[i];
}
pc_ = cur.ret_pc;
frames_.pop_back();
return Fault::None;
}
} // namespace vm