Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ public void visit(BlockNode node) {

// Save the last statement's result to the outer register BEFORE exiting scope
if (outerResultReg >= 0 && lastResultReg >= 0) {
emit(Opcodes.MOVE);
emit(Opcodes.ALIAS);
emitReg(outerResultReg);
emitReg(lastResultReg);
}
Expand Down Expand Up @@ -782,7 +782,7 @@ public void visit(NumberNode node) {

if (isInteger) {
// Regular integer - use LOAD_INT to create mutable scalar
// Note: We don't use RuntimeScalarCache here because MOVE just copies references,
// Note: We don't use RuntimeScalarCache here because ALIAS just copies references,
// and we need mutable scalars for variables (++, --, etc.)
int intValue = Integer.parseInt(value);
emit(Opcodes.LOAD_INT);
Expand Down Expand Up @@ -3949,7 +3949,7 @@ private void visitEvalBlock(SubroutineNode node) {

// Store result from block
if (lastResultReg >= 0) {
emit(Opcodes.MOVE);
emit(Opcodes.ALIAS);
emitReg(resultReg);
emitReg(lastResultReg);
}
Expand Down Expand Up @@ -4188,7 +4188,7 @@ public void visit(For3Node node) {
}
// Save last statement result into outer register before exiting scope
if (outerResultReg >= 0 && lastResultReg >= 0) {
emit(Opcodes.MOVE);
emit(Opcodes.ALIAS);
emitReg(outerResultReg);
emitReg(lastResultReg);
}
Expand Down Expand Up @@ -4374,7 +4374,7 @@ public void visit(IfNode node) {
// Both branches should produce results in the same register
// If they differ, move else result to then result register
if (thenResultReg >= 0 && elseResultReg >= 0 && thenResultReg != elseResultReg) {
emit(Opcodes.MOVE);
emit(Opcodes.ALIAS);
emitReg(thenResultReg);
emitReg(elseResultReg);
}
Expand Down Expand Up @@ -4426,7 +4426,7 @@ public void visit(TernaryOperatorNode node) {
int trueReg = lastResultReg;

// Move true result to rd
emit(Opcodes.MOVE);
emit(Opcodes.ALIAS);
emitReg(rd);
emitReg(trueReg);

Expand All @@ -4444,7 +4444,7 @@ public void visit(TernaryOperatorNode node) {
int falseReg = lastResultReg;

// Move false result to rd
emit(Opcodes.MOVE);
emit(Opcodes.ALIAS);
emitReg(rd);
emitReg(falseReg);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,8 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
// REGISTER OPERATIONS
// =================================================================

case Opcodes.MOVE: {
// Register copy: rd = rs
case Opcodes.ALIAS: {
// Register alias: rd = rs (shares reference, does NOT copy value)
// Must unwrap RuntimeScalarReadOnly to prevent read-only values in variable registers
int dest = bytecode[pc++];
int src = bytecode[pc++];
Expand Down Expand Up @@ -273,6 +273,16 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
break;
}

case Opcodes.MY_SCALAR: {
// Lexical scalar assignment: rd = new RuntimeScalar(); rd.set(rs)
int rd = bytecode[pc++];
int rs = bytecode[pc++];
RuntimeScalar newScalar = new RuntimeScalar();
registers[rs].addToScalar(newScalar);
registers[rd] = newScalar;
break;
}

// =================================================================
// VARIABLE ACCESS - GLOBAL
// =================================================================
Expand Down Expand Up @@ -1215,7 +1225,7 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
break;

// =================================================================
// SUPERINSTRUCTIONS - Eliminate MOVE overhead
// SUPERINSTRUCTIONS - Eliminate ALIAS overhead
// =================================================================

case Opcodes.INC_REG: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
node.right.accept(bytecodeCompiler);
int valueReg = bytecodeCompiler.lastResultReg;

// Move to variable register
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.MY_SCALAR);
bytecodeCompiler.emitReg(reg);
bytecodeCompiler.emitReg(valueReg);

Expand Down Expand Up @@ -228,8 +227,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
node.right.accept(bytecodeCompiler);
int valueReg = bytecodeCompiler.lastResultReg;

// Move to variable register
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.MY_SCALAR);
bytecodeCompiler.emitReg(reg);
bytecodeCompiler.emitReg(valueReg);

Expand Down Expand Up @@ -329,13 +327,11 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
// Assign to variable
if (sigil.equals("$")) {
if (sigilOp.id != 0) {
// Captured variable - use SET_SCALAR to preserve aliasing
bytecodeCompiler.emit(Opcodes.SET_SCALAR);
bytecodeCompiler.emitReg(varReg);
bytecodeCompiler.emitReg(elemReg);
} else {
// Regular variable - use MOVE
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.MY_SCALAR);
bytecodeCompiler.emitReg(varReg);
bytecodeCompiler.emitReg(elemReg);
}
Expand Down Expand Up @@ -612,7 +608,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
}

// Regular assignment: $x = value
// OPTIMIZATION: Detect $x = $x + $y and emit ADD_ASSIGN instead of ADD_SCALAR + MOVE
// OPTIMIZATION: Detect $x = $x + $y and emit ADD_ASSIGN instead of ADD_SCALAR + ALIAS
if (node.left instanceof OperatorNode && node.right instanceof BinaryOperatorNode) {
OperatorNode leftOp = (OperatorNode) node.left;
BinaryOperatorNode rightBin = (BinaryOperatorNode) node.right;
Expand All @@ -639,7 +635,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
rightBin.right.accept(bytecodeCompiler);
int rhsReg = bytecodeCompiler.lastResultReg;

// Emit ADD_ASSIGN instead of ADD_SCALAR + MOVE
// Emit ADD_ASSIGN instead of ADD_SCALAR + ALIAS
bytecodeCompiler.emit(Opcodes.ADD_ASSIGN);
bytecodeCompiler.emitReg(targetReg);
bytecodeCompiler.emitReg(rhsReg);
Expand Down Expand Up @@ -740,7 +736,7 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
// LOAD_UNDEF allocates a new mutable RuntimeScalar in the target register;
// SET_SCALAR copies the source value into it.
// This avoids two bugs:
// - MOVE aliases constants from the pool, corrupting them on later mutation
// - ALIAS shares constants from the pool, corrupting them on later mutation
// - SET_SCALAR alone modifies the existing object in-place, which breaks
// 'local' variable restoration when the register was shared
bytecodeCompiler.emit(Opcodes.LOAD_UNDEF);
Expand Down Expand Up @@ -906,9 +902,8 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
bytecodeCompiler.emitReg(rhsListReg);
bytecodeCompiler.emitReg(indexReg);

// Assign to variable
if (sigil.equals("$")) {
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.SET_SCALAR);
bytecodeCompiler.emitReg(varReg);
bytecodeCompiler.emitReg(elemReg);
} else if (sigil.equals("@")) {
Expand Down Expand Up @@ -1040,9 +1035,10 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
String varName = ((IdentifierNode) node.left).name;

if (bytecodeCompiler.hasVariable(varName)) {
// Lexical variable - copy to its register
int targetReg = bytecodeCompiler.getVariableRegister(varName);
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.LOAD_UNDEF);
bytecodeCompiler.emitReg(targetReg);
bytecodeCompiler.emit(Opcodes.SET_SCALAR);
bytecodeCompiler.emitReg(targetReg);
bytecodeCompiler.emitReg(valueReg);
bytecodeCompiler.lastResultReg = targetReg;
Expand Down Expand Up @@ -1545,7 +1541,9 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
bytecodeCompiler.emitReg(targetReg);
bytecodeCompiler.emitReg(elementReg);
} else {
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.LOAD_UNDEF);
bytecodeCompiler.emitReg(targetReg);
bytecodeCompiler.emit(Opcodes.SET_SCALAR);
bytecodeCompiler.emitReg(targetReg);
bytecodeCompiler.emitReg(elementReg);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ else if (node.right instanceof BinaryOperatorNode) {

// Allocate result register and move left value to it
int rd = bytecodeCompiler.allocateRegister();
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.ALIAS);
bytecodeCompiler.emitReg(rd);
bytecodeCompiler.emitReg(rs1);

Expand All @@ -459,7 +459,7 @@ else if (node.right instanceof BinaryOperatorNode) {
int rs2 = bytecodeCompiler.lastResultReg;

// Move right result to rd (overwriting left value)
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.ALIAS);
bytecodeCompiler.emitReg(rd);
bytecodeCompiler.emitReg(rs2);

Expand All @@ -484,7 +484,7 @@ else if (node.right instanceof BinaryOperatorNode) {

// Allocate result register and move left value to it
int rd = bytecodeCompiler.allocateRegister();
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.ALIAS);
bytecodeCompiler.emitReg(rd);
bytecodeCompiler.emitReg(rs1);

Expand All @@ -501,7 +501,7 @@ else if (node.right instanceof BinaryOperatorNode) {
int rs2 = bytecodeCompiler.lastResultReg;

// Move right result to rd (overwriting left value)
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.ALIAS);
bytecodeCompiler.emitReg(rd);
bytecodeCompiler.emitReg(rs2);

Expand All @@ -526,7 +526,7 @@ else if (node.right instanceof BinaryOperatorNode) {

// Allocate result register and move left value to it
int rd = bytecodeCompiler.allocateRegister();
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.ALIAS);
bytecodeCompiler.emitReg(rd);
bytecodeCompiler.emitReg(rs1);

Expand All @@ -549,7 +549,7 @@ else if (node.right instanceof BinaryOperatorNode) {
int rs2 = bytecodeCompiler.lastResultReg;

// Move right result to rd (overwriting left value)
bytecodeCompiler.emit(Opcodes.MOVE);
bytecodeCompiler.emit(Opcodes.ALIAS);
bytecodeCompiler.emitReg(rd);
bytecodeCompiler.emitReg(rs2);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,10 +288,10 @@ public String disassemble() {
pc += 1;
sb.append("GOTO_IF_TRUE r").append(condReg).append(" -> ").append(target).append("\n");
break;
case Opcodes.MOVE:
case Opcodes.ALIAS:
int dest = bytecode[pc++];
int src = bytecode[pc++];
sb.append("MOVE r").append(dest).append(" = r").append(src).append("\n");
sb.append("ALIAS r").append(dest).append(" = r").append(src).append("\n");
break;
case Opcodes.LOAD_CONST:
int rd = bytecode[pc++];
Expand Down Expand Up @@ -365,6 +365,11 @@ public String disassemble() {
rd = bytecode[pc++];
sb.append("LOAD_UNDEF r").append(rd).append("\n");
break;
case Opcodes.MY_SCALAR:
rd = bytecode[pc++];
src = bytecode[pc++];
sb.append("MY_SCALAR r").append(rd).append(" = r").append(src).append("\n");
break;
case Opcodes.LOAD_GLOBAL_SCALAR:
rd = bytecode[pc++];
int nameIdx = bytecode[pc++];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.perlonjava.runtime.operators.Unpack;
import org.perlonjava.runtime.runtimetypes.RuntimeBase;
import org.perlonjava.runtime.runtimetypes.RuntimeCode;
import org.perlonjava.runtime.runtimetypes.RuntimeContextType;
import org.perlonjava.runtime.runtimetypes.RuntimeList;
import org.perlonjava.runtime.runtimetypes.RuntimeScalar;

Expand Down Expand Up @@ -91,6 +92,9 @@ public static int execute(int opcode, int[] bytecode, int pc, RuntimeBase[] regi
default -> throw new IllegalStateException("Unknown opcode in MiscOpcodeHandler: " + opcode);
};

if (ctx == RuntimeContextType.SCALAR && result instanceof RuntimeList) {
result = ((RuntimeList) result).scalar();
}
registers[rd] = result;
return pc;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,8 @@ public static int executeBitwiseAndBinary(int[] bytecode, int pc, RuntimeBase[]
int rs1 = bytecode[pc++];
int rs2 = bytecode[pc++];
registers[rd] = BitwiseOperators.bitwiseAnd(
(RuntimeScalar) registers[rs1],
(RuntimeScalar) registers[rs2]
registers[rs1].scalar(),
registers[rs2].scalar()
);
return pc;
}
Expand All @@ -412,8 +412,8 @@ public static int executeBitwiseOrBinary(int[] bytecode, int pc, RuntimeBase[] r
int rs1 = bytecode[pc++];
int rs2 = bytecode[pc++];
registers[rd] = BitwiseOperators.bitwiseOr(
(RuntimeScalar) registers[rs1],
(RuntimeScalar) registers[rs2]
registers[rs1].scalar(),
registers[rs2].scalar()
);
return pc;
}
Expand All @@ -427,8 +427,8 @@ public static int executeBitwiseXorBinary(int[] bytecode, int pc, RuntimeBase[]
int rs1 = bytecode[pc++];
int rs2 = bytecode[pc++];
registers[rd] = BitwiseOperators.bitwiseXor(
(RuntimeScalar) registers[rs1],
(RuntimeScalar) registers[rs2]
registers[rs1].scalar(),
registers[rs2].scalar()
);
return pc;
}
Expand All @@ -442,8 +442,8 @@ public static int executeStringBitwiseAnd(int[] bytecode, int pc, RuntimeBase[]
int rs1 = bytecode[pc++];
int rs2 = bytecode[pc++];
registers[rd] = BitwiseOperators.bitwiseAndDot(
(RuntimeScalar) registers[rs1],
(RuntimeScalar) registers[rs2]
registers[rs1].scalar(),
registers[rs2].scalar()
);
return pc;
}
Expand All @@ -457,8 +457,8 @@ public static int executeStringBitwiseOr(int[] bytecode, int pc, RuntimeBase[] r
int rs1 = bytecode[pc++];
int rs2 = bytecode[pc++];
registers[rd] = BitwiseOperators.bitwiseOrDot(
(RuntimeScalar) registers[rs1],
(RuntimeScalar) registers[rs2]
registers[rs1].scalar(),
registers[rs2].scalar()
);
return pc;
}
Expand All @@ -472,8 +472,8 @@ public static int executeStringBitwiseXor(int[] bytecode, int pc, RuntimeBase[]
int rs1 = bytecode[pc++];
int rs2 = bytecode[pc++];
registers[rd] = BitwiseOperators.bitwiseXorDot(
(RuntimeScalar) registers[rs1],
(RuntimeScalar) registers[rs2]
registers[rs1].scalar(),
registers[rs2].scalar()
);
return pc;
}
Expand All @@ -485,7 +485,7 @@ public static int executeStringBitwiseXor(int[] bytecode, int pc, RuntimeBase[]
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]);
registers[rd] = BitwiseOperators.bitwiseNotBinary(registers[rs].scalar());
return pc;
}

Expand All @@ -496,7 +496,7 @@ public static int executeBitwiseNotBinary(int[] bytecode, int pc, RuntimeBase[]
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]);
registers[rd] = BitwiseOperators.bitwiseNotDot(registers[rs].scalar());
return pc;
}

Expand Down
Loading