feat: 增强 VMProgramBuilder 功能并优化代码结构

- 优化类注释,明确 VMProgramBuilder 的职责和功能
- 重构部分方法名称,提高代码可读性
- 添加 super 调用支持和更灵活的符号匹配机制
- 优化 CALL 和 BRANCH指令的修补逻辑
- 添加辅助方法 lastSegment,提高代码复用性
This commit is contained in:
Luke 2025-09-01 12:18:36 +08:00
parent 9e322f3d87
commit 981a1eacdb

View File

@ -1,18 +1,25 @@
package org.jcnc.snow.compiler.backend.builder;
import org.jcnc.snow.vm.engine.VMOpCode;
import java.util.*;
/**
* VMProgramBuilder 用于构建虚拟机(VM)的最终指令列表
* <p>
* 主要职责
* {@code VMProgramBuilder} 负责后端阶段的 VM 指令序列组装及符号修补
* <ul>
* <li>维护代码指令序列和符号地址表</li>
* <li>支持跨函数标签跳转的延后修补(Call/Branch Fixup)</li>
* <li>支持虚拟机本地槽位类型的管理( I/F...)</li>
* <li>管理函数与标签到指令地址的映射</li>
* <li>支持 CALL 和分支指令的延迟回填符号修补</li>
* <li>支持槽位类型标注用于类型检查和后端优化可选</li>
* </ul>
*
* <p><b>符号修补机制</b></p>
* <ul>
* <li>支持根据函数简名进行匹配例如 Student.getName 可匹配到 Person.getName实现方法复用和继承支持</li>
* <li>自动处理 super 调用的符号绑定例如 Student.super 可自动绑定到 Person.__init__</li>
* <li>所有未解决的 CALL 或分支符号在 build() 阶段将抛出异常便于调试和定位错误</li>
* </ul>
*/
public final class VMProgramBuilder {
/**
@ -46,6 +53,10 @@ public final class VMProgramBuilder {
/** 当前代码指针(已生成指令的数量/下一个指令的位置) */
private int pc = 0;
// ==============================
// 槽位类型操作
// ==============================
/**
* 设置槽位(局部变量/虚拟寄存器)的类型前缀
*
@ -66,17 +77,11 @@ public final class VMProgramBuilder {
return slotType.getOrDefault(slot, 'I');
}
/* ==========================================================
函数/标签管理
========================================================== */
// =============函数/标签声明与指令生成=================
/**
* 标记一个函数或标签的起始位置
* <p>
* 1. 记录符号到当前 pc 的映射
* 2. 立即尝试修补之前所有针对该符号的延后调用和分支
*
* @param name 函数名或标签名(全限定名)
* 声明一个函数/标签的起始地址并尝试修补所有引用到此符号的 CALL/BRANCH
* @param name 函数或标签全名 "Person.getName""loop.start"
*/
public void beginFunction(String name) {
addr.put(name, pc);
@ -84,17 +89,15 @@ public final class VMProgramBuilder {
patchBranchFixes(name);
}
/** 函数结尾的处理(占位,无需特殊处理)。 */
/** 函数结束接口,目前无具体实现,便于将来扩展。 */
public void endFunction() {}
/**
* 添加一条指令或标签到代码列表
*
* @param line 指令字符串或标签字符串(若以冒号结尾为标签)
* 添加一条 VM 指令或标签末尾':'视为标签
* @param line 指令或标签
*/
public void emit(String line) {
if (line.endsWith(":")) {
// 标签定义
String label = line.substring(0, line.length() - 1);
addr.put(label, pc);
patchBranchFixes(label);
@ -105,10 +108,9 @@ public final class VMProgramBuilder {
}
/**
* 添加一条 CALL 指令若目标未定义则延后修补
*
* @param target 目标函数全名
* @param nArgs 参数个数
* 添加一条 CALL 指令目标尚未声明时使用占位符并登记延迟修补
* @param target 目标函数全名IR 侧生成
* @param nArgs 实参个数
*/
public void emitCall(String target, int nArgs) {
Integer a = resolve(target);
@ -129,9 +131,9 @@ public final class VMProgramBuilder {
public void emitBranch(String opcode, String label) {
Integer a = resolve(label);
if (a != null) {
emit(opcode + ' ' + a);
emit(opcode + " " + a);
} else {
emit(opcode + ' ' + PLACEHOLDER);
emit(opcode + " " + PLACEHOLDER);
branchFixes.add(new BranchFix(pc - 1, label));
}
}
@ -147,8 +149,8 @@ public final class VMProgramBuilder {
public List<String> build() {
if (!callFixes.isEmpty() || !branchFixes.isEmpty()) {
throw new IllegalStateException(
"Unresolved symbols — CALL: " + callFixes +
", BRANCH: " + branchFixes);
"Unresolved symbols — CALL: " + callFixes + ", BRANCH: " + branchFixes
);
}
return List.copyOf(code);
}
@ -164,29 +166,31 @@ public final class VMProgramBuilder {
}
/**
* 修补所有等待目标函数 name CALL 指令
* <p>
* 支持两种匹配
* <ul>
* <li>全名匹配f.target == name</li>
* <li>简名匹配f.target 不含 '.'且等于 name 的最后一段</li>
* </ul>
* 这样 IR 里生成 CALL getCity 也能绑定到 Address.getCity
* 对所有待修补的 CALL 指令进行补丁
* 匹配规则
* 1. 全限定名完全匹配
* 2. 简名(最后一段)匹配
* 3. super 调用target .super 结尾name .__init__ 结尾
* @param name 新声明的符号名
*/
private void patchCallFixes(String name) {
// 当前函数的简名去掉前缀
String simpleName = name.contains(".")
? name.substring(name.lastIndexOf('.') + 1)
: name;
String nameSimple = lastSegment(name);
for (Iterator<CallFix> it = callFixes.iterator(); it.hasNext();) {
for (Iterator<CallFix> it = callFixes.iterator(); it.hasNext(); ) {
CallFix f = it.next();
// 全限定名完全匹配
boolean qualifiedMatch = f.target.equals(name);
boolean simpleMatch = !f.target.contains(".") && f.target.equals(simpleName);
// 简名匹配
String targetSimple = lastSegment(f.target);
boolean simpleMatch = targetSimple.equals(nameSimple);
// super 调用绑定
boolean superMatch = f.target.endsWith(".super") && name.endsWith(".__init__");
if (qualifiedMatch || simpleMatch) {
code.set(f.index, VMOpCode.CALL + " " + addr.get(name) + " " + f.nArgs);
if (qualifiedMatch || simpleMatch || superMatch) {
int targetAddr = addr.get(name);
code.set(f.index, VMOpCode.CALL + " " + targetAddr + " " + f.nArgs);
it.remove();
}
}
@ -198,7 +202,7 @@ public final class VMProgramBuilder {
* @param label 目标标签
*/
private void patchBranchFixes(String label) {
for (Iterator<BranchFix> it = branchFixes.iterator(); it.hasNext();) {
for (Iterator<BranchFix> it = branchFixes.iterator(); it.hasNext(); ) {
BranchFix f = it.next();
if (f.label.equals(label)) {
String patched = code.get(f.index).replace(PLACEHOLDER, addr.get(label).toString());
@ -207,4 +211,14 @@ public final class VMProgramBuilder {
}
}
}
/**
* 获取符号名最后一段即最后一个 '.' 之后的名字若无 '.' 则为原名
* @param sym 符号全名
* @return 简名
*/
private static String lastSegment(String sym) {
int p = sym.lastIndexOf('.');
return (p >= 0 && p < sym.length() - 1) ? sym.substring(p + 1) : sym;
}
}