Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 33 additions & 16 deletions src/main/java/org/perlonjava/interpreter/BytecodeCompiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -1449,25 +1449,42 @@ private void handleGeneralHashAccess(BinaryOperatorNode node) {
keyReg = lastResultReg;
}

// The base might be either:
// 1. A RuntimeHash (from %hash which was a hash variable)
// 2. A RuntimeScalar containing a hashref (from $hash{outer})
// We need to handle both cases. Dereference if needed.
// Check if this is a glob slot access: *X{key}
// In this case, node.left is an OperatorNode with operator "*"
boolean isGlobSlotAccess = (node.left instanceof OperatorNode) &&
((OperatorNode) node.left).operator.equals("*");

if (isGlobSlotAccess) {
// For glob slot access, call hashDerefGetNonStrict directly
// This uses RuntimeGlob's override which accesses the slot without dereferencing
int rd = allocateRegister();
emit(Opcodes.GLOB_SLOT_GET);
emitReg(rd);
emitReg(baseReg);
emitReg(keyReg);

// For now, let's assume it's a scalar with hashref and dereference it first
int hashReg = allocateRegister();
emit(Opcodes.DEREF_HASH);
emitReg(hashReg);
emitReg(baseReg);
lastResultReg = rd;
} else {
// Normal hash access: dereference first, then get element
// The base might be either:
// 1. A RuntimeHash (from %hash which was a hash variable)
// 2. A RuntimeScalar containing a hashref (from $hash{outer})
// We need to handle both cases. Dereference if needed.

// Now get the element
int rd = allocateRegister();
emit(Opcodes.HASH_GET);
emitReg(rd);
emitReg(hashReg);
emitReg(keyReg);
int hashReg = allocateRegister();
emit(Opcodes.DEREF_HASH);
emitReg(hashReg);
emitReg(baseReg);

lastResultReg = rd;
// Now get the element
int rd = allocateRegister();
emit(Opcodes.HASH_GET);
emitReg(rd);
emitReg(hashReg);
emitReg(keyReg);

lastResultReg = rd;
}
} else {
throwCompilerException("Multi-element hash access not yet implemented");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2330,6 +2330,13 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
break;
}

case Opcodes.GLOB_SLOT_GET: {
// Glob slot access: rd = glob.hashDerefGetNonStrict(key, "main")
// Format: GLOB_SLOT_GET rd globReg keyReg
pc = SlowOpcodeHandler.executeGlobSlotGet(bytecode, pc, registers);
break;
}

// GENERATED_HANDLERS_END

default:
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/perlonjava/interpreter/InterpretedCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,12 @@ public String disassemble() {
int opStrIdx = bytecode[pc++];
sb.append("FILETEST_LASTHANDLE r").append(rd).append(" = ").append(stringPool[opStrIdx]).append(" _\n");
break;
case Opcodes.GLOB_SLOT_GET:
rd = bytecode[pc++];
int globReg2 = bytecode[pc++];
int keyReg = bytecode[pc++];
sb.append("GLOB_SLOT_GET r").append(rd).append(" = r").append(globReg2).append("{r").append(keyReg).append("}\n");
break;
case Opcodes.PUSH_LOCAL_VARIABLE:
rs = bytecode[pc++];
sb.append("PUSH_LOCAL_VARIABLE r").append(rs).append("\n");
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/org/perlonjava/interpreter/Opcodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -855,10 +855,21 @@ public class Opcodes {
/** Logical OR assignment: target ||= value */
public static final short LOGICAL_OR_ASSIGN = 229;

// =================================================================
// MANUAL OPCODE ADDITIONS
// Add new custom opcodes HERE (before LASTOP), not in the generated section below.
// The GENERATED_OPCODES section is automatically regenerated and will overwrite any manual additions.
// After adding an opcode here, increment LASTOP to match the highest opcode number.
// =================================================================

/** Glob slot access: rd = glob.hashDerefGetNonStrict(key, "main")
* Used for *X{HASH} style access to glob slots */
public static final short GLOB_SLOT_GET = 230;

// =================================================================
// BUILT-IN FUNCTION OPCODES - after LASTOP
// Last manually-assigned opcode (for tool reference)
private static final short LASTOP = 229;
private static final short LASTOP = 230;

// =================================================================
// Generated by dev/tools/generate_opcode_handlers.pl
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/org/perlonjava/interpreter/SlowOpcodeHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,34 @@ public static int executeFiletestLastHandle(
return pc;
}

/**
* GLOB_SLOT_GET: rd = glob.hashDerefGetNonStrict(key, "main")
* Format: [GLOB_SLOT_GET] [rd] [globReg] [keyReg]
* Effect: Access glob slot (like *X{HASH}) using RuntimeGlob's override
* This ensures proper glob slot access without incorrectly dereferencing the glob as a hash
*/
public static int executeGlobSlotGet(
short[] bytecode,
int pc,
RuntimeBase[] registers) {

int rd = bytecode[pc++];
int globReg = bytecode[pc++];
int keyReg = bytecode[pc++];

RuntimeBase globBase = registers[globReg];
RuntimeScalar key = (RuntimeScalar) registers[keyReg];

// Convert to scalar if needed
RuntimeScalar glob = globBase.scalar();

// Call hashDerefGetNonStrict which for RuntimeGlob accesses the slot directly
// without dereferencing the glob as a hash
registers[rd] = glob.hashDerefGetNonStrict(key, "main");

return pc;
}

private SlowOpcodeHandler() {
// Utility class - no instantiation
}
Expand Down