diff --git a/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java b/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java index 098b97112..27e1de016 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java +++ b/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java @@ -25,7 +25,7 @@ public class BytecodeCompiler implements Visitor { // Pre-allocate with reasonable initial capacity to reduce resizing // Typical small eval/subroutine needs 20-50 bytecodes, 5-10 constants, 3-8 strings - final List bytecode = new ArrayList<>(64); + final List bytecode = new ArrayList<>(64); private final List constants = new ArrayList<>(16); private final List stringPool = new ArrayList<>(16); private final Map stringPoolIndex = new HashMap<>(16); // O(1) lookup @@ -1476,23 +1476,17 @@ void handlePushUnshift(BinaryOperatorNode node) { emitReg(arrayReg); emit(nameIdx); } - } else if (leftOp.operator.equals("@") && leftOp.operand instanceof OperatorNode) { - // Array dereference: @$arrayref - OperatorNode derefOp = (OperatorNode) leftOp.operand; - if (derefOp.operator.equals("$")) { - // Compile the scalar reference - derefOp.accept(this); - int refReg = lastResultReg; - - // Dereference to get the array - arrayReg = allocateRegister(); - emitWithToken(Opcodes.DEREF_ARRAY, node.getIndex()); - emitReg(arrayReg); - emitReg(refReg); - } else { - throwCompilerException("push/unshift requires array or array reference"); - return; - } + } else if (leftOp.operator.equals("@") && !(leftOp.operand instanceof IdentifierNode)) { + // Array dereference: @$arrayref or @{expr} + // Evaluate the operand expression to get the reference, then deref + leftOp.operand.accept(this); + int refReg = lastResultReg; + + // Dereference to get the array + arrayReg = allocateRegister(); + emitWithToken(Opcodes.DEREF_ARRAY, node.getIndex()); + emitReg(arrayReg); + emitReg(refReg); } else { throwCompilerException("push/unshift requires array or array reference"); return; @@ -1518,8 +1512,12 @@ void handlePushUnshift(BinaryOperatorNode node) { emitReg(arrayReg); emitReg(valuesReg); - // push/unshift return the new array size - lastResultReg = -1; // No result register needed + // push/unshift return the new array size in scalar context + int rd = allocateRegister(); + emit(Opcodes.ARRAY_SIZE); + emitReg(rd); + emitReg(arrayReg); + lastResultReg = rd; } @Override @@ -2651,6 +2649,32 @@ void compileVariableReference(OperatorNode node, String op) { } else { lastResultReg = hashReg; } + } else if (node.operand instanceof OperatorNode refOp) { + // %$ref or %{expr} — dereference scalar to hash + refOp.accept(this); + int scalarReg = lastResultReg; + int hashReg = allocateRegister(); + emitWithToken(Opcodes.DEREF_HASH, node.getIndex()); + emitReg(hashReg); + emitReg(scalarReg); + if (currentCallContext == RuntimeContextType.SCALAR) { + int rd = allocateRegister(); + emit(Opcodes.ARRAY_SIZE); + emitReg(rd); + emitReg(hashReg); + lastResultReg = rd; + } else { + lastResultReg = hashReg; + } + } else if (node.operand instanceof BlockNode blockNode) { + // %{ block } — evaluate block and dereference to hash + blockNode.accept(this); + int scalarReg = lastResultReg; + int hashReg = allocateRegister(); + emitWithToken(Opcodes.DEREF_HASH, node.getIndex()); + emitReg(hashReg); + emitReg(scalarReg); + lastResultReg = hashReg; } else { throwCompilerException("Unsupported % operand: " + node.operand.getClass().getSimpleName()); } @@ -2835,7 +2859,7 @@ private int addToConstantPool(Object obj) { } void emit(short opcode) { - bytecode.add(opcode); + bytecode.add((int) opcode); } /** @@ -2845,23 +2869,22 @@ void emit(short opcode) { void emitWithToken(short opcode, int tokenIndex) { int pc = bytecode.size(); pcToTokenIndex.put(pc, tokenIndex); - bytecode.add(opcode); + bytecode.add((int) opcode); } void emit(int value) { - bytecode.add((short)value); + bytecode.add(value); } void emitInt(int value) { - bytecode.add((short)(value >> 16)); // High 16 bits - bytecode.add((short)value); // Low 16 bits + bytecode.add(value); // Full int in one slot } /** * Emit a short value (register index, small immediate, etc.). */ private void emitShort(int value) { - bytecode.add((short)value); + bytecode.add(value); } /** @@ -2869,7 +2892,7 @@ private void emitShort(int value) { * Registers are now 16-bit (0-65535) instead of 8-bit (0-255). */ void emitReg(int register) { - bytecode.add((short)register); + bytecode.add(register); } /** @@ -2877,16 +2900,15 @@ void emitReg(int register) { * Used for forward jumps where the target is unknown at emit time. */ void patchIntOffset(int position, int target) { - // Store absolute target address (not relative offset) as 2 shorts - bytecode.set(position, (short)((target >> 16) & 0xFFFF)); // High 16 bits - bytecode.set(position + 1, (short)(target & 0xFFFF)); // Low 16 bits + // Store absolute target address in one slot + bytecode.set(position, target); } /** * Helper for forward jumps - emit placeholder and return position for later patching. */ private void emitJumpPlaceholder() { - emitInt(0); // 2 shorts (4 bytes) placeholder + emitInt(0); // 1 int slot placeholder } private void patchJump(int placeholderPos, int target) { @@ -2898,14 +2920,14 @@ private void patchJump(int placeholderPos, int target) { * Used for forward jumps where the target is unknown at emit time. */ private void patchShortOffset(int position, int target) { - bytecode.set(position, (short)target); + bytecode.set(position, target); } /** - * Convert List bytecode to short[] array. + * Convert List bytecode to int[] array. */ - private short[] toShortArray() { - short[] result = new short[bytecode.size()]; + private int[] toShortArray() { + int[] result = new int[bytecode.size()]; for (int i = 0; i < bytecode.size(); i++) { result[i] = bytecode.get(i); } @@ -3880,7 +3902,7 @@ int getSourceLine() { * Get the bytecode list for position tracking. * Used by refactored compiler classes for jump patching. */ - List getBytecode() { + List getBytecode() { return bytecode; } diff --git a/src/main/java/org/perlonjava/backend/bytecode/BytecodeInterpreter.java b/src/main/java/org/perlonjava/backend/bytecode/BytecodeInterpreter.java index d169ef0a3..954e406f7 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/BytecodeInterpreter.java +++ b/src/main/java/org/perlonjava/backend/bytecode/BytecodeInterpreter.java @@ -62,7 +62,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c } int pc = 0; // Program counter - short[] bytecode = code.bytecode; + final int[] bytecode = code.bytecode; // Eval block exception handling: stack of catch PCs // When EVAL_TRY is executed, push the catch PC onto this stack @@ -72,7 +72,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c try { // Main dispatch loop - JVM JIT optimizes switch to tableswitch (O(1) jump) while (pc < bytecode.length) { - short opcode = bytecode[pc++]; + int opcode = bytecode[pc++]; switch (opcode) { // ================================================================= @@ -115,7 +115,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c // Conditional jump: if (!rs) pc = offset int condReg = bytecode[pc++]; int target = readInt(bytecode, pc); - pc += 2; + pc += 1; // Convert to scalar if needed for boolean test RuntimeBase condBase = registers[condReg]; @@ -133,7 +133,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c // Conditional jump: if (rs) pc = offset int condReg = bytecode[pc++]; int target = readInt(bytecode, pc); - pc += 2; + pc += 1; // Convert to scalar if needed for boolean test RuntimeBase condBase = registers[condReg]; @@ -171,7 +171,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c // Load integer: rd = immediate (create NEW mutable scalar, not cached) int rd = bytecode[pc++]; int value = readInt(bytecode, pc); - pc += 2; + pc += 1; // Create NEW RuntimeScalar (mutable) instead of using cache // This is needed for local variables that may be modified (++/--) registers[rd] = new RuntimeScalar(value); @@ -254,7 +254,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c int iterReg = bytecode[pc++]; int nameIdx = bytecode[pc++]; int bodyTarget = readInt(bytecode, pc); - pc += 2; + pc += 1; String name = code.stringPool[nameIdx]; RuntimeScalar iterScalar = (RuntimeScalar) registers[iterReg]; @@ -490,7 +490,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c int rd = bytecode[pc++]; int rs = bytecode[pc++]; int immediate = readInt(bytecode, pc); - pc += 2; + pc += 1; // Calls specialized unboxed method (rare optimization) registers[rd] = MathOperators.add( (RuntimeScalar) registers[rs], @@ -600,7 +600,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c int rd = bytecode[pc++]; int iterReg = bytecode[pc++]; int bodyTarget = readInt(bytecode, pc); // Absolute target address - pc += 2; // Skip the int we just read + pc += 1; // Skip the int we just read RuntimeScalar iterScalar = (RuntimeScalar) registers[iterReg]; @SuppressWarnings("unchecked") @@ -1087,7 +1087,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c // Add immediate and assign: rd += imm (modifies rd in place) int rd = bytecode[pc++]; int immediate = readInt(bytecode, pc); - pc += 2; + pc += 1; RuntimeScalar result = MathOperators.add((RuntimeScalar) registers[rd], immediate); ((RuntimeScalar) registers[rd]).set(result); break; @@ -1417,7 +1417,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c // catch_target is absolute bytecode address (4 bytes) int catchPc = readInt(bytecode, pc); // Read 4-byte absolute address - pc += 2; // Skip the 2 shorts we just read + pc += 1; // Skip the 2 shorts we just read // Push catch PC onto eval stack evalCatchStack.push(catchPc); @@ -1651,7 +1651,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c int listReg = bytecode[pc++]; int closureReg = bytecode[pc++]; int packageIdx = readInt(bytecode, pc); - pc += 2; + pc += 1; RuntimeBase listBase = registers[listReg]; RuntimeList list = listBase.getList(); @@ -1997,13 +1997,50 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c case Opcodes.CALLER: case Opcodes.EACH: case Opcodes.PACK: + case Opcodes.UNPACK: case Opcodes.VEC: case Opcodes.LOCALTIME: case Opcodes.GMTIME: case Opcodes.CRYPT: + case Opcodes.CLOSE: + case Opcodes.BINMODE: + case Opcodes.SEEK: + case Opcodes.EOF_OP: + case Opcodes.SYSREAD: + case Opcodes.SYSWRITE: + case Opcodes.SYSOPEN: + case Opcodes.SOCKET: + case Opcodes.BIND: + case Opcodes.CONNECT: + case Opcodes.LISTEN: + case Opcodes.WRITE: + case Opcodes.FORMLINE: + case Opcodes.PRINTF: + case Opcodes.ACCEPT: + case Opcodes.SYSSEEK: + case Opcodes.TRUNCATE: + case Opcodes.READ: pc = MiscOpcodeHandler.execute(opcode, bytecode, pc, registers); break; + case Opcodes.SET_PACKAGE: { + // Non-scoped package declaration: package Foo; + // Update the runtime current-package tracker so caller() returns the right package. + int nameIdx = bytecode[pc++]; + InterpreterState.currentPackage.get().set(code.stringPool[nameIdx]); + break; + } + + case Opcodes.PUSH_PACKAGE: { + // Scoped package block entry: package Foo { ... + // Save current package via DynamicVariableManager so it is restored + // automatically when the scope exits via POP_LOCAL_LEVEL. + int nameIdx = bytecode[pc++]; + DynamicVariableManager.pushLocalVariable(InterpreterState.currentPackage.get()); + InterpreterState.currentPackage.get().set(code.stringPool[nameIdx]); + break; + } + default: // Unknown opcode int opcodeInt = opcode & 0xFF; @@ -2090,7 +2127,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c * * @return Updated program counter */ - private static int executeTypeOps(short opcode, short[] bytecode, int pc, + private static int executeTypeOps(int opcode, int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { switch (opcode) { case Opcodes.CREATE_LAST: { @@ -2251,7 +2288,7 @@ private static int executeTypeOps(short opcode, short[] bytecode, int pc, int rd = bytecode[pc++]; int rs = bytecode[pc++]; int packageIdx = readInt(bytecode, pc); - pc += 2; // readInt reads 2 shorts + pc += 1; // readInt reads 2 shorts RuntimeScalar codeRef = (RuntimeScalar) registers[rs]; String packageName = code.stringPool[packageIdx]; registers[rd] = RuntimeCode.prototype(codeRef, packageName); @@ -2286,7 +2323,7 @@ private static int executeTypeOps(short opcode, short[] bytecode, int pc, * * @return Updated program counter */ - private static int executeCollections(short opcode, short[] bytecode, int pc, + private static int executeCollections(int opcode, int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { switch (opcode) { case Opcodes.ARRAY_SET: { @@ -2460,7 +2497,7 @@ private static int executeCollections(short opcode, short[] bytecode, int pc, * * @return Updated program counter */ - private static int executeArithmetic(short opcode, short[] bytecode, int pc, + private static int executeArithmetic(int opcode, int[] bytecode, int pc, RuntimeBase[] registers) { switch (opcode) { case Opcodes.MUL_SCALAR: { @@ -2522,7 +2559,7 @@ private static int executeArithmetic(short opcode, short[] bytecode, int pc, int rd = bytecode[pc++]; int rs = bytecode[pc++]; int immediate = readInt(bytecode, pc); - pc += 2; + pc += 1; registers[rd] = MathOperators.add( (RuntimeScalar) registers[rs], immediate @@ -2737,7 +2774,7 @@ private static int executeArithmetic(short opcode, short[] bytecode, int pc, * * @return Updated program counter */ - private static int executeComparisons(short opcode, short[] bytecode, int pc, + private static int executeComparisons(int opcode, int[] bytecode, int pc, RuntimeBase[] registers) { switch (opcode) { case Opcodes.COMPARE_NUM: { @@ -2920,7 +2957,7 @@ private static int executeComparisons(short opcode, short[] bytecode, int pc, * Handles: DEREF_ARRAY, DEREF_HASH, *_SLICE, *_SLICE_SET, *_SLICE_DELETE, LIST_SLICE_FROM * Direct dispatch to SlowOpcodeHandler methods (Phase 2 complete). */ - private static int executeSliceOps(short opcode, short[] bytecode, int pc, + private static int executeSliceOps(int opcode, int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { // Direct method calls - no SLOWOP_* constants needed! switch (opcode) { @@ -2949,7 +2986,7 @@ private static int executeSliceOps(short opcode, short[] bytecode, int pc, * Execute array/string operations (opcodes 122-127). * Handles: SPLICE, REVERSE, SPLIT, LENGTH_OP, EXISTS, DELETE */ - private static int executeArrayStringOps(short opcode, short[] bytecode, int pc, + private static int executeArrayStringOps(int opcode, int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { switch (opcode) { case Opcodes.SPLICE: @@ -2973,7 +3010,7 @@ private static int executeArrayStringOps(short opcode, short[] bytecode, int pc, * Execute closure/scope operations (opcodes 128-131). * Handles: RETRIEVE_BEGIN_*, LOCAL_SCALAR */ - private static int executeScopeOps(short opcode, short[] bytecode, int pc, + private static int executeScopeOps(int opcode, int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { switch (opcode) { case Opcodes.RETRIEVE_BEGIN_SCALAR: @@ -2994,7 +3031,7 @@ private static int executeScopeOps(short opcode, short[] bytecode, int pc, * Handles: CHOWN, WAITPID, FORK, GETPPID, *PGRP, *PRIORITY, *SOCKOPT, * SYSCALL, SEMGET, SEMOP, MSGGET, MSGSND, MSGRCV, SHMGET, SHMREAD, SHMWRITE */ - private static int executeSystemOps(short opcode, short[] bytecode, int pc, + private static int executeSystemOps(int opcode, int[] bytecode, int pc, RuntimeBase[] registers) { switch (opcode) { case Opcodes.CHOWN: @@ -3044,7 +3081,7 @@ private static int executeSystemOps(short opcode, short[] bytecode, int pc, * Execute special I/O operations (opcodes 151-154). * Handles: EVAL_STRING, SELECT_OP, LOAD_GLOB, SLEEP_OP */ - private static int executeSpecialIO(short opcode, short[] bytecode, int pc, + private static int executeSpecialIO(int opcode, int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { switch (opcode) { case Opcodes.EVAL_STRING: @@ -3061,13 +3098,11 @@ private static int executeSpecialIO(short opcode, short[] bytecode, int pc, } /** - * Read a 32-bit integer from bytecode (stored as 2 shorts: high 16 bits, low 16 bits). - * Uses unsigned short values to reconstruct the full 32-bit integer. + * Read a 32-bit integer from bytecode (stored as 1 int slot). + * With int[] storage a full int fits in a single slot. */ - private static int readInt(short[] bytecode, int pc) { - int high = bytecode[pc] & 0xFFFF; // Keep mask here - need full 32-bit range - int low = bytecode[pc + 1] & 0xFFFF; // Keep mask here - need full 32-bit range - return (high << 16) | low; + private static int readInt(int[] bytecode, int pc) { + return bytecode[pc]; } /** diff --git a/src/main/java/org/perlonjava/backend/bytecode/CompileAssignment.java b/src/main/java/org/perlonjava/backend/bytecode/CompileAssignment.java index 360bdc478..3ee669681 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/CompileAssignment.java +++ b/src/main/java/org/perlonjava/backend/bytecode/CompileAssignment.java @@ -1203,28 +1203,34 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, bytecodeCompiler.currentCallContext = savedContext; return; } else if (hashOp.operator.equals("$")) { - // $hash{key} - dereference to get hash - if (!(hashOp.operand instanceof IdentifierNode)) { - bytecodeCompiler.throwCompilerException("Hash assignment requires identifier"); - return; - } - String varName = ((IdentifierNode) hashOp.operand).name; - String hashVarName = "%" + varName; - - if (bytecodeCompiler.hasVariable(hashVarName)) { - // Lexical hash - hashReg = bytecodeCompiler.getVariableRegister(hashVarName); + // $hash{key} or $$ref{key} - dereference to get hash + if (hashOp.operand instanceof IdentifierNode) { + String varName = ((IdentifierNode) hashOp.operand).name; + String hashVarName = "%" + varName; + + if (bytecodeCompiler.hasVariable(hashVarName)) { + // Lexical hash + hashReg = bytecodeCompiler.getVariableRegister(hashVarName); + } else { + // Global hash - load it + hashReg = bytecodeCompiler.allocateRegister(); + String globalHashName = NameNormalizer.normalizeVariableName( + varName, + bytecodeCompiler.getCurrentPackage() + ); + int nameIdx = bytecodeCompiler.addToStringPool(globalHashName); + bytecodeCompiler.emit(Opcodes.LOAD_GLOBAL_HASH); + bytecodeCompiler.emitReg(hashReg); + bytecodeCompiler.emit(nameIdx); + } } else { - // Global hash - load it + // $$ref{key} = value — compile the scalar ref expression and deref to hash + hashOp.operand.accept(bytecodeCompiler); + int scalarReg = bytecodeCompiler.lastResultReg; hashReg = bytecodeCompiler.allocateRegister(); - String globalHashName = NameNormalizer.normalizeVariableName( - varName, - bytecodeCompiler.getCurrentPackage() - ); - int nameIdx = bytecodeCompiler.addToStringPool(globalHashName); - bytecodeCompiler.emit(Opcodes.LOAD_GLOBAL_HASH); + bytecodeCompiler.emitWithToken(Opcodes.DEREF_HASH, node.getIndex()); bytecodeCompiler.emitReg(hashReg); - bytecodeCompiler.emit(nameIdx); + bytecodeCompiler.emitReg(scalarReg); } } else { bytecodeCompiler.throwCompilerException("Hash assignment requires scalar dereference: $var{key}"); @@ -1290,6 +1296,83 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler, return; } + // Handle arrow dereference assignment: $ref->{key} = value or $$ref{key} = value + // These parse as BinaryOperatorNode("->", expr, HashLiteralNode/ArrayLiteralNode) + if (leftBin.operator.equals("->")) { + Node rightSide = leftBin.right; + if (rightSide instanceof HashLiteralNode hashKey) { + // $ref->{key} = value — hash element via reference + leftBin.left.accept(bytecodeCompiler); + int refReg = bytecodeCompiler.lastResultReg; + + // Dereference to get the hash + int hashReg = bytecodeCompiler.allocateRegister(); + bytecodeCompiler.emitWithToken(Opcodes.DEREF_HASH, node.getIndex()); + bytecodeCompiler.emitReg(hashReg); + bytecodeCompiler.emitReg(refReg); + + // Compile key + int keyReg; + if (!hashKey.elements.isEmpty()) { + Node keyElement = hashKey.elements.get(0); + if (keyElement instanceof IdentifierNode) { + String keyString = ((IdentifierNode) keyElement).name; + keyReg = bytecodeCompiler.allocateRegister(); + int keyIdx = bytecodeCompiler.addToStringPool(keyString); + bytecodeCompiler.emit(Opcodes.LOAD_STRING); + bytecodeCompiler.emitReg(keyReg); + bytecodeCompiler.emit(keyIdx); + } else { + keyElement.accept(bytecodeCompiler); + keyReg = bytecodeCompiler.lastResultReg; + } + } else { + bytecodeCompiler.throwCompilerException("Hash key required for arrow assignment"); + return; + } + + // Compile RHS and emit HASH_SET + node.right.accept(bytecodeCompiler); + int valReg = bytecodeCompiler.lastResultReg; + bytecodeCompiler.emit(Opcodes.HASH_SET); + bytecodeCompiler.emitReg(hashReg); + bytecodeCompiler.emitReg(keyReg); + bytecodeCompiler.emitReg(valReg); + bytecodeCompiler.lastResultReg = valReg; + bytecodeCompiler.currentCallContext = savedContext; + return; + } else if (rightSide instanceof ArrayLiteralNode arrayIdx) { + // $ref->[index] = value — array element via reference + leftBin.left.accept(bytecodeCompiler); + int refReg = bytecodeCompiler.lastResultReg; + + // Dereference to get the array + int arrayReg = bytecodeCompiler.allocateRegister(); + bytecodeCompiler.emitWithToken(Opcodes.DEREF_ARRAY, node.getIndex()); + bytecodeCompiler.emitReg(arrayReg); + bytecodeCompiler.emitReg(refReg); + + // Compile index + if (arrayIdx.elements.isEmpty()) { + bytecodeCompiler.throwCompilerException("Array index required for arrow assignment"); + return; + } + arrayIdx.elements.get(0).accept(bytecodeCompiler); + int idxReg = bytecodeCompiler.lastResultReg; + + // Compile RHS and emit ARRAY_SET + node.right.accept(bytecodeCompiler); + int valReg = bytecodeCompiler.lastResultReg; + bytecodeCompiler.emit(Opcodes.ARRAY_SET); + bytecodeCompiler.emitReg(arrayReg); + bytecodeCompiler.emitReg(idxReg); + bytecodeCompiler.emitReg(valReg); + bytecodeCompiler.lastResultReg = valReg; + bytecodeCompiler.currentCallContext = savedContext; + return; + } + } + // Handle lvalue subroutine: f() = value // When a function is called in lvalue context, it returns a RuntimeBaseProxy // that wraps a mutable reference. We can assign to it using SET_SCALAR. diff --git a/src/main/java/org/perlonjava/backend/bytecode/CompileOperator.java b/src/main/java/org/perlonjava/backend/bytecode/CompileOperator.java index 4f2a84a88..8db1e2a77 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/CompileOperator.java +++ b/src/main/java/org/perlonjava/backend/bytecode/CompileOperator.java @@ -75,8 +75,7 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode .set(new RuntimeScalar(version)); } - // Update the current package/class in symbol table - // This tracks package name, isClass flag, and version + // Update the current package/class in symbol table (compile-time tracking) bytecodeCompiler.symbolTable.setCurrentPackage(packageName, isClass); // Register as Perl 5.38+ class for proper stringification if needed @@ -84,6 +83,19 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode ClassRegistry.registerClass(packageName); } + // Emit runtime package tracking opcode so caller() and eval STRING work. + // Scoped blocks (package Foo { }) use PUSH_PACKAGE so DynamicVariableManager + // can restore the previous package when the scope exits. + // Non-scoped (package Foo;) use SET_PACKAGE which just overwrites. + boolean isScoped = Boolean.TRUE.equals(node.getAnnotation("isScoped")); + int nameIdx = bytecodeCompiler.addToStringPool(packageName); + if (isScoped) { + bytecodeCompiler.emit(Opcodes.PUSH_PACKAGE); + } else { + bytecodeCompiler.emit(Opcodes.SET_PACKAGE); + } + bytecodeCompiler.emit(nameIdx); + bytecodeCompiler.lastResultReg = -1; // No runtime value } else { bytecodeCompiler.throwCompilerException(op + " operator requires an identifier"); @@ -894,19 +906,24 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode bytecodeCompiler.lastResultReg = rd; } else if (op.equals("pop")) { // Array pop: $x = pop @array or $x = pop @$ref - // operand: ListNode containing OperatorNode("@", IdentifierNode or OperatorNode) - if (node.operand == null || !(node.operand instanceof ListNode)) { + // operand: OperatorNode("@", ...) directly (default @_/@ARGV injected by parser) + // or ListNode containing OperatorNode("@", IdentifierNode or OperatorNode) + if (node.operand == null) { bytecodeCompiler.throwCompilerException("pop requires array argument"); } - ListNode list = (ListNode) node.operand; - if (list.elements.isEmpty() || !(list.elements.get(0) instanceof OperatorNode)) { - bytecodeCompiler.throwCompilerException("pop requires array variable"); - } - - OperatorNode arrayOp = (OperatorNode) list.elements.get(0); - if (!arrayOp.operator.equals("@")) { + OperatorNode arrayOp; + if (node.operand instanceof OperatorNode directOp && directOp.operator.equals("@")) { + // Direct OperatorNode("@", ...) - default array case + arrayOp = directOp; + } else if (node.operand instanceof ListNode list && !list.elements.isEmpty() + && list.elements.get(0) instanceof OperatorNode listOp + && listOp.operator.equals("@")) { + // ListNode-wrapped OperatorNode("@", ...) - explicit array case + arrayOp = listOp; + } else { bytecodeCompiler.throwCompilerException("pop requires array variable: pop @array"); + return; } int arrayReg = -1; // Will be assigned in if/else blocks @@ -953,19 +970,24 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode bytecodeCompiler.lastResultReg = rd; } else if (op.equals("shift")) { // Array shift: $x = shift @array or $x = shift @$ref - // operand: ListNode containing OperatorNode("@", IdentifierNode or OperatorNode) - if (node.operand == null || !(node.operand instanceof ListNode)) { + // operand: OperatorNode("@", ...) directly (default @_/@ARGV injected by parser) + // or ListNode containing OperatorNode("@", IdentifierNode or OperatorNode) + if (node.operand == null) { bytecodeCompiler.throwCompilerException("shift requires array argument"); } - ListNode list = (ListNode) node.operand; - if (list.elements.isEmpty() || !(list.elements.get(0) instanceof OperatorNode)) { - bytecodeCompiler.throwCompilerException("shift requires array variable"); - } - - OperatorNode arrayOp = (OperatorNode) list.elements.get(0); - if (!arrayOp.operator.equals("@")) { + OperatorNode arrayOp; + if (node.operand instanceof OperatorNode directOp && directOp.operator.equals("@")) { + // Direct OperatorNode("@", ...) - default array case + arrayOp = directOp; + } else if (node.operand instanceof ListNode list && !list.elements.isEmpty() + && list.elements.get(0) instanceof OperatorNode listOp + && listOp.operator.equals("@")) { + // ListNode-wrapped OperatorNode("@", ...) - explicit array case + arrayOp = listOp; + } else { bytecodeCompiler.throwCompilerException("shift requires array variable: shift @array"); + return; } int arrayReg = -1; // Will be assigned in if/else blocks @@ -2698,9 +2720,16 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode } else if (op.equals("chmod") || op.equals("unlink") || op.equals("utime") || op.equals("rename") || op.equals("link") || op.equals("readlink") || op.equals("umask") || op.equals("system") || op.equals("pack") || - op.equals("vec") || op.equals("crypt") || op.equals("localtime") || - op.equals("gmtime") || op.equals("caller") || op.equals("fileno") || - op.equals("getc") || op.equals("qx")) { + op.equals("unpack") || op.equals("vec") || op.equals("crypt") || + op.equals("localtime") || op.equals("gmtime") || op.equals("caller") || + op.equals("fileno") || op.equals("getc") || op.equals("qx") || + op.equals("close") || + op.equals("binmode") || op.equals("seek") || + op.equals("eof") || op.equals("sysread") || op.equals("syswrite") || + op.equals("sysopen") || op.equals("socket") || op.equals("bind") || + op.equals("connect") || op.equals("listen") || op.equals("write") || + op.equals("formline") || op.equals("printf") || op.equals("accept") || + op.equals("sysseek") || op.equals("truncate") || op.equals("read")) { // Generic handler for operators that take arguments and call runtime methods // Format: OPCODE rd argsReg ctx // argsReg must be a RuntimeList @@ -2743,10 +2772,29 @@ public static void visitOperator(BytecodeCompiler bytecodeCompiler, OperatorNode case "caller" -> Opcodes.CALLER; case "each" -> Opcodes.EACH; case "pack" -> Opcodes.PACK; + case "unpack" -> Opcodes.UNPACK; case "vec" -> Opcodes.VEC; case "localtime" -> Opcodes.LOCALTIME; case "gmtime" -> Opcodes.GMTIME; case "crypt" -> Opcodes.CRYPT; + case "close" -> Opcodes.CLOSE; + case "binmode" -> Opcodes.BINMODE; + case "seek" -> Opcodes.SEEK; + case "eof" -> Opcodes.EOF_OP; + case "sysread" -> Opcodes.SYSREAD; + case "syswrite" -> Opcodes.SYSWRITE; + case "sysopen" -> Opcodes.SYSOPEN; + case "socket" -> Opcodes.SOCKET; + case "bind" -> Opcodes.BIND; + case "connect" -> Opcodes.CONNECT; + case "listen" -> Opcodes.LISTEN; + case "write" -> Opcodes.WRITE; + case "formline" -> Opcodes.FORMLINE; + case "printf" -> Opcodes.PRINTF; + case "accept" -> Opcodes.ACCEPT; + case "sysseek" -> Opcodes.SYSSEEK; + case "truncate" -> Opcodes.TRUNCATE; + case "read" -> Opcodes.READ; default -> throw new IllegalStateException("Unexpected operator: " + op); }; diff --git a/src/main/java/org/perlonjava/backend/bytecode/EvalStringHandler.java b/src/main/java/org/perlonjava/backend/bytecode/EvalStringHandler.java index ad85c2c85..b3700b7d7 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/EvalStringHandler.java +++ b/src/main/java/org/perlonjava/backend/bytecode/EvalStringHandler.java @@ -76,6 +76,12 @@ public static RuntimeScalar evalString(String perlCode, symbolTable.warningFlagsStack.push((java.util.BitSet) currentCode.warningFlags.clone()); } + // Inherit the runtime current package so eval STRING compiles in the right package. + // InterpreterState.currentPackage is updated by SET_PACKAGE/PUSH_PACKAGE opcodes + // as "package Foo;" declarations execute at runtime. + String runtimePackage = InterpreterState.currentPackage.get().toString(); + symbolTable.setCurrentPackage(runtimePackage, false); + ErrorMessageUtil errorUtil = new ErrorMessageUtil(sourceName, tokens); EmitterContext ctx = new EmitterContext( new JavaClassInfo(), diff --git a/src/main/java/org/perlonjava/backend/bytecode/InterpretedCode.java b/src/main/java/org/perlonjava/backend/bytecode/InterpretedCode.java index d14d144d2..769d812f8 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/InterpretedCode.java +++ b/src/main/java/org/perlonjava/backend/bytecode/InterpretedCode.java @@ -22,7 +22,7 @@ */ public class InterpretedCode extends RuntimeCode { // Bytecode and metadata - public final short[] bytecode; // Instruction stream (opcodes + operands as shorts) + public final int[] bytecode; // Instruction stream (opcodes + operands as ints) public final Object[] constants; // Constant pool (RuntimeBase objects) public final String[] stringPool; // String constants (variable names, etc.) public final int maxRegisters; // Number of registers needed @@ -57,7 +57,7 @@ public class InterpretedCode extends RuntimeCode { * @param featureFlags Feature flags at compile time (for eval STRING inheritance) * @param warningFlags Warning flags at compile time (for eval STRING inheritance) */ - public InterpretedCode(short[] bytecode, Object[] constants, String[] stringPool, + public InterpretedCode(int[] bytecode, Object[] constants, String[] stringPool, int maxRegisters, RuntimeBase[] capturedVars, String sourceName, int sourceLine, TreeMap pcToTokenIndex, @@ -81,7 +81,7 @@ public InterpretedCode(short[] bytecode, Object[] constants, String[] stringPool } // Legacy constructor for backward compatibility - public InterpretedCode(short[] bytecode, Object[] constants, String[] stringPool, + public InterpretedCode(int[] bytecode, Object[] constants, String[] stringPool, int maxRegisters, RuntimeBase[] capturedVars, String sourceName, int sourceLine, java.util.Map pcToTokenIndex) { @@ -92,7 +92,7 @@ public InterpretedCode(short[] bytecode, Object[] constants, String[] stringPool } // Legacy constructor with variableRegistry but no errorUtil - public InterpretedCode(short[] bytecode, Object[] constants, String[] stringPool, + public InterpretedCode(int[] bytecode, Object[] constants, String[] stringPool, int maxRegisters, RuntimeBase[] capturedVars, String sourceName, int sourceLine, java.util.Map pcToTokenIndex, @@ -220,7 +220,7 @@ public String disassemble() { int pc = 0; while (pc < bytecode.length) { int startPc = pc; - short opcode = bytecode[pc++]; + int opcode = bytecode[pc++]; sb.append(String.format("%4d: ", startPc)); switch (opcode) { @@ -233,30 +233,30 @@ public String disassemble() { break; case Opcodes.GOTO: sb.append("GOTO ").append(readInt(bytecode, pc)).append("\n"); - pc += 2; + pc += 1; break; case Opcodes.LAST: sb.append("LAST ").append(readInt(bytecode, pc)).append("\n"); - pc += 2; + pc += 1; break; case Opcodes.NEXT: sb.append("NEXT ").append(readInt(bytecode, pc)).append("\n"); - pc += 2; + pc += 1; break; case Opcodes.REDO: sb.append("REDO ").append(readInt(bytecode, pc)).append("\n"); - pc += 2; + pc += 1; break; case Opcodes.GOTO_IF_FALSE: int condReg = bytecode[pc++]; int target = readInt(bytecode, pc); - pc += 2; + pc += 1; sb.append("GOTO_IF_FALSE r").append(condReg).append(" -> ").append(target).append("\n"); break; case Opcodes.GOTO_IF_TRUE: condReg = bytecode[pc++]; target = readInt(bytecode, pc); - pc += 2; + pc += 1; sb.append("GOTO_IF_TRUE r").append(condReg).append(" -> ").append(target).append("\n"); break; case Opcodes.MOVE: @@ -295,7 +295,7 @@ public String disassemble() { case Opcodes.LOAD_INT: rd = bytecode[pc++]; int value = readInt(bytecode, pc); - pc += 2; + pc += 1; sb.append("LOAD_INT r").append(rd).append(" = ").append(value).append("\n"); break; case Opcodes.LOAD_STRING: @@ -398,21 +398,21 @@ public String disassemble() { rd = bytecode[pc++]; int rs = bytecode[pc++]; int imm = readInt(bytecode, pc); - pc += 2; + pc += 1; sb.append("ADD_SCALAR_INT r").append(rd).append(" = r").append(rs).append(" + ").append(imm).append("\n"); break; case Opcodes.SUB_SCALAR_INT: rd = bytecode[pc++]; rs = bytecode[pc++]; int subImm = readInt(bytecode, pc); - pc += 2; + pc += 1; sb.append("SUB_SCALAR_INT r").append(rd).append(" = r").append(rs).append(" - ").append(subImm).append("\n"); break; case Opcodes.MUL_SCALAR_INT: rd = bytecode[pc++]; rs = bytecode[pc++]; int mulImm = readInt(bytecode, pc); - pc += 2; + pc += 1; sb.append("MUL_SCALAR_INT r").append(rd).append(" = r").append(rs).append(" * ").append(mulImm).append("\n"); break; case Opcodes.CONCAT: @@ -473,7 +473,7 @@ public String disassemble() { case Opcodes.ADD_ASSIGN_INT: rd = bytecode[pc++]; imm = readInt(bytecode, pc); - pc += 2; + pc += 1; sb.append("ADD_ASSIGN_INT r").append(rd).append(" += ").append(imm).append("\n"); break; case Opcodes.STRING_CONCAT_ASSIGN: @@ -1033,7 +1033,7 @@ public String disassemble() { rs1 = bytecode[pc++]; // list register rs2 = bytecode[pc++]; // closure register int pkgIdx = readInt(bytecode, pc); - pc += 2; + pc += 1; sb.append("SORT r").append(rd).append(" = sort(r").append(rs1) .append(", r").append(rs2).append(", pkg=").append(stringPool[pkgIdx]).append(")\n"); break; @@ -1110,7 +1110,7 @@ public String disassemble() { rd = bytecode[pc++]; rs = bytecode[pc++]; int packageIdx = readInt(bytecode, pc); - pc += 2; // readInt reads 2 shorts + pc += 1; // readInt reads 2 shorts String packageName = (stringPool != null && packageIdx < stringPool.length) ? stringPool[packageIdx] : ""; sb.append("PROTOTYPE r").append(rd).append(" = prototype(r").append(rs) @@ -1142,7 +1142,7 @@ public String disassemble() { rd = bytecode[pc++]; int iterReg = bytecode[pc++]; int bodyTarget = readInt(bytecode, pc); // Absolute body address - pc += 2; + pc += 1; sb.append("FOREACH_NEXT_OR_EXIT r").append(rd) .append(" = r").append(iterReg).append(".next() and goto ") .append(bodyTarget).append("\n"); @@ -1281,11 +1281,60 @@ public String disassemble() { rd = bytecode[pc++]; int fgIterReg = bytecode[pc++]; nameIdx = bytecode[pc++]; - int fgBody = readInt(bytecode, pc); pc += 2; + int fgBody = readInt(bytecode, pc); pc += 1; sb.append("FOREACH_GLOBAL_NEXT_OR_EXIT r").append(rd).append(" = r").append(fgIterReg) .append(".next(), alias $").append(stringPool[nameIdx]).append(" and goto ").append(fgBody).append("\n"); break; } + // Misc list operators: OPCODE rd argsReg ctx + case Opcodes.PACK: + case Opcodes.UNPACK: + case Opcodes.CRYPT: + case Opcodes.LOCALTIME: + case Opcodes.GMTIME: + case Opcodes.CHMOD: + case Opcodes.UNLINK: + case Opcodes.UTIME: + case Opcodes.RENAME: + case Opcodes.LINK: + case Opcodes.READLINK: + case Opcodes.UMASK: + case Opcodes.GETC: + case Opcodes.FILENO: + case Opcodes.SYSTEM: + case Opcodes.CALLER: + case Opcodes.EACH: + case Opcodes.VEC: { + rd = bytecode[pc++]; + int miscArgsReg = bytecode[pc++]; + int miscCtx = bytecode[pc++]; + String miscName = switch (opcode) { + case Opcodes.PACK -> "pack"; + case Opcodes.UNPACK -> "unpack"; + case Opcodes.CRYPT -> "crypt"; + case Opcodes.LOCALTIME -> "localtime"; + case Opcodes.GMTIME -> "gmtime"; + case Opcodes.CHMOD -> "chmod"; + case Opcodes.UNLINK -> "unlink"; + case Opcodes.UTIME -> "utime"; + case Opcodes.RENAME -> "rename"; + case Opcodes.LINK -> "link"; + case Opcodes.READLINK -> "readlink"; + case Opcodes.UMASK -> "umask"; + case Opcodes.GETC -> "getc"; + case Opcodes.FILENO -> "fileno"; + case Opcodes.SYSTEM -> "system"; + case Opcodes.CALLER -> "caller"; + case Opcodes.EACH -> "each"; + case Opcodes.VEC -> "vec"; + default -> "misc_op_" + opcode; + }; + sb.append(miscName).append(" r").append(rd) + .append(" = ").append(miscName).append("(r").append(miscArgsReg) + .append(", ctx=").append(miscCtx).append(")\n"); + break; + } + // DEPRECATED: SLOW_OP case removed - opcode 87 is no longer emitted // All operations now use direct opcodes (114-154) @@ -1358,20 +1407,18 @@ public String disassemble() { } /** - * Read a 32-bit integer from bytecode (stored as 2 shorts: high 16 bits, low 16 bits). - * Uses unsigned short values to reconstruct the full 32-bit integer. + * Read a 32-bit integer from bytecode (stored as 1 int slot). + * With int[] storage a full int fits in a single slot. */ - private static int readInt(short[] bytecode, int pc) { - int high = bytecode[pc] & 0xFFFF; // Keep mask here - need full 32-bit range - int low = bytecode[pc + 1] & 0xFFFF; // Keep mask here - need full 32-bit range - return (high << 16) | low; + private static int readInt(int[] bytecode, int pc) { + return bytecode[pc]; } /** * Builder class for constructing InterpretedCode instances. */ public static class Builder { - private short[] bytecode; + private int[] bytecode; private Object[] constants = new Object[0]; private String[] stringPool = new String[0]; private int maxRegisters = 10; @@ -1379,7 +1426,7 @@ public static class Builder { private String sourceName = ""; private int sourceLine = 1; - public Builder bytecode(short[] bytecode) { + public Builder bytecode(int[] bytecode) { this.bytecode = bytecode; return this; } diff --git a/src/main/java/org/perlonjava/backend/bytecode/InterpreterState.java b/src/main/java/org/perlonjava/backend/bytecode/InterpreterState.java index 480084fe5..72c6656d1 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/InterpreterState.java +++ b/src/main/java/org/perlonjava/backend/bytecode/InterpreterState.java @@ -1,5 +1,6 @@ package org.perlonjava.backend.bytecode; +import org.perlonjava.runtime.runtimetypes.RuntimeScalar; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; @@ -17,6 +18,22 @@ public class InterpreterState { private static final ThreadLocal> frameStack = ThreadLocal.withInitial(ArrayDeque::new); + /** + * Thread-local RuntimeScalar holding the runtime current package name. + * + * This is the single source of truth for the current package at runtime. + * It is used by: + * - caller() to return the correct calling package + * - eval STRING to compile code in the right package + * - SET_PACKAGE opcode (non-scoped: package Foo;) — sets it directly + * - PUSH_PACKAGE opcode (scoped: package Foo { }) — saves via DynamicVariableManager then sets + * + * Scoped package blocks are automatically restored when the scope exits via + * the existing POP_LOCAL_LEVEL opcode (DynamicVariableManager.popToLocalLevel). + */ + public static final ThreadLocal currentPackage = + ThreadLocal.withInitial(() -> new RuntimeScalar("main")); + /** * Represents a single interpreter call frame. * Contains minimal information needed for stack trace formatting. diff --git a/src/main/java/org/perlonjava/backend/bytecode/MiscOpcodeHandler.java b/src/main/java/org/perlonjava/backend/bytecode/MiscOpcodeHandler.java index a37514af6..b002b5e28 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/MiscOpcodeHandler.java +++ b/src/main/java/org/perlonjava/backend/bytecode/MiscOpcodeHandler.java @@ -2,6 +2,7 @@ import org.perlonjava.runtime.nativ.NativeUtils; import org.perlonjava.runtime.operators.*; +import org.perlonjava.runtime.operators.Unpack; import org.perlonjava.runtime.runtimetypes.RuntimeBase; import org.perlonjava.runtime.runtimetypes.RuntimeCode; import org.perlonjava.runtime.runtimetypes.RuntimeList; @@ -17,7 +18,7 @@ public class MiscOpcodeHandler { * Execute miscellaneous operators that take arguments and call runtime methods. * Format: OPCODE rd argsReg ctx */ - public static int execute(short opcode, short[] bytecode, int pc, RuntimeBase[] registers) { + public static int execute(int opcode, int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int argsReg = bytecode[pc++]; int ctx = bytecode[pc++]; @@ -53,10 +54,30 @@ public static int execute(short opcode, short[] bytecode, int pc, RuntimeBase[] } } case Opcodes.PACK -> Pack.pack(args); + case Opcodes.UNPACK -> Unpack.unpack(ctx, argsArray); case Opcodes.VEC -> Vec.vec(args); case Opcodes.LOCALTIME -> Time.localtime(args, ctx); case Opcodes.GMTIME -> Time.gmtime(args, ctx); case Opcodes.CRYPT -> Crypt.crypt(args); + // I/O operators + case Opcodes.CLOSE -> IOOperator.close(ctx, argsArray); + case Opcodes.BINMODE -> IOOperator.binmode(ctx, argsArray); + case Opcodes.SEEK -> IOOperator.seek(ctx, argsArray); + case Opcodes.EOF_OP -> IOOperator.eof(ctx, argsArray); + case Opcodes.SYSREAD -> IOOperator.sysread(ctx, argsArray); + case Opcodes.SYSWRITE -> IOOperator.syswrite(ctx, argsArray); + case Opcodes.SYSOPEN -> IOOperator.sysopen(ctx, argsArray); + case Opcodes.SOCKET -> IOOperator.socket(ctx, argsArray); + case Opcodes.BIND -> IOOperator.bind(ctx, argsArray); + case Opcodes.CONNECT -> IOOperator.connect(ctx, argsArray); + case Opcodes.LISTEN -> IOOperator.listen(ctx, argsArray); + case Opcodes.WRITE -> IOOperator.write(ctx, argsArray); + case Opcodes.FORMLINE -> IOOperator.formline(ctx, argsArray); + case Opcodes.PRINTF -> IOOperator.printf(ctx, argsArray); + case Opcodes.ACCEPT -> IOOperator.accept(ctx, argsArray); + case Opcodes.SYSSEEK -> IOOperator.sysseek(ctx, argsArray); + case Opcodes.TRUNCATE -> IOOperator.truncate(ctx, argsArray); + case Opcodes.READ -> IOOperator.read(ctx, argsArray); default -> throw new IllegalStateException("Unknown opcode in MiscOpcodeHandler: " + opcode); }; diff --git a/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java b/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java index 95318bb18..b9c5cc77c 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java +++ b/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java @@ -24,7 +24,7 @@ public class OpcodeHandlerExtended { * @param registers Register file * @return Updated program counter */ - public static int executeSprintf(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSprintf(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int formatReg = bytecode[pc++]; int argsListReg = bytecode[pc++]; @@ -45,7 +45,7 @@ public static int executeSprintf(short[] bytecode, int pc, RuntimeBase[] registe * @param registers Register file * @return Updated program counter */ - public static int executeChop(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeChop(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int scalarReg = bytecode[pc++]; @@ -63,7 +63,7 @@ public static int executeChop(short[] bytecode, int pc, RuntimeBase[] registers) * @param registers Register file * @return Updated program counter */ - public static int executeGetReplacementRegex(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeGetReplacementRegex(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int patternReg = bytecode[pc++]; int replacementReg = bytecode[pc++]; @@ -86,7 +86,7 @@ public static int executeGetReplacementRegex(short[] bytecode, int pc, RuntimeBa * @param registers Register file * @return Updated program counter */ - public static int executeSubstrVar(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSubstrVar(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int argsListReg = bytecode[pc++]; int ctx = bytecode[pc++]; @@ -107,7 +107,7 @@ public static int executeSubstrVar(short[] bytecode, int pc, RuntimeBase[] regis * @param registers Register file * @return Updated program counter */ - public static int executeRepeatAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeRepeatAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeBase result = Operator.repeat( @@ -128,7 +128,7 @@ public static int executeRepeatAssign(short[] bytecode, int pc, RuntimeBase[] re * @param registers Register file * @return Updated program counter */ - public static int executePowAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executePowAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeBase val1 = registers[rd]; @@ -149,7 +149,7 @@ public static int executePowAssign(short[] bytecode, int pc, RuntimeBase[] regis * @param registers Register file * @return Updated program counter */ - public static int executeLeftShiftAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeLeftShiftAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar s1 = (RuntimeScalar) registers[rd]; @@ -168,7 +168,7 @@ public static int executeLeftShiftAssign(short[] bytecode, int pc, RuntimeBase[] * @param registers Register file * @return Updated program counter */ - public static int executeRightShiftAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeRightShiftAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar s1 = (RuntimeScalar) registers[rd]; @@ -187,7 +187,7 @@ public static int executeRightShiftAssign(short[] bytecode, int pc, RuntimeBase[ * @param registers Register file * @return Updated program counter */ - public static int executeLogicalAndAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeLogicalAndAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar s1 = ((RuntimeBase) registers[rd]).scalar(); @@ -210,7 +210,7 @@ public static int executeLogicalAndAssign(short[] bytecode, int pc, RuntimeBase[ * @param registers Register file * @return Updated program counter */ - public static int executeLogicalOrAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeLogicalOrAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar s1 = ((RuntimeBase) registers[rd]).scalar(); @@ -233,7 +233,7 @@ public static int executeLogicalOrAssign(short[] bytecode, int pc, RuntimeBase[] * @param registers Register file * @return Updated program counter */ - public static int executeStringConcatAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeStringConcatAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar result = StringOperators.stringConcat( @@ -253,7 +253,7 @@ public static int executeStringConcatAssign(short[] bytecode, int pc, RuntimeBas * @param registers Register file * @return Updated program counter */ - public static int executeBitwiseAndAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeBitwiseAndAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar result = BitwiseOperators.bitwiseAnd( @@ -273,7 +273,7 @@ public static int executeBitwiseAndAssign(short[] bytecode, int pc, RuntimeBase[ * @param registers Register file * @return Updated program counter */ - public static int executeBitwiseOrAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeBitwiseOrAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar result = BitwiseOperators.bitwiseOrBinary( @@ -293,7 +293,7 @@ public static int executeBitwiseOrAssign(short[] bytecode, int pc, RuntimeBase[] * @param registers Register file * @return Updated program counter */ - public static int executeBitwiseXorAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeBitwiseXorAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar result = BitwiseOperators.bitwiseXorBinary( @@ -313,7 +313,7 @@ public static int executeBitwiseXorAssign(short[] bytecode, int pc, RuntimeBase[ * @param registers Register file * @return Updated program counter */ - public static int executeStringBitwiseAndAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeStringBitwiseAndAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar result = BitwiseOperators.bitwiseAndDot( @@ -333,7 +333,7 @@ public static int executeStringBitwiseAndAssign(short[] bytecode, int pc, Runtim * @param registers Register file * @return Updated program counter */ - public static int executeStringBitwiseOrAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeStringBitwiseOrAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar result = BitwiseOperators.bitwiseOrDot( @@ -353,7 +353,7 @@ public static int executeStringBitwiseOrAssign(short[] bytecode, int pc, Runtime * @param registers Register file * @return Updated program counter */ - public static int executeStringBitwiseXorAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeStringBitwiseXorAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; RuntimeScalar result = BitwiseOperators.bitwiseXorDot( @@ -370,7 +370,7 @@ public static int executeStringBitwiseXorAssign(short[] bytecode, int pc, Runtim * Execute bitwise AND binary operation. * Format: BITWISE_AND_BINARY rd rs1 rs2 */ - public static int executeBitwiseAndBinary(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeBitwiseAndBinary(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs1 = bytecode[pc++]; int rs2 = bytecode[pc++]; @@ -385,7 +385,7 @@ public static int executeBitwiseAndBinary(short[] bytecode, int pc, RuntimeBase[ * Execute bitwise OR binary operation. * Format: BITWISE_OR_BINARY rd rs1 rs2 */ - public static int executeBitwiseOrBinary(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeBitwiseOrBinary(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs1 = bytecode[pc++]; int rs2 = bytecode[pc++]; @@ -400,7 +400,7 @@ public static int executeBitwiseOrBinary(short[] bytecode, int pc, RuntimeBase[] * Execute bitwise XOR binary operation. * Format: BITWISE_XOR_BINARY rd rs1 rs2 */ - public static int executeBitwiseXorBinary(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeBitwiseXorBinary(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs1 = bytecode[pc++]; int rs2 = bytecode[pc++]; @@ -415,7 +415,7 @@ public static int executeBitwiseXorBinary(short[] bytecode, int pc, RuntimeBase[ * Execute string bitwise AND operation. * Format: STRING_BITWISE_AND rd rs1 rs2 */ - public static int executeStringBitwiseAnd(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeStringBitwiseAnd(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs1 = bytecode[pc++]; int rs2 = bytecode[pc++]; @@ -430,7 +430,7 @@ public static int executeStringBitwiseAnd(short[] bytecode, int pc, RuntimeBase[ * Execute string bitwise OR operation. * Format: STRING_BITWISE_OR rd rs1 rs2 */ - public static int executeStringBitwiseOr(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeStringBitwiseOr(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs1 = bytecode[pc++]; int rs2 = bytecode[pc++]; @@ -445,7 +445,7 @@ public static int executeStringBitwiseOr(short[] bytecode, int pc, RuntimeBase[] * Execute string bitwise XOR operation. * Format: STRING_BITWISE_XOR rd rs1 rs2 */ - public static int executeStringBitwiseXor(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeStringBitwiseXor(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs1 = bytecode[pc++]; int rs2 = bytecode[pc++]; @@ -460,7 +460,7 @@ public static int executeStringBitwiseXor(short[] bytecode, int pc, RuntimeBase[ * Execute bitwise NOT binary operation. * Format: BITWISE_NOT_BINARY rd rs */ - public static int executeBitwiseNotBinary(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeBitwiseNotBinary(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; registers[rd] = BitwiseOperators.bitwiseNotBinary((RuntimeScalar) registers[rs]); @@ -471,7 +471,7 @@ public static int executeBitwiseNotBinary(short[] bytecode, int pc, RuntimeBase[ * Execute bitwise NOT string operation. * Format: BITWISE_NOT_STRING rd rs */ - public static int executeBitwiseNotString(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeBitwiseNotString(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; registers[rd] = BitwiseOperators.bitwiseNotDot((RuntimeScalar) registers[rs]); @@ -482,7 +482,7 @@ public static int executeBitwiseNotString(short[] bytecode, int pc, RuntimeBase[ * Execute stat operation. * Format: STAT rd rs ctx */ - public static int executeStat(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeStat(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; int ctx = bytecode[pc++]; @@ -494,7 +494,7 @@ public static int executeStat(short[] bytecode, int pc, RuntimeBase[] registers) * Execute lstat operation. * Format: LSTAT rd rs ctx */ - public static int executeLstat(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeLstat(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; int ctx = bytecode[pc++]; @@ -506,7 +506,7 @@ public static int executeLstat(short[] bytecode, int pc, RuntimeBase[] registers * Execute print operation. * Format: PRINT contentReg filehandleReg */ - public static int executePrint(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executePrint(int[] bytecode, int pc, RuntimeBase[] registers) { int contentReg = bytecode[pc++]; int filehandleReg = bytecode[pc++]; @@ -544,7 +544,7 @@ public static int executePrint(short[] bytecode, int pc, RuntimeBase[] registers * Execute say operation. * Format: SAY contentReg filehandleReg */ - public static int executeSay(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSay(int[] bytecode, int pc, RuntimeBase[] registers) { int contentReg = bytecode[pc++]; int filehandleReg = bytecode[pc++]; @@ -582,7 +582,7 @@ public static int executeSay(short[] bytecode, int pc, RuntimeBase[] registers) * Execute chomp operation. * Format: CHOMP rd rs */ - public static int executeChomp(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeChomp(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; registers[rd] = registers[rs].chomp(); @@ -593,7 +593,7 @@ public static int executeChomp(short[] bytecode, int pc, RuntimeBase[] registers * Execute wantarray operation. * Format: WANTARRAY rd wantarrayReg */ - public static int executeWantarray(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeWantarray(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int wantarrayReg = bytecode[pc++]; int ctx = ((RuntimeScalar) registers[wantarrayReg]).getInt(); @@ -605,7 +605,7 @@ public static int executeWantarray(short[] bytecode, int pc, RuntimeBase[] regis * Execute require operation. * Format: REQUIRE rd rs */ - public static int executeRequire(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeRequire(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; registers[rd] = ModuleOperators.require((RuntimeScalar) registers[rs]); @@ -616,7 +616,7 @@ public static int executeRequire(short[] bytecode, int pc, RuntimeBase[] registe * Execute pos operation. * Format: POS rd rs */ - public static int executePos(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executePos(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; registers[rd] = ((RuntimeScalar) registers[rs]).pos(); @@ -627,7 +627,7 @@ public static int executePos(short[] bytecode, int pc, RuntimeBase[] registers) * Execute index operation. * Format: INDEX rd strReg substrReg posReg */ - public static int executeIndex(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeIndex(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int strReg = bytecode[pc++]; int substrReg = bytecode[pc++]; @@ -644,7 +644,7 @@ public static int executeIndex(short[] bytecode, int pc, RuntimeBase[] registers * Execute rindex operation. * Format: RINDEX rd strReg substrReg posReg */ - public static int executeRindex(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeRindex(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int strReg = bytecode[pc++]; int substrReg = bytecode[pc++]; @@ -661,7 +661,7 @@ public static int executeRindex(short[] bytecode, int pc, RuntimeBase[] register * Execute pre-increment operation. * Format: PRE_AUTOINCREMENT rd */ - public static int executePreAutoIncrement(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executePreAutoIncrement(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; ((RuntimeScalar) registers[rd]).preAutoIncrement(); return pc; @@ -671,7 +671,7 @@ public static int executePreAutoIncrement(short[] bytecode, int pc, RuntimeBase[ * Execute post-increment operation. * Format: POST_AUTOINCREMENT rd rs */ - public static int executePostAutoIncrement(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executePostAutoIncrement(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; registers[rd] = ((RuntimeScalar) registers[rs]).postAutoIncrement(); @@ -682,7 +682,7 @@ public static int executePostAutoIncrement(short[] bytecode, int pc, RuntimeBase * Execute pre-decrement operation. * Format: PRE_AUTODECREMENT rd */ - public static int executePreAutoDecrement(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executePreAutoDecrement(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; ((RuntimeScalar) registers[rd]).preAutoDecrement(); return pc; @@ -692,7 +692,7 @@ public static int executePreAutoDecrement(short[] bytecode, int pc, RuntimeBase[ * Execute post-decrement operation. * Format: POST_AUTODECREMENT rd rs */ - public static int executePostAutoDecrement(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executePostAutoDecrement(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; registers[rd] = ((RuntimeScalar) registers[rs]).postAutoDecrement(); @@ -703,7 +703,7 @@ public static int executePostAutoDecrement(short[] bytecode, int pc, RuntimeBase * Execute open operation. * Format: OPEN rd ctx argsReg */ - public static int executeOpen(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeOpen(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int ctx = bytecode[pc++]; int argsReg = bytecode[pc++]; @@ -717,7 +717,7 @@ public static int executeOpen(short[] bytecode, int pc, RuntimeBase[] registers) * Execute readline operation. * Format: READLINE rd fhReg ctx */ - public static int executeReadline(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeReadline(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int fhReg = bytecode[pc++]; int ctx = bytecode[pc++]; @@ -729,7 +729,7 @@ public static int executeReadline(short[] bytecode, int pc, RuntimeBase[] regist * Execute match regex operation. * Format: MATCH_REGEX rd stringReg regexReg ctx */ - public static int executeMatchRegex(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeMatchRegex(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int stringReg = bytecode[pc++]; int regexReg = bytecode[pc++]; @@ -746,7 +746,7 @@ public static int executeMatchRegex(short[] bytecode, int pc, RuntimeBase[] regi * Execute negated match regex operation. * Format: MATCH_REGEX_NOT rd stringReg regexReg ctx */ - public static int executeMatchRegexNot(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeMatchRegexNot(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int stringReg = bytecode[pc++]; int regexReg = bytecode[pc++]; @@ -765,7 +765,7 @@ public static int executeMatchRegexNot(short[] bytecode, int pc, RuntimeBase[] r * Execute create closure operation. * Format: CREATE_CLOSURE rd template_idx num_captures reg1 reg2 ... */ - public static int executeCreateClosure(short[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { + public static int executeCreateClosure(int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { int rd = bytecode[pc++]; int templateIdx = bytecode[pc++]; int numCaptures = bytecode[pc++]; @@ -802,7 +802,7 @@ public static int executeCreateClosure(short[] bytecode, int pc, RuntimeBase[] r * Execute iterator create operation. * Format: ITERATOR_CREATE rd rs */ - public static int executeIteratorCreate(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeIteratorCreate(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; @@ -819,7 +819,7 @@ public static int executeIteratorCreate(short[] bytecode, int pc, RuntimeBase[] * Execute iterator has next operation. * Format: ITERATOR_HAS_NEXT rd iterReg */ - public static int executeIteratorHasNext(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeIteratorHasNext(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int iterReg = bytecode[pc++]; @@ -837,7 +837,7 @@ public static int executeIteratorHasNext(short[] bytecode, int pc, RuntimeBase[] * Execute iterator next operation. * Format: ITERATOR_NEXT rd iterReg */ - public static int executeIteratorNext(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeIteratorNext(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int iterReg = bytecode[pc++]; @@ -855,7 +855,7 @@ public static int executeIteratorNext(short[] bytecode, int pc, RuntimeBase[] re * Execute subtract assign operation. * Format: SUBTRACT_ASSIGN rd rs */ - public static int executeSubtractAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSubtractAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; @@ -872,7 +872,7 @@ public static int executeSubtractAssign(short[] bytecode, int pc, RuntimeBase[] * Execute multiply assign operation. * Format: MULTIPLY_ASSIGN rd rs */ - public static int executeMultiplyAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeMultiplyAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; @@ -889,7 +889,7 @@ public static int executeMultiplyAssign(short[] bytecode, int pc, RuntimeBase[] * Execute divide assign operation. * Format: DIVIDE_ASSIGN rd rs */ - public static int executeDivideAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeDivideAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; @@ -906,7 +906,7 @@ public static int executeDivideAssign(short[] bytecode, int pc, RuntimeBase[] re * Execute modulus assign operation. * Format: MODULUS_ASSIGN rd rs */ - public static int executeModulusAssign(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeModulusAssign(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; diff --git a/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerFileTest.java b/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerFileTest.java index 50fbe5d1b..9e6b5971f 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerFileTest.java +++ b/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerFileTest.java @@ -22,7 +22,7 @@ public class OpcodeHandlerFileTest { * @param opcode The file test opcode (190-216) * @return Updated program counter */ - public static int executeFileTest(short[] bytecode, int pc, RuntimeBase[] registers, short opcode) { + public static int executeFileTest(int[] bytecode, int pc, RuntimeBase[] registers, int opcode) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; diff --git a/src/main/java/org/perlonjava/backend/bytecode/Opcodes.java b/src/main/java/org/perlonjava/backend/bytecode/Opcodes.java index c9784cce9..dd7ac7b97 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/Opcodes.java +++ b/src/main/java/org/perlonjava/backend/bytecode/Opcodes.java @@ -1004,5 +1004,65 @@ public class Opcodes { * Format: FOREACH_GLOBAL_NEXT_OR_EXIT varReg iterReg nameIdx exitTarget */ public static final short FOREACH_GLOBAL_NEXT_OR_EXIT = 304; + /** Unpack binary data into a list of scalars. + * Format: UNPACK rd argsReg ctx */ + public static final short UNPACK = 305; + + /** Set current package at runtime (non-scoped: package Foo;). + * Format: SET_PACKAGE nameIdx + * Effect: Updates InterpreterState current frame's packageName to stringPool[nameIdx] */ + public static final short SET_PACKAGE = 306; + + // ================================================================= + // I/O OPERATORS (309-329) - truly new ones not already defined above + // Note: OPEN=165, READLINE=166, TELL=LASTOP+37 already exist + // ================================================================= + /** close FILEHANDLE: Format: CLOSE rd argsReg ctx */ + public static final short CLOSE = 309; + /** binmode FILEHANDLE,LAYER: Format: BINMODE rd argsReg ctx */ + public static final short BINMODE = 312; + /** seek FILEHANDLE,POS,WHENCE: Format: SEEK rd argsReg ctx */ + public static final short SEEK = 313; + /** eof FILEHANDLE: Format: EOF_OP rd argsReg ctx */ + public static final short EOF_OP = 315; + /** sysread FILEHANDLE,SCALAR,LENGTH: Format: SYSREAD rd argsReg ctx */ + public static final short SYSREAD = 316; + /** syswrite FILEHANDLE,SCALAR: Format: SYSWRITE rd argsReg ctx */ + public static final short SYSWRITE = 317; + /** sysopen FILEHANDLE,FILENAME,MODE: Format: SYSOPEN rd argsReg ctx */ + public static final short SYSOPEN = 318; + /** socket SOCKET,DOMAIN,TYPE,PROTOCOL: Format: SOCKET rd argsReg ctx */ + public static final short SOCKET = 319; + /** bind SOCKET,NAME: Format: BIND rd argsReg ctx */ + public static final short BIND = 320; + /** connect SOCKET,NAME: Format: CONNECT rd argsReg ctx */ + public static final short CONNECT = 321; + /** listen SOCKET,QUEUESIZE: Format: LISTEN rd argsReg ctx */ + public static final short LISTEN = 322; + /** write FILEHANDLE: Format: WRITE rd argsReg ctx */ + public static final short WRITE = 323; + /** formline PICTURE,LIST: Format: FORMLINE rd argsReg ctx */ + public static final short FORMLINE = 324; + /** printf FILEHANDLE,FORMAT,LIST: Format: PRINTF rd argsReg ctx */ + public static final short PRINTF = 325; + /** accept NEWSOCKET,GENERICSOCKET: Format: ACCEPT rd argsReg ctx */ + public static final short ACCEPT = 326; + /** sysseek FILEHANDLE,POS,WHENCE: Format: SYSSEEK rd argsReg ctx */ + public static final short SYSSEEK = 327; + /** truncate FILEHANDLE,LENGTH: Format: TRUNCATE rd argsReg ctx */ + public static final short TRUNCATE = 328; + /** read FILEHANDLE,SCALAR,LENGTH: Format: READ rd argsReg ctx */ + public static final short READ = 329; + + /** Enter scoped package block (package Foo { ...). + * Format: PUSH_PACKAGE nameIdx + * Effect: Saves current packageName, sets new one */ + public static final short PUSH_PACKAGE = 307; + + /** Exit scoped package block (closing } of package Foo { ...). + * Format: POP_PACKAGE + * Effect: Restores previous packageName */ + public static final short POP_PACKAGE = 308; + private Opcodes() {} // Utility class - no instantiation } diff --git a/src/main/java/org/perlonjava/backend/bytecode/ScalarBinaryOpcodeHandler.java b/src/main/java/org/perlonjava/backend/bytecode/ScalarBinaryOpcodeHandler.java index 61967aa61..55722acdd 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/ScalarBinaryOpcodeHandler.java +++ b/src/main/java/org/perlonjava/backend/bytecode/ScalarBinaryOpcodeHandler.java @@ -17,7 +17,7 @@ public class ScalarBinaryOpcodeHandler { /** * Execute scalar binary operations (atan2, eq, ne, lt, le, gt, ge, cmp, etc.) operation. */ - public static int execute(int opcode, short[] bytecode, int pc, + public static int execute(int opcode, int[] bytecode, int pc, RuntimeBase[] registers) { // Read registers (shared by all opcodes in this group) int rd = bytecode[pc++]; @@ -47,7 +47,7 @@ public static int execute(int opcode, short[] bytecode, int pc, /** * Disassemble scalar binary operations (atan2, eq, ne, lt, le, gt, ge, cmp, etc.) operation. */ - public static int disassemble(int opcode, short[] bytecode, int pc, + public static int disassemble(int opcode, int[] bytecode, int pc, StringBuilder sb) { int rd = bytecode[pc++]; int rs1 = bytecode[pc++]; diff --git a/src/main/java/org/perlonjava/backend/bytecode/ScalarUnaryOpcodeHandler.java b/src/main/java/org/perlonjava/backend/bytecode/ScalarUnaryOpcodeHandler.java index 0e52fa990..971aacd13 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/ScalarUnaryOpcodeHandler.java +++ b/src/main/java/org/perlonjava/backend/bytecode/ScalarUnaryOpcodeHandler.java @@ -22,7 +22,7 @@ public class ScalarUnaryOpcodeHandler { /** * Execute scalar unary operations (chr, ord, abs, sin, cos, lc, uc, etc.) operation. */ - public static int execute(int opcode, short[] bytecode, int pc, + public static int execute(int opcode, int[] bytecode, int pc, RuntimeBase[] registers) { // Read registers (shared by all opcodes in this group) int rd = bytecode[pc++]; @@ -70,7 +70,7 @@ public static int execute(int opcode, short[] bytecode, int pc, /** * Disassemble scalar unary operations (chr, ord, abs, sin, cos, lc, uc, etc.) operation. */ - public static int disassemble(int opcode, short[] bytecode, int pc, + public static int disassemble(int opcode, int[] bytecode, int pc, StringBuilder sb) { int rd = bytecode[pc++]; int rs = bytecode[pc++]; diff --git a/src/main/java/org/perlonjava/backend/bytecode/SlowOpcodeHandler.java b/src/main/java/org/perlonjava/backend/bytecode/SlowOpcodeHandler.java index cbffa1891..5e577f5f0 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/SlowOpcodeHandler.java +++ b/src/main/java/org/perlonjava/backend/bytecode/SlowOpcodeHandler.java @@ -66,7 +66,7 @@ public class SlowOpcodeHandler { * Format: [SLOW_CHOWN] [rs_list] [rs_uid] [rs_gid] * Effect: Changes ownership of files in list */ - public static int executeChown(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeChown(int[] bytecode, int pc, RuntimeBase[] registers) { int listReg = bytecode[pc++]; int uidReg = bytecode[pc++]; int gidReg = bytecode[pc++]; @@ -83,7 +83,7 @@ public static int executeChown(short[] bytecode, int pc, RuntimeBase[] registers * Format: [SLOW_WAITPID] [rd] [rs_pid] [rs_flags] * Effect: Waits for child process and returns status */ - public static int executeWaitpid(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeWaitpid(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int pidReg = bytecode[pc++]; int flagsReg = bytecode[pc++]; @@ -102,7 +102,7 @@ public static int executeWaitpid(short[] bytecode, int pc, RuntimeBase[] registe * Format: [SLOW_SETSOCKOPT] [rs_socket] [rs_level] [rs_optname] [rs_optval] * Effect: Sets socket option */ - public static int executeSetsockopt(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSetsockopt(int[] bytecode, int pc, RuntimeBase[] registers) { int socketReg = bytecode[pc++]; int levelReg = bytecode[pc++]; int optnameReg = bytecode[pc++]; @@ -119,7 +119,7 @@ public static int executeSetsockopt(short[] bytecode, int pc, RuntimeBase[] regi * Format: [SLOW_GETSOCKOPT] [rd] [rs_socket] [rs_level] [rs_optname] * Effect: Gets socket option value */ - public static int executeGetsockopt(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeGetsockopt(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int socketReg = bytecode[pc++]; int levelReg = bytecode[pc++]; @@ -136,7 +136,7 @@ public static int executeGetsockopt(short[] bytecode, int pc, RuntimeBase[] regi * Format: [SLOW_GETPRIORITY] [rd] [rs_which] [rs_who] * Effect: Gets process priority */ - public static int executeGetpriority(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeGetpriority(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int whichReg = bytecode[pc++]; int whoReg = bytecode[pc++]; @@ -151,7 +151,7 @@ public static int executeGetpriority(short[] bytecode, int pc, RuntimeBase[] reg * Format: [SLOW_SETPRIORITY] [rs_which] [rs_who] [rs_priority] * Effect: Sets process priority */ - public static int executeSetpriority(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSetpriority(int[] bytecode, int pc, RuntimeBase[] registers) { int whichReg = bytecode[pc++]; int whoReg = bytecode[pc++]; int priorityReg = bytecode[pc++]; @@ -166,7 +166,7 @@ public static int executeSetpriority(short[] bytecode, int pc, RuntimeBase[] reg * Format: [SLOW_GETPGRP] [rd] [rs_pid] * Effect: Gets process group ID */ - public static int executeGetpgrp(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeGetpgrp(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int pidReg = bytecode[pc++]; @@ -180,7 +180,7 @@ public static int executeGetpgrp(short[] bytecode, int pc, RuntimeBase[] registe * Format: [SLOW_SETPGRP] [rs_pid] [rs_pgrp] * Effect: Sets process group ID */ - public static int executeSetpgrp(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSetpgrp(int[] bytecode, int pc, RuntimeBase[] registers) { int pidReg = bytecode[pc++]; int pgrpReg = bytecode[pc++]; @@ -193,7 +193,7 @@ public static int executeSetpgrp(short[] bytecode, int pc, RuntimeBase[] registe * Format: [SLOW_GETPPID] [rd] * Effect: Gets parent process ID */ - public static int executeGetppid(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeGetppid(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; // Java 9+ has ProcessHandle.current().parent() @@ -207,7 +207,7 @@ public static int executeGetppid(short[] bytecode, int pc, RuntimeBase[] registe * Format: [SLOW_FORK] [rd] * Effect: Forks process (not supported in Java) */ - public static int executeFork(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeFork(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; // fork() is not supported in Java - return -1 (error) @@ -222,7 +222,7 @@ public static int executeFork(short[] bytecode, int pc, RuntimeBase[] registers) * Format: [SLOW_SEMGET] [rd] [rs_key] [rs_nsems] [rs_flags] * Effect: Gets semaphore set identifier */ - public static int executeSemget(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSemget(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int keyReg = bytecode[pc++]; int nsemsReg = bytecode[pc++]; @@ -237,7 +237,7 @@ public static int executeSemget(short[] bytecode, int pc, RuntimeBase[] register * Format: [SLOW_SEMOP] [rd] [rs_semid] [rs_opstring] * Effect: Performs semaphore operations */ - public static int executeSemop(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSemop(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int semidReg = bytecode[pc++]; int opstringReg = bytecode[pc++]; @@ -251,7 +251,7 @@ public static int executeSemop(short[] bytecode, int pc, RuntimeBase[] registers * Format: [SLOW_MSGGET] [rd] [rs_key] [rs_flags] * Effect: Gets message queue identifier */ - public static int executeMsgget(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeMsgget(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int keyReg = bytecode[pc++]; int flagsReg = bytecode[pc++]; @@ -265,7 +265,7 @@ public static int executeMsgget(short[] bytecode, int pc, RuntimeBase[] register * Format: [SLOW_MSGSND] [rd] [rs_id] [rs_msg] [rs_flags] * Effect: Sends message to queue */ - public static int executeMsgsnd(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeMsgsnd(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int idReg = bytecode[pc++]; int msgReg = bytecode[pc++]; @@ -280,7 +280,7 @@ public static int executeMsgsnd(short[] bytecode, int pc, RuntimeBase[] register * Format: [SLOW_MSGRCV] [rd] [rs_id] [rs_size] [rs_type] [rs_flags] * Effect: Receives message from queue */ - public static int executeMsgrcv(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeMsgrcv(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int idReg = bytecode[pc++]; int sizeReg = bytecode[pc++]; @@ -296,7 +296,7 @@ public static int executeMsgrcv(short[] bytecode, int pc, RuntimeBase[] register * Format: [SLOW_SHMGET] [rd] [rs_key] [rs_size] [rs_flags] * Effect: Gets shared memory segment */ - public static int executeShmget(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeShmget(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int keyReg = bytecode[pc++]; int sizeReg = bytecode[pc++]; @@ -311,7 +311,7 @@ public static int executeShmget(short[] bytecode, int pc, RuntimeBase[] register * Format: [SLOW_SHMREAD] [rd] [rs_id] [rs_pos] [rs_size] * Effect: Reads from shared memory */ - public static int executeShmread(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeShmread(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int idReg = bytecode[pc++]; int posReg = bytecode[pc++]; @@ -326,7 +326,7 @@ public static int executeShmread(short[] bytecode, int pc, RuntimeBase[] registe * Format: [SLOW_SHMWRITE] [rs_id] [rs_pos] [rs_string] * Effect: Writes to shared memory */ - public static int executeShmwrite(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeShmwrite(int[] bytecode, int pc, RuntimeBase[] registers) { int idReg = bytecode[pc++]; int posReg = bytecode[pc++]; int stringReg = bytecode[pc++]; @@ -340,7 +340,7 @@ public static int executeShmwrite(short[] bytecode, int pc, RuntimeBase[] regist * Format: [SLOW_SYSCALL] [rd] [rs_number] [arg_count] [rs_arg1] [rs_arg2] ... * Effect: Makes arbitrary system call */ - public static int executeSyscall(short[] bytecode, int pc, RuntimeBase[] registers) { + public static int executeSyscall(int[] bytecode, int pc, RuntimeBase[] registers) { int rd = bytecode[pc++]; int numberReg = bytecode[pc++]; int argCount = bytecode[pc++]; @@ -360,7 +360,7 @@ public static int executeSyscall(short[] bytecode, int pc, RuntimeBase[] registe * Effect: Dynamically evaluates Perl code string */ public static int executeEvalString( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { @@ -398,7 +398,7 @@ public static int executeEvalString( * Effect: Sets or gets the default output filehandle */ public static int executeSelect( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -423,7 +423,7 @@ public static int executeSelect( * Effect: Loads a glob/filehandle from global variables */ public static int executeLoadGlob( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { @@ -450,7 +450,7 @@ public static int executeLoadGlob( * @return The new program counter */ public static int executeSleep( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -478,7 +478,7 @@ public static int executeSleep( * @return Updated program counter */ public static int executeDerefArray( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -509,7 +509,7 @@ public static int executeDerefArray( * Effect: rd = PersistentVariable.retrieveBeginScalar(stringPool[nameIdx], begin_id) */ public static int executeRetrieveBeginScalar( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { @@ -531,7 +531,7 @@ public static int executeRetrieveBeginScalar( * Effect: rd = PersistentVariable.retrieveBeginArray(stringPool[nameIdx], begin_id) */ public static int executeRetrieveBeginArray( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { @@ -553,7 +553,7 @@ public static int executeRetrieveBeginArray( * Effect: rd = PersistentVariable.retrieveBeginHash(stringPool[nameIdx], begin_id) */ public static int executeRetrieveBeginHash( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { @@ -575,7 +575,7 @@ public static int executeRetrieveBeginHash( * Effect: rd = GlobalRuntimeScalar.makeLocal(stringPool[nameIdx]) */ public static int executeLocalScalar( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { @@ -597,7 +597,7 @@ public static int executeLocalScalar( * In scalar context, returns last element removed (or undef if no elements removed) */ public static int executeSplice( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -630,7 +630,7 @@ public static int executeSplice( * Effect: rd = array.getSlice(indices) */ public static int executeArraySlice( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -653,7 +653,7 @@ public static int executeArraySlice( * Effect: rd = Operator.reverse(ctx, args...) */ public static int executeReverse( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -676,7 +676,7 @@ public static int executeReverse( * Effect: Sets array elements at indices to values */ public static int executeArraySliceSet( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -699,7 +699,7 @@ public static int executeArraySliceSet( * Effect: rd = Operator.split(pattern, args, ctx) */ public static int executeSplit( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -723,7 +723,7 @@ public static int executeSplit( * Effect: rd = exists operand (fallback for non-simple cases) */ public static int executeExists( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -743,7 +743,7 @@ public static int executeExists( * Effect: rd = delete operand (fallback for non-simple cases) */ public static int executeDelete( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -767,7 +767,7 @@ public static int executeDelete( * @return Updated program counter */ public static int executeDerefHash( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -798,7 +798,7 @@ public static int executeDerefHash( * Effect: rd = RuntimeArray of values for the given keys */ public static int executeHashSlice( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -828,7 +828,7 @@ public static int executeHashSlice( * Effect: rd = RuntimeList of deleted values */ public static int executeHashSliceDelete( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -858,7 +858,7 @@ public static int executeHashSliceDelete( * Effect: Assign values to multiple hash keys (slice assignment) */ public static int executeHashSliceSet( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -898,7 +898,7 @@ public static int executeHashSliceSet( * Format: [SLOWOP_LIST_SLICE_FROM] [rd] [listReg] [startIndex] */ public static int executeListSliceFrom( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -959,7 +959,7 @@ public static int executeListSliceFrom( * Format: [SLOWOP_LENGTH] [rd] [stringReg] */ public static int executeLength( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -982,7 +982,7 @@ public static int executeLength( * Returns: Count of transliterated characters */ public static int executeTransliterate( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { @@ -992,8 +992,8 @@ public static int executeTransliterate( int modifiersReg = bytecode[pc++]; int targetReg = bytecode[pc++]; - // Read context (4 bytes = 1 int) - int context = ((bytecode[pc++] & 0xFFFF) << 16) | (bytecode[pc++] & 0xFFFF); + // Read context (1 int slot) + int context = bytecode[pc++]; RuntimeScalar search = (RuntimeScalar) registers[searchReg]; RuntimeScalar replace = (RuntimeScalar) registers[replaceReg]; @@ -1013,7 +1013,7 @@ public static int executeTransliterate( * Effect: Applies file test operator to cached filehandle from last stat/lstat */ public static int executeFiletestLastHandle( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers, InterpretedCode code) { @@ -1036,7 +1036,7 @@ public static int executeFiletestLastHandle( * This ensures proper glob slot access without incorrectly dereferencing the glob as a hash */ public static int executeGlobSlotGet( - short[] bytecode, + int[] bytecode, int pc, RuntimeBase[] registers) { diff --git a/src/main/java/org/perlonjava/runtime/operators/IOOperator.java b/src/main/java/org/perlonjava/runtime/operators/IOOperator.java index 0e5957327..78aeb24d1 100644 --- a/src/main/java/org/perlonjava/runtime/operators/IOOperator.java +++ b/src/main/java/org/perlonjava/runtime/operators/IOOperator.java @@ -2093,4 +2093,53 @@ public static RuntimeScalar socketpair(int ctx, RuntimeBase... args) { } } + // ================================================================= + // Adapter overloads for MiscOpcodeHandler (int ctx, RuntimeBase... args) signature + // ================================================================= + + public static RuntimeScalar seek(int ctx, RuntimeBase... args) { + if (args.length < 3) throw new PerlCompilerException("Not enough arguments for seek"); + RuntimeList list = new RuntimeList(); + for (int i = 1; i < args.length; i++) list.add(args[i]); + return seek(args[0].scalar(), list); + } + + public static RuntimeScalar tell(int ctx, RuntimeBase... args) { + RuntimeScalar fh = args.length > 0 ? args[0].scalar() : new RuntimeScalar(); + return tell(fh); + } + + public static RuntimeScalar binmode(int ctx, RuntimeBase... args) { + if (args.length < 1) throw new PerlCompilerException("Not enough arguments for binmode"); + RuntimeList list = new RuntimeList(); + for (int i = 1; i < args.length; i++) list.add(args[i]); + return binmode(args[0].scalar(), list); + } + + public static RuntimeScalar eof(int ctx, RuntimeBase... args) { + RuntimeScalar fh = args.length > 0 ? args[0].scalar() : new RuntimeScalar(); + return eof(fh); + } + + public static RuntimeScalar printf(int ctx, RuntimeBase... args) { + if (args.length < 1) throw new PerlCompilerException("Not enough arguments for printf"); + RuntimeScalar fh = args[0].scalar(); + RuntimeList list = new RuntimeList(); + for (int i = 1; i < args.length; i++) list.add(args[i]); + return printf(list, fh); + } + + public static RuntimeScalar readline(int ctx, RuntimeBase... args) { + RuntimeScalar fh = args.length > 0 ? args[0].scalar() : new RuntimeScalar("main::STDIN"); + return (RuntimeScalar) Readline.readline(fh, ctx); + } + + public static RuntimeScalar sysseek(int ctx, RuntimeBase... args) { + return seek(ctx, args); + } + + public static RuntimeScalar read(int ctx, RuntimeBase... args) { + return sysread(ctx, args); + } + } diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Exporter.java b/src/main/java/org/perlonjava/runtime/perlmodule/Exporter.java index 2d49acbcc..9debb3ce2 100644 --- a/src/main/java/org/perlonjava/runtime/perlmodule/Exporter.java +++ b/src/main/java/org/perlonjava/runtime/perlmodule/Exporter.java @@ -248,7 +248,7 @@ public static RuntimeList exportToLevel(RuntimeArray args, int ctx) { public static RuntimeList exportTags(RuntimeArray args, int ctx) { // Extract the package name from caller - RuntimeScalar packageScalar = RuntimeCode.caller(new RuntimeList(), SCALAR).getFirst().scalar(); + String packageScalar = RuntimeCode.caller(new RuntimeList(), SCALAR).getFirst().scalar().toString(); // Retrieve the export lists and tags from the package RuntimeArray export = GlobalVariable.getGlobalArray(packageScalar + "::EXPORT"); RuntimeHash exportTags = GlobalVariable.getGlobalHash(packageScalar + "::EXPORT_TAGS"); @@ -264,11 +264,11 @@ public static RuntimeList exportTags(RuntimeArray args, int ctx) { public static RuntimeList exportOkTags(RuntimeArray args, int ctx) { // Extract the package name from caller RuntimeScalar packageScalar = RuntimeCode.caller(new RuntimeList(), SCALAR).getFirst().scalar(); - // System.out.println("exportOkTags " + packageScalar + "::EXPORT_OK " + packageScalar + "::EXPORT_TAGS"); + String packageName = packageScalar.toString(); // Retrieve the export lists and tags from the package - RuntimeArray exportOk = GlobalVariable.getGlobalArray(packageScalar + "::EXPORT_OK"); - RuntimeHash exportTags = GlobalVariable.getGlobalHash(packageScalar + "::EXPORT_TAGS"); + RuntimeArray exportOk = GlobalVariable.getGlobalArray(packageName + "::EXPORT_OK"); + RuntimeHash exportTags = GlobalVariable.getGlobalHash(packageName + "::EXPORT_TAGS"); for (RuntimeBase elem : args.elements) { RuntimeArray tags = exportTags.get(elem.toString()).arrayDeref(); for (RuntimeScalar tag : tags.elements) { diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/ExceptionFormatter.java b/src/main/java/org/perlonjava/runtime/runtimetypes/ExceptionFormatter.java index 2f7aa92fc..d699a6170 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/ExceptionFormatter.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/ExceptionFormatter.java @@ -51,6 +51,12 @@ private static ArrayList> formatThrowable(Throwable t) { var locationToClassName = new HashMap(); + // Snapshot interpreter frames so we can consume them in order. + // Each BytecodeInterpreter.execute() JVM frame corresponds to one Perl call + // level; consuming them in order gives the correct nested call stack. + var interpreterFrames = InterpreterState.getStack(); + int interpreterFrameIndex = 0; + for (var element : t.getStackTrace()) { if (element.getClassName().equals("org.perlonjava.frontend.parser.StatementParser") && element.getMethodName().equals("parseUseDeclaration")) { @@ -68,22 +74,33 @@ private static ArrayList> formatThrowable(Throwable t) { } } else if (element.getClassName().equals("org.perlonjava.backend.bytecode.BytecodeInterpreter") && element.getMethodName().equals("execute")) { - // Interpreter frame - get information from InterpreterState - var frame = InterpreterState.current(); - if (frame != null && frame.code != null) { - // Format the interpreter frame as a Perl stack entry - String subName = frame.subroutineName; - if (subName != null && !subName.isEmpty() && !subName.contains("::")) { - subName = frame.packageName + "::" + subName; - } + // Consume the next interpreter frame in order. + // Using current() always returned the same topmost frame; consuming + // in order correctly maps each JVM execute() frame to its Perl level. + if (interpreterFrameIndex < interpreterFrames.size()) { + var frame = interpreterFrames.get(interpreterFrameIndex); + if (frame != null && frame.code != null) { + // For the innermost frame (index 0), use the runtime current package + // tracked by SET_PACKAGE/PUSH_PACKAGE opcodes, which reflects runtime + // "package Foo;" declarations. Outer frames still use compile-time names. + String pkg = (interpreterFrameIndex == 0) + ? InterpreterState.currentPackage.get().toString() + : frame.packageName; + interpreterFrameIndex++; - var entry = new ArrayList(); - entry.add(frame.packageName); - entry.add(frame.code.sourceName); - entry.add(String.valueOf(frame.code.sourceLine)); - entry.add(subName); // Subroutine name - stackTrace.add(entry); - lastFileName = frame.code.sourceName != null ? frame.code.sourceName : ""; + String subName = frame.subroutineName; + if (subName != null && !subName.isEmpty() && !subName.contains("::")) { + subName = pkg + "::" + subName; + } + + var entry = new ArrayList(); + entry.add(pkg); + entry.add(frame.code.sourceName); + entry.add(String.valueOf(frame.code.sourceLine)); + entry.add(subName); + stackTrace.add(entry); + lastFileName = frame.code.sourceName != null ? frame.code.sourceName : ""; + } } } else if (element.getClassName().contains("org.perlonjava.anon") || element.getClassName().contains("org.perlonjava.runtime.perlmodule")) { diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeCode.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeCode.java index 71e5b074f..55163c53e 100644 --- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeCode.java +++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeCode.java @@ -16,6 +16,7 @@ import org.perlonjava.frontend.semantic.SymbolTable; import org.perlonjava.backend.bytecode.BytecodeCompiler; import org.perlonjava.backend.bytecode.InterpretedCode; +import org.perlonjava.backend.bytecode.InterpreterState; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -1190,15 +1191,6 @@ public static RuntimeList caller(RuntimeList args, int ctx) { frame++; } -// // Show debug info -// System.err.println("# Runtime stack trace: frame=" + frame + " size=" + stackTraceSize); -// for (int i = 0; i < stackTraceSize; i++) { -// ArrayList entry = stackTrace.get(i); -// String subName = entry.size() > 3 ? entry.get(3) : "NO_SUB"; -// System.err.println("# " + i + ": pkg=" + entry.get(0) + " file=" + entry.get(1) + " line=" + entry.get(2) + " sub=" + subName); -// } -// System.err.println(); - if (frame >= 0 && frame < stackTraceSize) { // Runtime stack trace if (ctx == RuntimeContextType.SCALAR) {