feat: 支持数组下标访问类型分派
- 扩展 __index_i 函数支持 byte、short、int、long、float、double、boolean等类型 - 新增 __index_b、__index_s、__index_l、__index_f、__index_d、__index_r 函数- 优化数组元素访问的 IR 生成逻辑,根据类型选择合适的函数 - 更新 VM 层的 ARR_GET 子命令处理逻辑,支持多种数据类型
This commit is contained in:
parent
4a84f37b20
commit
b093f8db72
@ -23,7 +23,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>syscall: 支持字符串常量与寄存器到子命令的绑定与解析</li>
|
* <li>syscall: 支持字符串常量与寄存器到子命令的绑定与解析</li>
|
||||||
* <li>数组下标访问: 特殊的“__index_i”和“__index_r”内部调用</li>
|
* <li>数组下标访问: 支持所有主流基础类型 “__index_b/s/i/l/f/d/r”</li>
|
||||||
* <li>普通函数: 支持自动推断返回值类型与槽位类型</li>
|
* <li>普通函数: 支持自动推断返回值类型与槽位类型</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@ -77,17 +77,37 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 一维数组整型下标访问
|
// 各种一维数组类型(byte/short/int/long/float/double/boolean)
|
||||||
if ("__index_i".equals(fn)) {
|
switch (fn) {
|
||||||
generateIndexInstruction(ins, out, slotMap, true);
|
case "__index_b" -> {
|
||||||
|
generateIndexInstruction(ins, out, slotMap, 'B');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case "__index_s" -> {
|
||||||
// 多维数组返回引用的下标访问
|
generateIndexInstruction(ins, out, slotMap, 'S');
|
||||||
if ("__index_r".equals(fn)) {
|
|
||||||
generateIndexInstruction(ins, out, slotMap, false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case "__index_i" -> {
|
||||||
|
generateIndexInstruction(ins, out, slotMap, 'I');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case "__index_l" -> {
|
||||||
|
generateIndexInstruction(ins, out, slotMap, 'L');
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 普通函数调用
|
// 普通函数调用
|
||||||
generateNormalCall(ins, out, slotMap, fn);
|
generateNormalCall(ins, out, slotMap, fn);
|
||||||
@ -155,25 +175,38 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成一维/多维数组的下标访问指令。
|
* 生成一维/多维数组的下标访问指令(支持类型分派)。
|
||||||
|
* <p>
|
||||||
|
* 本方法用于将 IR 层的数组下标访问表达式(如 arr[idx]),生成对应的 VM 指令序列。
|
||||||
|
* 支持 byte/short/int/long/float/double/reference 等所有基础类型的数组元素访问。
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param ins 调用指令
|
* <ul>
|
||||||
* @param out VM 程序构建器
|
* <li>1. 依次加载数组参数(arr)和下标参数(idx)到操作数栈</li>
|
||||||
* @param slotMap 寄存器到槽位映射
|
* <li>2. 发出 ARR_GET 系统调用指令(SYSCALL ARR_GET),通过 VM 访问对应元素</li>
|
||||||
* @param isInt 是否是一维整型下标
|
* <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, boolean isInt) {
|
private void generateIndexInstruction(CallInstruction ins, VMProgramBuilder out, Map<IRVirtualRegister, Integer> slotMap, char retType) {
|
||||||
String fn = ins.getFunctionName();
|
String fn = ins.getFunctionName();
|
||||||
List<IRValue> args = ins.getArguments();
|
List<IRValue> args = ins.getArguments();
|
||||||
if (args.size() != 2) {
|
if (args.size() != 2) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"[CallGenerator] %s 需要两个参数(arr, idx),实际: %s".formatted(fn, args));
|
"[CallGenerator] %s 需要两个参数(arr, idx),实际: %s".formatted(fn, args));
|
||||||
}
|
}
|
||||||
// 加载数组参数
|
// 加载数组参数(寄存器类型按 R/ref 处理,默认对象槽位)
|
||||||
loadArgument(out, slotMap, args.get(0), 'R', fn);
|
loadArgument(out, slotMap, args.get(0), 'R', fn);
|
||||||
// 加载下标参数
|
// 加载下标参数(寄存器类型按 I/int 处理)
|
||||||
loadArgument(out, slotMap, args.get(1), 'I', fn);
|
loadArgument(out, slotMap, args.get(1), 'I', fn);
|
||||||
|
|
||||||
|
// 发出 ARR_GET 系统调用(元素访问由 VM 完成类型分派)
|
||||||
out.emit(VMOpCode.SYSCALL + " " + "ARR_GET");
|
out.emit(VMOpCode.SYSCALL + " " + "ARR_GET");
|
||||||
|
|
||||||
// 保存返回值到目标寄存器
|
// 保存返回值到目标寄存器
|
||||||
@ -187,14 +220,39 @@ public class CallGenerator implements InstructionGenerator<CallInstruction> {
|
|||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"[CallGenerator] %s 未找到目标寄存器的槽位映射 (dest: %s)".formatted(fn, dest));
|
"[CallGenerator] %s 未找到目标寄存器的槽位映射 (dest: %s)".formatted(fn, dest));
|
||||||
}
|
}
|
||||||
if (isInt) {
|
|
||||||
|
// 按元素类型分派写入 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.emit(OpHelper.opcode("I_STORE") + " " + destSlot);
|
||||||
out.setSlotType(destSlot, 'I');
|
out.setSlotType(destSlot, 'I');
|
||||||
} else {
|
}
|
||||||
|
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.emit(OpHelper.opcode("R_STORE") + " " + destSlot);
|
||||||
out.setSlotType(destSlot, 'R');
|
out.setSlotType(destSlot, 'R');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成 syscall 指令分支逻辑。
|
* 生成 syscall 指令分支逻辑。
|
||||||
|
|||||||
@ -137,7 +137,7 @@ public record ExpressionBuilder(IRContext ctx) {
|
|||||||
* <li>否则:
|
* <li>否则:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>若数组表达式本身是下一个下标的中间值(即多维数组链式下标),则先用 __index_r 获取“引用”;</li>
|
* <li>若数组表达式本身是下一个下标的中间值(即多维数组链式下标),则先用 __index_r 获取“引用”;</li>
|
||||||
* <li>最后一级用 __index_i 获取实际整型元素值。</li>
|
* <li>最后一级用 __index_b/s/i/l/f/d/r,按声明类型智能分派。</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* </li>
|
* </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
@ -182,8 +182,28 @@ public record ExpressionBuilder(IRContext ctx) {
|
|||||||
// 非最末层,下标取“引用”
|
// 非最末层,下标取“引用”
|
||||||
ctx.addInstruction(new CallInstruction(dest, "__index_r", argv));
|
ctx.addInstruction(new CallInstruction(dest, "__index_r", argv));
|
||||||
} else {
|
} else {
|
||||||
// 最末层,下标取实际元素值
|
// 最末层,下标取实际元素值,按声明类型分派
|
||||||
ctx.addInstruction(new CallInstruction(dest, "__index_i", argv));
|
String func = "__index_i"; // 默认整型
|
||||||
|
if (node.array() instanceof IdentifierNode id) {
|
||||||
|
String declType = ctx.getScope().lookupType(id.name()); // 如 "double[]"、"int[]"
|
||||||
|
if (declType != null) {
|
||||||
|
String base = declType.toLowerCase();
|
||||||
|
int p = base.indexOf('[');
|
||||||
|
if (p > 0) base = base.substring(0, p); // 基本类型
|
||||||
|
switch (base) {
|
||||||
|
case "byte" -> func = "__index_b";
|
||||||
|
case "short" -> func = "__index_s";
|
||||||
|
case "int" -> func = "__index_i";
|
||||||
|
case "long" -> func = "__index_l";
|
||||||
|
case "float" -> func = "__index_f";
|
||||||
|
case "double" -> func = "__index_d";
|
||||||
|
case "boolean" -> func = "__index_i"; // 布尔型用 int 通道返回 1/0
|
||||||
|
case "string" -> func = "__index_r"; // 字符串/其它未识别类型均走引用
|
||||||
|
default -> func = "__index_r";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.addInstruction(new CallInstruction(dest, func, argv));
|
||||||
}
|
}
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
|
|||||||
@ -46,6 +46,97 @@ import static java.nio.file.StandardOpenOption.*;
|
|||||||
*/
|
*/
|
||||||
public class SyscallCommand implements Command {
|
public class SyscallCommand implements Command {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据传入的文件打开标志,构造 NIO {@link OpenOption} 集合。
|
||||||
|
* <p>
|
||||||
|
* 本方法负责将底层虚拟机传递的 flags 整数型位域,转换为 Java NIO 标准的文件打开选项集合,
|
||||||
|
* 以支持文件读、写、创建、截断、追加等多种访问场景。
|
||||||
|
* 常用于 SYSCALL 的 OPEN 子命令。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param flags 文件打开模式标志。各标志可组合使用,具体含义请参见虚拟机文档。
|
||||||
|
* @return 转换后的 OpenOption 集合,可直接用于 FileChannel.open 等 NIO 方法
|
||||||
|
*/
|
||||||
|
private static Set<OpenOption> flagsToOptions(int flags) {
|
||||||
|
Set<OpenOption> opts = new HashSet<>();
|
||||||
|
// 如果有写入标志,则添加WRITE,否则默认为READ。
|
||||||
|
if ((flags & 0x1) != 0) opts.add(WRITE);
|
||||||
|
else opts.add(READ);
|
||||||
|
// 如果包含创建标志,允许创建文件。
|
||||||
|
if ((flags & 0x40) != 0) opts.add(CREATE);
|
||||||
|
// 包含截断标志,打开时清空内容。
|
||||||
|
if ((flags & 0x200) != 0) opts.add(TRUNCATE_EXISTING);
|
||||||
|
// 包含追加标志,文件写入时追加到末尾。
|
||||||
|
if ((flags & 0x400) != 0) opts.add(APPEND);
|
||||||
|
return opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 捕获所有异常并统一处理,操作数栈压入 -1 代表本次系统调用失败。
|
||||||
|
* <p>
|
||||||
|
* 本方法是全局错误屏障,任何命令异常都会转换为虚拟机通用的失败信号,
|
||||||
|
* 保证上层调用逻辑不会被异常打断。实际应用中可拓展错误码机制。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param stack 操作数栈,将失败信号写入此栈
|
||||||
|
* @param e 抛出的异常对象,可在调试时输出日志
|
||||||
|
*/
|
||||||
|
private static void pushErr(OperandStack stack, Exception e) {
|
||||||
|
stack.push(-1);
|
||||||
|
System.err.println("Syscall exception: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 控制台输出通用方法,支持基本类型、字节数组、任意数组、对象等。
|
||||||
|
* <p>
|
||||||
|
* 该方法用于 SYSCALL PRINT/PRINTLN,将任意类型对象转为易读字符串输出到标准输出流。
|
||||||
|
* 字节数组自动按 UTF-8 解码,其它原生数组按格式化字符串输出。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param obj 待输出的内容,可以为任何类型(如基本类型、byte[]、数组、对象等)
|
||||||
|
* @param newline 是否自动换行。如果为 true,则在输出后换行;否则直接输出。
|
||||||
|
*/
|
||||||
|
private static void output(Object obj, boolean newline) {
|
||||||
|
String str;
|
||||||
|
if (obj == null) {
|
||||||
|
str = "null";
|
||||||
|
} else if (obj instanceof byte[] bytes) {
|
||||||
|
// 字节数组作为文本输出
|
||||||
|
str = new String(bytes);
|
||||||
|
} else if (obj.getClass().isArray()) {
|
||||||
|
// 其它数组格式化输出
|
||||||
|
str = arrayToString(obj);
|
||||||
|
} else {
|
||||||
|
str = obj.toString();
|
||||||
|
}
|
||||||
|
if (newline) System.out.println(str);
|
||||||
|
else System.out.print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将各种原生数组和对象数组转换为可读字符串,便于控制台输出和调试。
|
||||||
|
* <p>
|
||||||
|
* 本方法针对 int、long、double、float、short、char、byte、boolean 等所有原生数组类型
|
||||||
|
* 以及对象数组都能正确格式化,统一输出格式风格,避免显示为类型 hashCode。
|
||||||
|
* 若为不支持的类型,返回通用提示字符串。
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param array 任意原生数组或对象数组
|
||||||
|
* @return 该数组的可读字符串表示
|
||||||
|
*/
|
||||||
|
private static String arrayToString(Object array) {
|
||||||
|
if (array instanceof int[] a) return Arrays.toString(a);
|
||||||
|
if (array instanceof long[] a) return Arrays.toString(a);
|
||||||
|
if (array instanceof double[] a) return Arrays.toString(a);
|
||||||
|
if (array instanceof float[] a) return Arrays.toString(a);
|
||||||
|
if (array instanceof short[] a) return Arrays.toString(a);
|
||||||
|
if (array instanceof char[] a) return Arrays.toString(a);
|
||||||
|
if (array instanceof byte[] a) return Arrays.toString(a);
|
||||||
|
if (array instanceof boolean[] a) return Arrays.toString(a);
|
||||||
|
if (array instanceof Object[] a) return Arrays.deepToString(a);
|
||||||
|
return "Unsupported array";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分发并执行 SYSCALL 子命令,根据子命令类型从操作数栈取出参数、操作底层资源,并将结果压回栈顶。
|
* 分发并执行 SYSCALL 子命令,根据子命令类型从操作数栈取出参数、操作底层资源,并将结果压回栈顶。
|
||||||
*
|
*
|
||||||
@ -226,8 +317,24 @@ public class SyscallCommand implements Command {
|
|||||||
sel.close();
|
sel.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 数组元素访问:arr[idx] -> 返回元素(当前实现返回 int 或字符串/引用原样)
|
// 数组元素访问:arr[idx] —— 保留所有类型精度(byte/short/int/long/float/double/boolean/string/ref)
|
||||||
case "ARR_GET" -> {
|
case "ARR_GET" -> {
|
||||||
|
/**
|
||||||
|
* 执行数组下标访问操作 arr[idx],并将对应元素以真实类型压入操作数栈。
|
||||||
|
* <ul>
|
||||||
|
* <li>支持 List 与任意原生数组类型(int[]、double[] 等);</li>
|
||||||
|
* <li>idx 参数支持 Number/String 类型,自动转 int;</li>
|
||||||
|
* <li>下标越界将抛出异常,非数组类型将报错;</li>
|
||||||
|
* <li>返回结果保持类型精度:byte/short/int/long/float/double/boolean/string/object;</li>
|
||||||
|
* <li>boolean 元素以 1/0 压栈,string/引用直接压栈;</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* 异常与出错行为:
|
||||||
|
* <ul>
|
||||||
|
* <li>索引类型非法、目标非数组/列表,将抛 IllegalArgumentException;</li>
|
||||||
|
* <li>索引越界,将抛 IndexOutOfBoundsException;</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
Object idxObj = stack.pop();
|
Object idxObj = stack.pop();
|
||||||
Object arrObj = stack.pop();
|
Object arrObj = stack.pop();
|
||||||
int idx;
|
int idx;
|
||||||
@ -249,16 +356,32 @@ public class SyscallCommand implements Command {
|
|||||||
throw new IllegalArgumentException("ARR_GET: not an array/list: " + arrObj);
|
throw new IllegalArgumentException("ARR_GET: not an array/list: " + arrObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === 按真实类型压栈(byte/short/int/long/float/double/boolean/string/ref)===
|
||||||
if (elem instanceof Number n) {
|
if (elem instanceof Number n) {
|
||||||
|
if (elem instanceof Double) {
|
||||||
|
stack.push(n.doubleValue());
|
||||||
|
} else if (elem instanceof Float) {
|
||||||
|
stack.push(n.floatValue());
|
||||||
|
} else if (elem instanceof Long) {
|
||||||
|
stack.push(n.longValue());
|
||||||
|
} else if (elem instanceof Integer) {
|
||||||
stack.push(n.intValue());
|
stack.push(n.intValue());
|
||||||
|
} else if (elem instanceof Short) {
|
||||||
|
stack.push(n.shortValue());
|
||||||
|
} else if (elem instanceof Byte) {
|
||||||
|
stack.push(n.byteValue());
|
||||||
|
} else {
|
||||||
|
stack.push(n.intValue()); // 兜底
|
||||||
|
}
|
||||||
} else if (elem instanceof Boolean b) {
|
} else if (elem instanceof Boolean b) {
|
||||||
stack.push(b ? 1 : 0);
|
stack.push(b ? 1 : 0);
|
||||||
} else {
|
} else {
|
||||||
// 对于字符串或其它引用类型,直接返回引用,由上层决定如何存储
|
// string 或其它引用类型,直接返回
|
||||||
stack.push(elem);
|
stack.push(elem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 控制台输出
|
// 控制台输出
|
||||||
case "PRINT" -> {
|
case "PRINT" -> {
|
||||||
Object dataObj = stack.pop();
|
Object dataObj = stack.pop();
|
||||||
@ -279,95 +402,4 @@ public class SyscallCommand implements Command {
|
|||||||
|
|
||||||
return pc + 1;
|
return pc + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据传入的文件打开标志,构造 NIO {@link OpenOption} 集合。
|
|
||||||
* <p>
|
|
||||||
* 本方法负责将底层虚拟机传递的 flags 整数型位域,转换为 Java NIO 标准的文件打开选项集合,
|
|
||||||
* 以支持文件读、写、创建、截断、追加等多种访问场景。
|
|
||||||
* 常用于 SYSCALL 的 OPEN 子命令。
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param flags 文件打开模式标志。各标志可组合使用,具体含义请参见虚拟机文档。
|
|
||||||
* @return 转换后的 OpenOption 集合,可直接用于 FileChannel.open 等 NIO 方法
|
|
||||||
*/
|
|
||||||
private static Set<OpenOption> flagsToOptions(int flags) {
|
|
||||||
Set<OpenOption> opts = new HashSet<>();
|
|
||||||
// 如果有写入标志,则添加WRITE,否则默认为READ。
|
|
||||||
if ((flags & 0x1) != 0) opts.add(WRITE);
|
|
||||||
else opts.add(READ);
|
|
||||||
// 如果包含创建标志,允许创建文件。
|
|
||||||
if ((flags & 0x40) != 0) opts.add(CREATE);
|
|
||||||
// 包含截断标志,打开时清空内容。
|
|
||||||
if ((flags & 0x200) != 0) opts.add(TRUNCATE_EXISTING);
|
|
||||||
// 包含追加标志,文件写入时追加到末尾。
|
|
||||||
if ((flags & 0x400) != 0) opts.add(APPEND);
|
|
||||||
return opts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 捕获所有异常并统一处理,操作数栈压入 -1 代表本次系统调用失败。
|
|
||||||
* <p>
|
|
||||||
* 本方法是全局错误屏障,任何命令异常都会转换为虚拟机通用的失败信号,
|
|
||||||
* 保证上层调用逻辑不会被异常打断。实际应用中可拓展错误码机制。
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param stack 操作数栈,将失败信号写入此栈
|
|
||||||
* @param e 抛出的异常对象,可在调试时输出日志
|
|
||||||
*/
|
|
||||||
private static void pushErr(OperandStack stack, Exception e) {
|
|
||||||
stack.push(-1);
|
|
||||||
System.err.println("Syscall exception: " + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 控制台输出通用方法,支持基本类型、字节数组、任意数组、对象等。
|
|
||||||
* <p>
|
|
||||||
* 该方法用于 SYSCALL PRINT/PRINTLN,将任意类型对象转为易读字符串输出到标准输出流。
|
|
||||||
* 字节数组自动按 UTF-8 解码,其它原生数组按格式化字符串输出。
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param obj 待输出的内容,可以为任何类型(如基本类型、byte[]、数组、对象等)
|
|
||||||
* @param newline 是否自动换行。如果为 true,则在输出后换行;否则直接输出。
|
|
||||||
*/
|
|
||||||
private static void output(Object obj, boolean newline) {
|
|
||||||
String str;
|
|
||||||
if (obj == null) {
|
|
||||||
str = "null";
|
|
||||||
} else if (obj instanceof byte[] bytes) {
|
|
||||||
// 字节数组作为文本输出
|
|
||||||
str = new String(bytes);
|
|
||||||
} else if (obj.getClass().isArray()) {
|
|
||||||
// 其它数组格式化输出
|
|
||||||
str = arrayToString(obj);
|
|
||||||
} else {
|
|
||||||
str = obj.toString();
|
|
||||||
}
|
|
||||||
if (newline) System.out.println(str);
|
|
||||||
else System.out.print(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将各种原生数组和对象数组转换为可读字符串,便于控制台输出和调试。
|
|
||||||
* <p>
|
|
||||||
* 本方法针对 int、long、double、float、short、char、byte、boolean 等所有原生数组类型
|
|
||||||
* 以及对象数组都能正确格式化,统一输出格式风格,避免显示为类型 hashCode。
|
|
||||||
* 若为不支持的类型,返回通用提示字符串。
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param array 任意原生数组或对象数组
|
|
||||||
* @return 该数组的可读字符串表示
|
|
||||||
*/
|
|
||||||
private static String arrayToString(Object array) {
|
|
||||||
if (array instanceof int[] a) return Arrays.toString(a);
|
|
||||||
if (array instanceof long[] a) return Arrays.toString(a);
|
|
||||||
if (array instanceof double[] a) return Arrays.toString(a);
|
|
||||||
if (array instanceof float[] a) return Arrays.toString(a);
|
|
||||||
if (array instanceof short[] a) return Arrays.toString(a);
|
|
||||||
if (array instanceof char[] a) return Arrays.toString(a);
|
|
||||||
if (array instanceof byte[] a) return Arrays.toString(a);
|
|
||||||
if (array instanceof boolean[] a) return Arrays.toString(a);
|
|
||||||
if (array instanceof Object[] a) return Arrays.deepToString(a);
|
|
||||||
return "Unsupported array";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user