refactor: 重构代码以提高可读性和可维护性
- 优化了方法结构,减少了冗余代码 - 提高了错误提示的详细程度 - 增加了类型前缀处理方法,简化了类型判断逻辑 - 调整了参数加载逻辑,提高了代码复用性
This commit is contained in:
parent
86a78bd1c6
commit
325ca67872
@ -16,40 +16,62 @@ import java.util.Map;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@code CallGenerator} 负责将 IR 层的 {@link CallInstruction} 生成对应的 VM 层函数调用指令。
|
* CallGenerator 负责将 IR 层的 CallInstruction 转换为 VM 层的函数调用指令。
|
||||||
* <p>
|
* <p>
|
||||||
* 支持 syscall、普通函数调用、一维/多维数组下标访问、以及字符串常量池绑定等功能。
|
* 功能包括:
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>syscall: 支持字符串常量与寄存器到子命令的绑定与解析</li>
|
* <li>处理系统调用(syscall),支持字符串常量池</li>
|
||||||
* <li>数组下标访问: 支持所有主流基础类型 “__index_b/s/i/l/f/d/r”</li>
|
* <li>数组元素访问及赋值(__index / __setindex 系列)</li>
|
||||||
* <li>普通函数: 支持自动推断返回值类型与槽位类型</li>
|
* <li>普通函数调用,根据返回类型选择合适的 STORE 指令</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串常量池:用于绑定虚拟寄存器 id 到字符串值(供 syscall 子命令使用)。
|
* 字符串常量池,用于 syscall 子命令的字符串存储,
|
||||||
* <br>
|
* 键为虚拟寄存器 ID,值为字符串常量。
|
||||||
* 使用 ConcurrentHashMap 保证并发安全,所有 registerStringConst 的注册和读取都是线程安全的。
|
|
||||||
*/
|
*/
|
||||||
private static final Map<Integer, String> STRING_CONST_POOL = new ConcurrentHashMap<>();
|
private static final Map<Integer, String> STRING_CONST_POOL = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册一个字符串常量,绑定到虚拟寄存器 id。
|
* 当前正在生成的函数名,用于错误上下文。
|
||||||
|
*/
|
||||||
|
private String fn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册字符串常量到常量池。
|
||||||
*
|
*
|
||||||
* @param regId 虚拟寄存器 id
|
* @param regId 虚拟寄存器 ID
|
||||||
* @param value 字符串常量
|
* @param value 字符串常量值
|
||||||
*/
|
*/
|
||||||
public static void registerStringConst(int regId, String value) {
|
public static void registerStringConst(int regId, String value) {
|
||||||
STRING_CONST_POOL.put(regId, value);
|
STRING_CONST_POOL.put(regId, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回本生成器支持的 IR 指令类型。
|
* 将语言层类型名映射为 VM 指令的类型前缀字符。
|
||||||
*
|
*
|
||||||
* @return {@link CallInstruction} 类型的 Class 对象
|
* @param name 类型名称,如 "int", "double", "string"
|
||||||
|
* @return 对应的 VM 类型前缀('I','D','R' 等)
|
||||||
|
*/
|
||||||
|
private static char normalizeTypePrefix(String name) {
|
||||||
|
if (name == null) return 'I';
|
||||||
|
String n = name.toLowerCase(Locale.ROOT);
|
||||||
|
return switch (n) {
|
||||||
|
case "byte" -> 'B';
|
||||||
|
case "short" -> 'S';
|
||||||
|
case "int", "integer", "bool", "boolean" -> 'I';
|
||||||
|
case "long" -> 'L';
|
||||||
|
case "float" -> 'F';
|
||||||
|
case "double" -> 'D';
|
||||||
|
case "string" -> 'R'; // 字符串为引用类型
|
||||||
|
case "void" -> 'V';
|
||||||
|
default -> 'R'; // 结构体、自定义对象均视为引用类型
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回本生成器支持的 IR 指令类型,此处为 CallInstruction。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Class<CallInstruction> supportedClass() {
|
public Class<CallInstruction> supportedClass() {
|
||||||
@ -57,12 +79,12 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成指定的调用指令,包括 syscall、数组下标、普通函数。
|
* 核心生成方法,根据函数名分发到 syscall、数组操作或普通调用的处理逻辑。
|
||||||
*
|
*
|
||||||
* @param ins IR 层的调用指令
|
* @param ins 待转换的 IR 调用指令
|
||||||
* @param out VM 程序构建器
|
* @param out VM 程序构建器,用于输出指令
|
||||||
* @param slotMap 寄存器到槽位的映射表
|
* @param slotMap IR 虚拟寄存器到 VM 本地槽位的映射
|
||||||
* @param currentFn 当前函数名
|
* @param currentFn 当前所在的函数名,用于上下文传递
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void generate(CallInstruction ins,
|
public void generate(CallInstruction ins,
|
||||||
@ -71,91 +93,41 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
|||||||
String currentFn) {
|
String currentFn) {
|
||||||
String fn = ins.getFunctionName();
|
String fn = ins.getFunctionName();
|
||||||
|
|
||||||
// 特殊处理 syscall 调用
|
// 处理特殊的 syscall 调用
|
||||||
if ("syscall".equals(fn) || fn.endsWith(".syscall")) {
|
if ("syscall".equals(fn) || fn.endsWith(".syscall")) {
|
||||||
generateSyscall(ins, out, slotMap, fn);
|
generateSyscall(ins, out, slotMap, fn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 各种一维数组类型(byte/short/int/long/float/double/boolean)读取
|
// 处理数组读取和写入的内置函数
|
||||||
switch (fn) {
|
switch (fn) {
|
||||||
case "__index_b" -> {
|
case "__index_b" -> { generateIndexInstruction(ins, out, slotMap, 'B'); return; }
|
||||||
generateIndexInstruction(ins, out, slotMap, 'B');
|
case "__index_s" -> { generateIndexInstruction(ins, out, slotMap, 'S'); return; }
|
||||||
return;
|
case "__index_i" -> { generateIndexInstruction(ins, out, slotMap, 'I'); return; }
|
||||||
}
|
case "__index_l" -> { generateIndexInstruction(ins, out, slotMap, 'L'); return; }
|
||||||
case "__index_s" -> {
|
case "__index_f" -> { generateIndexInstruction(ins, out, slotMap, 'F'); return; }
|
||||||
generateIndexInstruction(ins, out, slotMap, 'S');
|
case "__index_d" -> { generateIndexInstruction(ins, out, slotMap, 'D'); return; }
|
||||||
return;
|
case "__index_r" -> { generateIndexInstruction(ins, out, slotMap, 'R'); return; }
|
||||||
}
|
case "__setindex_b" -> { generateSetIndexInstruction(ins, out, slotMap, 'B'); return; }
|
||||||
case "__index_i" -> {
|
case "__setindex_s" -> { generateSetIndexInstruction(ins, out, slotMap, 'S'); return; }
|
||||||
generateIndexInstruction(ins, out, slotMap, 'I');
|
case "__setindex_i" -> { generateSetIndexInstruction(ins, out, slotMap, 'I'); return; }
|
||||||
return;
|
case "__setindex_l" -> { generateSetIndexInstruction(ins, out, slotMap, 'L'); return; }
|
||||||
}
|
case "__setindex_f" -> { generateSetIndexInstruction(ins, out, slotMap, 'F'); return; }
|
||||||
case "__index_l" -> {
|
case "__setindex_d" -> { generateSetIndexInstruction(ins, out, slotMap, 'D'); return; }
|
||||||
generateIndexInstruction(ins, out, slotMap, 'L');
|
case "__setindex_r" -> { generateSetIndexInstruction(ins, out, slotMap, 'R'); return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
case "__index_f" -> {
|
|
||||||
generateIndexInstruction(ins, out, slotMap, 'F');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case "__index_d" -> {
|
|
||||||
generateIndexInstruction(ins, out, slotMap, 'D');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case "__index_r" -> {
|
|
||||||
generateIndexInstruction(ins, out, slotMap, 'R');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
case "__setindex_b" -> {
|
|
||||||
generateSetIndexInstruction(ins, out, slotMap, 'B');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case "__setindex_s" -> {
|
|
||||||
generateSetIndexInstruction(ins, out, slotMap, 'S');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case "__setindex_i" -> {
|
|
||||||
generateSetIndexInstruction(ins, out, slotMap, 'I');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case "__setindex_l" -> {
|
|
||||||
generateSetIndexInstruction(ins, out, slotMap, 'L');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case "__setindex_f" -> {
|
|
||||||
generateSetIndexInstruction(ins, out, slotMap, 'F');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case "__setindex_d" -> {
|
|
||||||
generateSetIndexInstruction(ins, out, slotMap, 'D');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
case "__setindex_r" -> {
|
|
||||||
generateSetIndexInstruction(ins, out, slotMap, 'R');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 普通函数调用
|
// 默认:普通函数调用
|
||||||
generateNormalCall(ins, out, slotMap, fn);
|
generateNormalCall(ins, out, slotMap, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========== 私有辅助方法 ==========
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成数组元素赋值指令(arr[idx] = value),无返回值。
|
* 生成数组元素赋值指令。
|
||||||
* <p>
|
|
||||||
* 调用栈压栈顺序为:arr (引用类型, R),idx (整型, I),value (元素类型, T)。
|
|
||||||
* 执行 SYSCALL ARR_SET 指令以完成数组赋值操作。
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @param ins 当前的调用指令(包含参数信息)
|
* @param ins 调用 __setindex_* 的 IR 指令
|
||||||
* @param out VM 指令生成器(用于输出 VM 指令)
|
* @param out VM 指令构建器
|
||||||
* @param slotMap 虚拟寄存器与槽位的映射表
|
* @param slotMap 寄存器到槽位映射
|
||||||
* @param valType 待写入的 value 的类型标识('B': byte, 'S': short, 'I': int, 'L': long, 'F': float, 'D': double, 其余为引用类型'R')
|
* @param valType 元素值的类型前缀(如 'I','R' 等)
|
||||||
* @throws IllegalStateException 如果参数数量不为3,则抛出异常
|
|
||||||
*/
|
*/
|
||||||
private void generateSetIndexInstruction(CallInstruction ins,
|
private void generateSetIndexInstruction(CallInstruction ins,
|
||||||
VMProgramBuilder out,
|
VMProgramBuilder out,
|
||||||
@ -163,88 +135,175 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
|||||||
char valType) {
|
char valType) {
|
||||||
List<IRValue> args = ins.getArguments();
|
List<IRValue> args = ins.getArguments();
|
||||||
if (args.size() != 3) {
|
if (args.size() != 3) {
|
||||||
// 参数数量错误,抛出异常并输出实际参数列表
|
throw new IllegalStateException("[CallGenerator] __setindex_* 需要三个参数 (arr, idx, value),实际: " + args);
|
||||||
throw new IllegalStateException(
|
|
||||||
"[CallGenerator] __setindex_* 需要三个参数(arr, idx, value),实际: " + args);
|
|
||||||
}
|
}
|
||||||
|
loadArgument(out, slotMap, args.get(0), 'R', ins.getFunctionName()); // 数组引用
|
||||||
// 第一个参数为数组对象,压入引用类型寄存器('R'),如 arr
|
loadArgument(out, slotMap, args.get(1), 'I', ins.getFunctionName()); // 索引
|
||||||
loadArgument(out, slotMap, args.get(0), 'R', ins.getFunctionName());
|
loadArgument(out, slotMap, args.get(2), valType, ins.getFunctionName()); // 值
|
||||||
|
out.emit(VMOpCode.SYSCALL + " ARR_SET");
|
||||||
// 第二个参数为索引值,压入整型寄存器('I'),如 idx
|
|
||||||
loadArgument(out, slotMap, args.get(1), 'I', ins.getFunctionName());
|
|
||||||
|
|
||||||
// 第三个参数为待赋值元素,根据元素类型压入相应类型寄存器
|
|
||||||
// 支持类型:'B'(byte), 'S'(short), 'I'(int), 'L'(long), 'F'(float), 'D'(double)
|
|
||||||
// 其他情况(如引用类型),按'R'处理
|
|
||||||
switch (valType) {
|
|
||||||
case 'B' -> loadArgument(out, slotMap, args.get(2), 'B', ins.getFunctionName());
|
|
||||||
case 'S' -> loadArgument(out, slotMap, args.get(2), 'S', ins.getFunctionName());
|
|
||||||
case 'I' -> loadArgument(out, slotMap, args.get(2), 'I', ins.getFunctionName());
|
|
||||||
case 'L' -> loadArgument(out, slotMap, args.get(2), 'L', ins.getFunctionName());
|
|
||||||
case 'F' -> loadArgument(out, slotMap, args.get(2), 'F', ins.getFunctionName());
|
|
||||||
case 'D' -> loadArgument(out, slotMap, args.get(2), 'D', ins.getFunctionName());
|
|
||||||
default -> loadArgument(out, slotMap, args.get(2), 'R', ins.getFunctionName());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 输出 VM 指令:SYSCALL ARR_SET,完成数组元素写入操作
|
|
||||||
out.emit(VMOpCode.SYSCALL + " " + "ARR_SET");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成数组元素读取指令。
|
||||||
|
*
|
||||||
|
* @param ins 调用 __index_* 的 IR 指令
|
||||||
|
* @param out VM 指令构建器
|
||||||
|
* @param slotMap 寄存器到槽位映射
|
||||||
|
* @param retType 返回值类型前缀
|
||||||
|
*/
|
||||||
|
private void generateIndexInstruction(CallInstruction ins,
|
||||||
|
VMProgramBuilder out,
|
||||||
|
Map<IRVirtualRegister, Integer> slotMap,
|
||||||
|
char retType) {
|
||||||
|
String fn = ins.getFunctionName();
|
||||||
|
List<IRValue> args = ins.getArguments();
|
||||||
|
if (args.size() != 2) {
|
||||||
|
throw new IllegalStateException("[CallGenerator] " + fn + " 需要两个参数 (arr, idx),实际: " + args);
|
||||||
|
}
|
||||||
|
loadArgument(out, slotMap, args.get(0), 'R', fn); // 数组引用
|
||||||
|
loadArgument(out, slotMap, args.get(1), 'I', fn); // 索引
|
||||||
|
out.emit(VMOpCode.SYSCALL + " ARR_GET");
|
||||||
|
|
||||||
|
IRVirtualRegister dest = ins.getDest();
|
||||||
|
if (dest == null) {
|
||||||
|
throw new IllegalStateException("[CallGenerator] " + fn + " 必须有返回值寄存器");
|
||||||
|
}
|
||||||
|
Integer destSlot = slotMap.get(dest);
|
||||||
|
if (destSlot == null) {
|
||||||
|
throw new IllegalStateException("[CallGenerator] " + fn + " 未找到目标槽位");
|
||||||
|
}
|
||||||
|
// 根据类型选择 STORE 指令
|
||||||
|
switch (retType) {
|
||||||
|
case 'B' -> out.emit(OpHelper.opcode("B_STORE") + " " + destSlot);
|
||||||
|
case 'S' -> out.emit(OpHelper.opcode("S_STORE") + " " + destSlot);
|
||||||
|
case 'I' -> out.emit(OpHelper.opcode("I_STORE") + " " + destSlot);
|
||||||
|
case 'L' -> out.emit(OpHelper.opcode("L_STORE") + " " + destSlot);
|
||||||
|
case 'F' -> out.emit(OpHelper.opcode("F_STORE") + " " + destSlot);
|
||||||
|
case 'D' -> out.emit(OpHelper.opcode("D_STORE") + " " + destSlot);
|
||||||
|
default -> out.emit(OpHelper.opcode("R_STORE") + " " + destSlot);
|
||||||
|
}
|
||||||
|
out.setSlotType(destSlot, retType);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 syscall 子命令(第一个参数),支持字符串常量与已绑定字符串的虚拟寄存器。
|
* 生成系统调用(syscall)指令。
|
||||||
|
* 首个参数为子命令,支持常量或寄存器引用;其余参数均以引用形式加载。
|
||||||
|
* 若存在返回寄存器,则将结果存为整数类型。
|
||||||
*
|
*
|
||||||
* @param arg 子命令参数(应为字符串常量或寄存器)
|
* @param ins syscall 对应的 IR 调用指令
|
||||||
* @param fn 当前函数名(仅用于报错信息)
|
* @param out VM 指令构建器
|
||||||
* @return 子命令(大写字符串)
|
* @param slotMap 寄存器到槽位的映射
|
||||||
* @throws IllegalStateException 如果参数不是字符串常量或已绑定寄存器
|
* @param fn 函数名("syscall" 或以 ".syscall" 结尾)
|
||||||
|
*/
|
||||||
|
private void generateSyscall(CallInstruction ins,
|
||||||
|
VMProgramBuilder out,
|
||||||
|
Map<IRVirtualRegister, Integer> slotMap,
|
||||||
|
String fn) {
|
||||||
|
List<IRValue> args = ins.getArguments();
|
||||||
|
if (args.isEmpty()) {
|
||||||
|
throw new IllegalStateException("[CallGenerator] syscall 至少需要一个子命令");
|
||||||
|
}
|
||||||
|
String subcmd = resolveSyscallSubcmd(args.get(0), fn);
|
||||||
|
for (int i = 1; i < args.size(); i++) {
|
||||||
|
loadArgument(out, slotMap, args.get(i), 'R', fn);
|
||||||
|
}
|
||||||
|
out.emit(VMOpCode.SYSCALL + " " + subcmd);
|
||||||
|
|
||||||
|
IRVirtualRegister dest = ins.getDest();
|
||||||
|
if (dest != null) {
|
||||||
|
Integer slot = slotMap.get(dest);
|
||||||
|
if (slot == null) throw new IllegalStateException("[CallGenerator] syscall 未找到目标槽位");
|
||||||
|
out.emit(OpHelper.opcode("I_STORE") + " " + slot);
|
||||||
|
out.setSlotType(slot, 'I');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 syscall 子命令字符串:
|
||||||
|
* 若为 IRConstant,则直接取字符串值;
|
||||||
|
* 若为 IRVirtualRegister,则从常量池中获取。
|
||||||
|
* 最终返回大写子命令名称。
|
||||||
|
*
|
||||||
|
* @param arg 第一个参数,常量或虚拟寄存器
|
||||||
|
* @param fn 所属函数名,用于错误提示
|
||||||
|
* @return 大写的子命令字符串
|
||||||
|
* @throws IllegalStateException 参数类型或常量池缺失时抛出
|
||||||
*/
|
*/
|
||||||
private String resolveSyscallSubcmd(IRValue arg, String fn) {
|
private String resolveSyscallSubcmd(IRValue arg, String fn) {
|
||||||
switch (arg) {
|
if (arg instanceof IRConstant(Object value)) {
|
||||||
case IRConstant(String s) -> {
|
if (value instanceof String s) {
|
||||||
return s.toUpperCase(Locale.ROOT);
|
return s.toUpperCase(Locale.ROOT);
|
||||||
}
|
}
|
||||||
case IRConstant(Object value) -> throw new IllegalStateException(
|
throw new IllegalStateException("[CallGenerator] syscall 子命令必须是字符串 (函数: " + fn + ")");
|
||||||
"[CallGenerator] syscall 第一个参数必须是字符串常量 (function: %s, value: %s)"
|
|
||||||
.formatted(fn, value)
|
|
||||||
);
|
|
||||||
case IRVirtualRegister(int id) -> {
|
|
||||||
String s = STRING_CONST_POOL.get(id);
|
|
||||||
if (s == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"[CallGenerator] 未找到 syscall 字符串常量绑定 (function: %s, regId: %d)"
|
|
||||||
.formatted(fn, id)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return s.toUpperCase(Locale.ROOT);
|
|
||||||
}
|
|
||||||
case null, default -> throw new IllegalStateException(
|
|
||||||
"[CallGenerator] syscall 第一个参数必须是字符串常量或已绑定字符串的寄存器 (function: %s, arg: %s)"
|
|
||||||
.formatted(fn, arg)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
if (arg instanceof IRVirtualRegister(int id)) {
|
||||||
|
String s = STRING_CONST_POOL.get(id);
|
||||||
|
if (s == null) throw new IllegalStateException("[CallGenerator] 未注册的 syscall 字符串常量");
|
||||||
|
return s.toUpperCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("[CallGenerator] syscall 子命令参数错误: " + arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载一个参数到栈,支持指定默认类型。如果未设置类型则采用默认类型。
|
* 生成普通函数调用指令:
|
||||||
|
* 参数均以引用形式压栈,调用完成后,若返回类型非 void,
|
||||||
|
* 则选择合适的 STORE 指令保存结果。
|
||||||
*
|
*
|
||||||
* @param out VM 程序构建器
|
* @param ins 调用指令
|
||||||
* @param slotMap 寄存器到槽位的映射
|
* @param out 指令构建器
|
||||||
* @param arg 参数值(应为虚拟寄存器)
|
* @param slotMap 寄存器到槽位映射
|
||||||
* @param defaultType 默认类型
|
* @param fn 被调用函数名称
|
||||||
* @param fn 当前函数名(用于错误提示)
|
|
||||||
* @throws IllegalStateException 如果参数不是虚拟寄存器,或槽位未找到
|
|
||||||
*/
|
*/
|
||||||
private void loadArgument(VMProgramBuilder out, Map<IRVirtualRegister, Integer> slotMap, IRValue arg, char defaultType, String fn) {
|
private void generateNormalCall(CallInstruction ins,
|
||||||
|
VMProgramBuilder out,
|
||||||
|
Map<IRVirtualRegister, Integer> slotMap,
|
||||||
|
String fn) {
|
||||||
|
String retTypeName = GlobalFunctionTable.getReturnType(fn);
|
||||||
|
char retType = normalizeTypePrefix(retTypeName);
|
||||||
|
|
||||||
|
for (IRValue arg : ins.getArguments()) {
|
||||||
|
loadArgument(out, slotMap, arg, 'R', fn);
|
||||||
|
}
|
||||||
|
out.emitCall(fn, ins.getArguments().size());
|
||||||
|
|
||||||
|
if ("void".equals(retTypeName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
IRVirtualRegister dest = ins.getDest();
|
||||||
|
if (dest == null) {
|
||||||
|
throw new IllegalStateException("[CallGenerator] 普通调用缺少返回寄存器");
|
||||||
|
}
|
||||||
|
Integer slot = slotMap.get(dest);
|
||||||
|
if (slot == null) {
|
||||||
|
throw new IllegalStateException("[CallGenerator] 未找到返回槽位");
|
||||||
|
}
|
||||||
|
out.emit(OpHelper.opcode(retType + "_STORE") + " " + slot);
|
||||||
|
out.setSlotType(slot, retType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载参数:
|
||||||
|
* 验证为虚拟寄存器后,获取槽位和类型,
|
||||||
|
* 缺省时使用 defaultType,然后发出 LOAD 指令。
|
||||||
|
*
|
||||||
|
* @param out 指令构建器
|
||||||
|
* @param slotMap 寄存器到槽位映射
|
||||||
|
* @param arg IR 参数值
|
||||||
|
* @param defaultType 缺省类型前缀
|
||||||
|
* @param fn 所属函数名,用于错误提示
|
||||||
|
*/
|
||||||
|
private void loadArgument(VMProgramBuilder out,
|
||||||
|
Map<IRVirtualRegister, Integer> slotMap,
|
||||||
|
IRValue arg,
|
||||||
|
char defaultType,
|
||||||
|
String fn) {
|
||||||
|
this.fn = fn;
|
||||||
if (!(arg instanceof IRVirtualRegister vr)) {
|
if (!(arg instanceof IRVirtualRegister vr)) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException("[CallGenerator] 参数必须是 IRVirtualRegister");
|
||||||
"[CallGenerator] 参数必须为虚拟寄存器 (function: %s, arg: %s)".formatted(fn, arg));
|
|
||||||
}
|
}
|
||||||
Integer slot = slotMap.get(vr);
|
Integer slot = slotMap.get(vr);
|
||||||
if (slot == null) {
|
if (slot == null) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException("[CallGenerator] 未找到参数槽位");
|
||||||
"[CallGenerator] 未找到虚拟寄存器的槽位映射 (function: %s, reg: %s)".formatted(fn, vr));
|
|
||||||
}
|
}
|
||||||
char t = out.getSlotType(slot);
|
char t = out.getSlotType(slot);
|
||||||
if (t == '\0') t = defaultType;
|
if (t == '\0') t = defaultType;
|
||||||
@ -252,175 +311,11 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成一维/多维数组的下标访问指令(支持类型分派)。
|
* 返回最近一次处理的函数名,可用于调试。
|
||||||
* <p>
|
|
||||||
* 本方法用于将 IR 层的数组下标访问表达式(如 arr[idx]),生成对应的 VM 指令序列。
|
|
||||||
* 支持 byte/short/int/long/float/double/reference 等所有基础类型的数组元素访问。
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* <ul>
|
* @return 函数名字符串
|
||||||
* <li>1. 依次加载数组参数(arr)和下标参数(idx)到操作数栈</li>
|
|
||||||
* <li>2. 发出 ARR_GET 系统调用指令(SYSCALL ARR_GET),通过 VM 访问对应元素</li>
|
|
||||||
* <li>3. 根据元素声明类型,将结果写入目标槽位,支持类型分派(B/S/I/L/F/D/R)</li>
|
|
||||||
* <li>4. 若参数或返回寄存器缺失,则抛出异常提示</li>
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @param ins 下标访问对应的 IR 调用指令,函数名通常为 __index_x
|
|
||||||
* @param out VM 程序构建器,用于发出 VM 指令
|
|
||||||
* @param slotMap IR 虚拟寄存器到 VM 槽位的映射表
|
|
||||||
* @param retType 元素类型标识('B' byte, 'S' short, 'I' int, 'L' long, 'F' float, 'D' double, 'R' ref/obj)
|
|
||||||
* @throws IllegalStateException 参数个数不符、缺少目标寄存器、未找到槽位等情况
|
|
||||||
*/
|
*/
|
||||||
private void generateIndexInstruction(CallInstruction ins, VMProgramBuilder out, Map<IRVirtualRegister, Integer> slotMap, char retType) {
|
public String getFn() {
|
||||||
String fn = ins.getFunctionName();
|
return fn;
|
||||||
List<IRValue> args = ins.getArguments();
|
|
||||||
if (args.size() != 2) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"[CallGenerator] %s 需要两个参数(arr, idx),实际: %s".formatted(fn, args));
|
|
||||||
}
|
|
||||||
// 加载数组参数(寄存器类型按 R/ref 处理,默认对象槽位)
|
|
||||||
loadArgument(out, slotMap, args.get(0), 'R', fn);
|
|
||||||
// 加载下标参数(寄存器类型按 I/int 处理)
|
|
||||||
loadArgument(out, slotMap, args.get(1), 'I', fn);
|
|
||||||
|
|
||||||
// 发出 ARR_GET 系统调用(元素访问由 VM 完成类型分派)
|
|
||||||
out.emit(VMOpCode.SYSCALL + " " + "ARR_GET");
|
|
||||||
|
|
||||||
// 保存返回值到目标寄存器
|
|
||||||
IRVirtualRegister dest = ins.getDest();
|
|
||||||
if (dest == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"[CallGenerator] %s 需要有目标寄存器用于保存返回值".formatted(fn));
|
|
||||||
}
|
|
||||||
Integer destSlot = slotMap.get(dest);
|
|
||||||
if (destSlot == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"[CallGenerator] %s 未找到目标寄存器的槽位映射 (dest: %s)".formatted(fn, dest));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 按元素类型分派写入 VM 槽位
|
|
||||||
switch (retType) {
|
|
||||||
case 'B' -> {
|
|
||||||
out.emit(OpHelper.opcode("B_STORE") + " " + destSlot);
|
|
||||||
out.setSlotType(destSlot, 'B');
|
|
||||||
}
|
|
||||||
case 'S' -> {
|
|
||||||
out.emit(OpHelper.opcode("S_STORE") + " " + destSlot);
|
|
||||||
out.setSlotType(destSlot, 'S');
|
|
||||||
}
|
|
||||||
case 'I' -> {
|
|
||||||
out.emit(OpHelper.opcode("I_STORE") + " " + destSlot);
|
|
||||||
out.setSlotType(destSlot, 'I');
|
|
||||||
}
|
|
||||||
case 'L' -> {
|
|
||||||
out.emit(OpHelper.opcode("L_STORE") + " " + destSlot);
|
|
||||||
out.setSlotType(destSlot, 'L');
|
|
||||||
}
|
|
||||||
case 'F' -> {
|
|
||||||
out.emit(OpHelper.opcode("F_STORE") + " " + destSlot);
|
|
||||||
out.setSlotType(destSlot, 'F');
|
|
||||||
}
|
|
||||||
case 'D' -> {
|
|
||||||
out.emit(OpHelper.opcode("D_STORE") + " " + destSlot);
|
|
||||||
out.setSlotType(destSlot, 'D');
|
|
||||||
}
|
|
||||||
default -> {
|
|
||||||
out.emit(OpHelper.opcode("R_STORE") + " " + destSlot);
|
|
||||||
out.setSlotType(destSlot, 'R');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成 syscall 指令分支逻辑。
|
|
||||||
* <ol>
|
|
||||||
* <li>解析 syscall 子命令</li>
|
|
||||||
* <li>压栈剩余参数</li>
|
|
||||||
* <li>发出 SYSCALL 指令</li>
|
|
||||||
* <li>若有返回值则保存至目标槽位</li>
|
|
||||||
* </ol>
|
|
||||||
*
|
|
||||||
* @param ins 调用指令
|
|
||||||
* @param out VM 程序构建器
|
|
||||||
* @param slotMap 寄存器到槽位映射
|
|
||||||
* @param fn 当前函数名
|
|
||||||
*/
|
|
||||||
private void generateSyscall(CallInstruction ins, VMProgramBuilder out, Map<IRVirtualRegister, Integer> slotMap, String fn) {
|
|
||||||
List<IRValue> args = ins.getArguments();
|
|
||||||
if (args.isEmpty()) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"[CallGenerator] syscall 需要子命令参数 (function: %s)".formatted(fn));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0. 解析 syscall 子命令(第一个参数)
|
|
||||||
String subcmd = resolveSyscallSubcmd(args.getFirst(), fn);
|
|
||||||
|
|
||||||
// 1. 压栈其余 syscall 参数(从 index 1 开始)
|
|
||||||
for (int i = 1; i < args.size(); i++) {
|
|
||||||
loadArgument(out, slotMap, args.get(i), 'R', fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 生成 SYSCALL 指令
|
|
||||||
out.emit(VMOpCode.SYSCALL + " " + subcmd);
|
|
||||||
|
|
||||||
// 3. 有返回值则保存到目标槽位
|
|
||||||
IRVirtualRegister dest = ins.getDest();
|
|
||||||
if (dest != null) {
|
|
||||||
Integer destSlot = slotMap.get(dest);
|
|
||||||
if (destSlot == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"[CallGenerator] syscall 未找到目标寄存器的槽位映射 (function: %s, dest: %s)"
|
|
||||||
.formatted(fn, dest));
|
|
||||||
}
|
|
||||||
out.emit(OpHelper.opcode("I_STORE") + " " + destSlot);
|
|
||||||
out.setSlotType(destSlot, 'I');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成普通函数调用指令:
|
|
||||||
* <ol>
|
|
||||||
* <li>推断返回值类型</li>
|
|
||||||
* <li>压栈所有参数</li>
|
|
||||||
* <li>生成 CALL 指令</li>
|
|
||||||
* <li>保存返回值(若非 void)</li>
|
|
||||||
* </ol>
|
|
||||||
*
|
|
||||||
* @param ins 调用指令
|
|
||||||
* @param out VM 程序构建器
|
|
||||||
* @param slotMap 寄存器到槽位映射
|
|
||||||
* @param fn 当前函数名
|
|
||||||
*/
|
|
||||||
private void generateNormalCall(CallInstruction ins, VMProgramBuilder out, Map<IRVirtualRegister, Integer> slotMap, String fn) {
|
|
||||||
// 1. 推断返回值类型(首字母大写,缺省为 'I')
|
|
||||||
String retTypeName = GlobalFunctionTable.getReturnType(fn);
|
|
||||||
char retType = (retTypeName != null && !retTypeName.isEmpty()) ? Character.toUpperCase(retTypeName.charAt(0)) : 'I';
|
|
||||||
|
|
||||||
// 2. 压栈所有参数
|
|
||||||
for (IRValue arg : ins.getArguments()) {
|
|
||||||
loadArgument(out, slotMap, arg, 'R', fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 发出 CALL 指令
|
|
||||||
out.emitCall(fn, ins.getArguments().size());
|
|
||||||
|
|
||||||
// 3.5 void 返回直接结束
|
|
||||||
if ("void".equals(retTypeName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 保存返回值到目标寄存器
|
|
||||||
IRVirtualRegister dest = ins.getDest();
|
|
||||||
if (dest == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"[CallGenerator] 普通函数调用未找到目标寄存器 (function: %s)".formatted(fn));
|
|
||||||
}
|
|
||||||
Integer destSlot = slotMap.get(dest);
|
|
||||||
if (destSlot == null) {
|
|
||||||
throw new IllegalStateException(
|
|
||||||
"[CallGenerator] 普通函数调用未找到目标寄存器的槽位映射 (function: %s, dest: %s)".formatted(fn, dest));
|
|
||||||
}
|
|
||||||
out.emit(OpHelper.opcode(retType + "_STORE") + " " + destSlot);
|
|
||||||
out.setSlotType(destSlot, retType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user