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
2 changes: 2 additions & 0 deletions src/main/java/org/perlonjava/app/cli/ArgumentParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,7 @@ private static int processLongSwitches(String[] args, CompilerOptions parsedArgs
case "--debug":
// Enable debugging mode
parsedArgs.debugEnabled = true;
CompilerOptions.DEBUG_ENABLED = true;
break;
case "--tokenize":
// Enable tokenize-only mode
Expand Down Expand Up @@ -1193,6 +1194,7 @@ private static int handleDebugFlags(String[] args, CompilerOptions parsedArgs, i
// Store debug flags for potential future use
parsedArgs.debugFlags = debugFlags;
parsedArgs.debugEnabled = true;
CompilerOptions.DEBUG_ENABLED = true;

return index;
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/perlonjava/app/cli/CompilerOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
* - unicodeStdin/Stdout/Stderr/etc.: Unicode/encoding flags for different I/O streams.
*/
public class CompilerOptions implements Cloneable {
/**
* Global static flag to gate debug logging. Set once at CLI parsing time.
* Use this for fast short-circuit evaluation before calling logDebug().
*/
public static boolean DEBUG_ENABLED = false;
public boolean debugEnabled = false;
public boolean disassembleEnabled = false;
public boolean useInterpreter = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ public static RuntimeList executePerlCode(CompilerOptions compilerOptions,
globalInitialized = true;
}

ctx.logDebug("parse code: " + compilerOptions.code);
ctx.logDebug(" call context " + ctx.contextType);
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("parse code: " + compilerOptions.code);
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug(" call context " + ctx.contextType);

// Apply any BEGIN-block filters before tokenization if requested
// This is a workaround for the limitation that our architecture tokenizes all source upfront
Expand Down Expand Up @@ -175,10 +175,10 @@ public static RuntimeList executePerlCode(CompilerOptions compilerOptions,
RuntimeIO.closeAllHandles();
return null; // success
}
ctx.logDebug("-- AST:\n" + ast + "--\n");
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("-- AST:\n" + ast + "--\n");

// Create the Java class from the AST
ctx.logDebug("createClassWithMethod");
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("createClassWithMethod");
// Create a new instance of ErrorMessageUtil, resetting the line counter
ctx.errorUtil = new ErrorMessageUtil(ctx.compilerOptions.fileName, tokens);
// Snapshot the symbol table after parsing.
Expand Down Expand Up @@ -241,11 +241,11 @@ public static RuntimeList executePerlAST(Node ast,
globalInitialized = true;
}

ctx.logDebug("Using provided AST");
ctx.logDebug(" call context " + ctx.contextType);
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Using provided AST");
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug(" call context " + ctx.contextType);

// Create the Java class from the AST
ctx.logDebug("createClassWithMethod");
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("createClassWithMethod");
ctx.errorUtil = new ErrorMessageUtil(ctx.compilerOptions.fileName, tokens);
// Snapshot the symbol table as seen by the parser (includes lexical decls + pragma state).
ctx.symbolTable = ctx.symbolTable.snapShot();
Expand Down Expand Up @@ -323,7 +323,7 @@ private static RuntimeList executeCode(RuntimeCode runtimeCode, EmitterContext c
throw new RuntimeException(t);
}

ctx.logDebug("Result of generatedMethod: " + result);
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Result of generatedMethod: " + result);

RuntimeIO.flushAllHandles();
return result;
Expand All @@ -343,7 +343,7 @@ private static RuntimeList executeCode(RuntimeCode runtimeCode, EmitterContext c
private static RuntimeCode compileToExecutable(Node ast, EmitterContext ctx) throws Exception {
if (ctx.compilerOptions.useInterpreter || RuntimeCode.FORCE_INTERPRETER) {
// Interpreter path - returns InterpretedCode (extends RuntimeCode)
ctx.logDebug("Compiling to bytecode interpreter");
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Compiling to bytecode interpreter");
BytecodeCompiler compiler = new BytecodeCompiler(
ctx.compilerOptions.fileName,
1, // sourceLine (legacy parameter)
Expand All @@ -361,7 +361,7 @@ private static RuntimeCode compileToExecutable(Node ast, EmitterContext ctx) thr
return interpretedCode;
} else {
// Compiler path - returns CompiledCode (wrapper around generated class)
ctx.logDebug("Compiling to JVM bytecode");
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Compiling to JVM bytecode");
try {
Class<?> generatedClass = EmitterMethodCreator.createClassWithMethod(
ctx,
Expand Down Expand Up @@ -399,7 +399,7 @@ private static RuntimeCode compileToExecutable(Node ast, EmitterContext ctx) thr
System.err.println("Note: Method too large after AST splitting, using interpreter backend.");
}

ctx.logDebug("Falling back to bytecode interpreter due to method size");
if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Falling back to bytecode interpreter due to method size");
// Reset strict/feature/warning flags before fallback compilation.
// The JVM compiler already processed BEGIN blocks (use strict, etc.)
// which set these flags on ctx.symbolTable. But the interpreter will
Expand Down
40 changes: 21 additions & 19 deletions src/main/java/org/perlonjava/backend/jvm/Dereference.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.perlonjava.backend.jvm;

import org.perlonjava.app.cli.CompilerOptions;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.perlonjava.frontend.analysis.EmitterVisitor;
Expand All @@ -19,7 +21,7 @@ public class Dereference {
* Handles the postfix `[]` operator.
*/
static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node, String arrayOperation) {
emitterVisitor.ctx.logDebug("handleArrayElementOperator " + node + " in context " + emitterVisitor.ctx.contextType);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleArrayElementOperator " + node + " in context " + emitterVisitor.ctx.contextType);
EmitterVisitor scalarVisitor =
emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context

Expand All @@ -37,7 +39,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper
// Rewrite the variable node from `$` to `@`
OperatorNode varNode = new OperatorNode("@", identifierNode, sigilNode.tokenIndex);

emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var[] ");
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var[] ");
varNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter

int arraySlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot();
Expand Down Expand Up @@ -104,7 +106,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper
* Instead, it evaluates EXPR and applies the subscript directly.
* This allows ${$aref}[0] to work even though ${$aref} alone would fail.
*/
emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ${BLOCK}[] ");
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ${BLOCK}[] ");

// Evaluate the block expression to get a RuntimeScalar (might be array/hash ref)
sigilNode.operand.accept(scalarVisitor);
Expand Down Expand Up @@ -159,7 +161,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper
* NumberNode: 10
* NumberNode: 20
*/
emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var[] ");
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var[] ");
sigilNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter

int arraySlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot();
Expand Down Expand Up @@ -208,7 +210,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper
* Perl index/value slice: returns alternating index and value.
*/

emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) %var[] ");
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) %var[] ");

// Evaluate base as scalar (array reference)
sigilNode.operand.accept(scalarVisitor);
Expand Down Expand Up @@ -312,7 +314,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper
* hashOperation is one of: "get", "delete", "exists"
*/
public static void handleHashElementOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node, String hashOperation) {
emitterVisitor.ctx.logDebug("handleHashElementOperator " + node + " in context " + emitterVisitor.ctx.contextType);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleHashElementOperator " + node + " in context " + emitterVisitor.ctx.contextType);
EmitterVisitor scalarVisitor =
emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context

Expand All @@ -331,7 +333,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina
// Rewrite the variable node from `$` to `%`
OperatorNode varNode = new OperatorNode("%", identifierNode, sigilNode.tokenIndex);

emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} ");
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} ");
varNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter

int leftSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot();
Expand All @@ -351,7 +353,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina
nodeZero = nodeRight.elements.getFirst(); // Update nodeZero to the new StringNode
}

emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right);

// Optimization: if there's only one element and it's a string literal
if (nodeRight.elements.size() == 1 && nodeZero instanceof StringNode) {
Expand Down Expand Up @@ -431,7 +433,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina
* Instead, it evaluates EXPR and applies the subscript directly.
* This allows ${$href}{key} to work even though ${$href} alone would fail.
*/
emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ${BLOCK}{} ");
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ${BLOCK}{} ");

// Evaluate the block expression to get a RuntimeScalar (might be array/hash ref)
sigilNode.operand.accept(scalarVisitor);
Expand Down Expand Up @@ -493,7 +495,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina
// Rewrite the variable node from `@` to `%`
OperatorNode varNode = new OperatorNode("%", sigilNode.operand, sigilNode.tokenIndex);

emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} " + varNode);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} " + varNode);
varNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter

int leftSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot();
Expand All @@ -505,7 +507,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina

// emit the {x} as a RuntimeList
ListNode nodeRight = ((HashLiteralNode) node.right).asListNode();
emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} as listNode: " + nodeRight);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} as listNode: " + nodeRight);

if (!nodeRight.elements.isEmpty()) {
Node nodeZero = nodeRight.elements.getFirst();
Expand All @@ -515,7 +517,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina
}
}

emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right);
nodeRight.accept(emitterVisitor.with(RuntimeContextType.LIST));

int keyListSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot();
Expand Down Expand Up @@ -561,7 +563,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina
// Rewrite the variable node from `@` to `%`
OperatorNode varNode = new OperatorNode("%", sigilNode.operand, sigilNode.tokenIndex);

emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} " + varNode);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} " + varNode);
varNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter

int leftSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot();
Expand All @@ -573,7 +575,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina

// emit the {x} as a RuntimeList
ListNode nodeRight = ((HashLiteralNode) node.right).asListNode();
emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} as listNode: " + nodeRight);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} as listNode: " + nodeRight);

if (!nodeRight.elements.isEmpty()) {
Node nodeZero = nodeRight.elements.getFirst();
Expand All @@ -583,7 +585,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina
}
}

emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right);
nodeRight.accept(emitterVisitor.with(RuntimeContextType.LIST));

int keyListSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot();
Expand Down Expand Up @@ -628,7 +630,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina
*/
static void handleArrowOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node) {
MethodVisitor mv = emitterVisitor.ctx.mv;
emitterVisitor.ctx.logDebug("handleArrowOperator " + node + " in context " + emitterVisitor.ctx.contextType);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleArrowOperator " + node + " in context " + emitterVisitor.ctx.contextType);
EmitterVisitor scalarVisitor =
emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context

Expand Down Expand Up @@ -785,7 +787,7 @@ static void handleArrowOperator(EmitterVisitor emitterVisitor, BinaryOperatorNod
}

public static void handleArrowArrayDeref(EmitterVisitor emitterVisitor, BinaryOperatorNode node, String arrayOperation) {
emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ->[] ");
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ->[] ");
EmitterVisitor scalarVisitor =
emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context

Expand Down Expand Up @@ -894,7 +896,7 @@ public static void handleArrowArrayDeref(EmitterVisitor emitterVisitor, BinaryOp
}

public static void handleArrowHashDeref(EmitterVisitor emitterVisitor, BinaryOperatorNode node, String hashOperation) {
emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ->{} " + node);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ->{} " + node);
EmitterVisitor scalarVisitor =
emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context

Expand All @@ -918,7 +920,7 @@ public static void handleArrowHashDeref(EmitterVisitor emitterVisitor, BinaryOpe
}
}

emitterVisitor.ctx.logDebug("visit -> (HashLiteralNode) autoquote " + node.right);
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit -> (HashLiteralNode) autoquote " + node.right);
nodeRight.accept(emitterVisitor.with(RuntimeContextType.SCALAR));

int keySlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.perlonjava.backend.jvm;

import org.perlonjava.app.cli.CompilerOptions;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.perlonjava.frontend.analysis.EmitterVisitor;
Expand All @@ -20,7 +22,7 @@ public class EmitBinaryOperator {
static void handleBinaryOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node, OperatorHandler operatorHandler) {
EmitterVisitor scalarVisitor =
emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context
emitterVisitor.ctx.logDebug("handleBinaryOperator: " + node.toString());
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleBinaryOperator: " + node.toString());

// Optimization
if ((node.operator.equals("+")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.perlonjava.backend.jvm;

import org.perlonjava.app.cli.CompilerOptions;

import org.objectweb.asm.Opcodes;
import org.perlonjava.frontend.analysis.EmitterVisitor;
import org.perlonjava.frontend.astnode.BinaryOperatorNode;
Expand All @@ -9,7 +11,7 @@
public class EmitBinaryOperatorNode {

public static void emitBinaryOperatorNode(EmitterVisitor emitterVisitor, BinaryOperatorNode node) {
emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) %s in context %s"
if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) %s in context %s"
.formatted(node.operator, emitterVisitor.ctx.contextType));

switch (node.operator) {
Expand Down
Loading
Loading