Class CompileStack

java.lang.Object
org.codehaus.groovy.classgen.asm.CompileStack

public class CompileStack extends Object
Manages different aspects of the code of a code block like handling labels, defining variables, and scopes. After a MethodNode is visited clear should be called, for initialization the method init should be used.

Some Notes:

  • every push method will require a later pop call
  • method parameters may define a category 2 variable, so don't ignore the type stored in the variable object
  • the index of the variable may not be as assumed when the variable is a parameter of a method because the parameter may be used in a closure, so don't ignore the stored variable index
  • the names of temporary variables can be ignored. The names are only used for debugging and do not conflict with each other or normal variables. For accessing, the index of the variable must be used.
  • never mix temporary and normal variables by changes to this class. While the name is very important for a normal variable, it is only a helper construct for temporary variables. That means for example a name for a temporary variable can be used multiple times without conflict. So mixing them both may lead to the problem that a normal or temporary variable is hidden or even removed. That must not happen!
See Also:
  • Constructor Details

    • CompileStack

      public CompileStack(WriterController controller)
      Creates a CompileStack managed by the given controller.
      Parameters:
      controller - the writer controller for the current compilation
  • Method Details

    • getBreakLabel

      public org.objectweb.asm.Label getBreakLabel()
      Returns the current break label, or null if not inside a breakable construct.
    • getContinueLabel

      public org.objectweb.asm.Label getContinueLabel()
      Returns the current continue label, or null if not inside a loop.
    • getScope

      public VariableScope getScope()
      Returns the current variable scope.
    • pushState

      public void pushState()
      Saves the current compilation state onto an internal stack so that it can be restored by a later call to pop(). Every push* method calls this internally; it is also exposed for callers that need a bare state snapshot without additional label setup.
    • removeVar

      public void removeVar(int variableIndex)
      Indicates that the specified temporary variable is no longer used.
    • pop

      public void pop()
      Restores the compilation state that was saved by the matching push* call, and emits end-labels for all local variables declared within the scope that is being popped.
    • defineTemporaryVariable

      public int defineTemporaryVariable(Variable var, boolean store)
      Creates a temporary variable.
      Parameters:
      var - specifies name and type
      store - defines if the toplevel argument of the stack should be stored
      Returns:
      the index used for this temporary variable
    • getVariable

      public BytecodeVariable getVariable(String variableName)
      Returns a variable by name, throwing a GroovyBugError if it does not exist. Convenience overload of getVariable(String, boolean) with mustExist = true.
      Parameters:
      variableName - the name to look up
      Returns:
      the corresponding BytecodeVariable
    • getVariable

      public BytecodeVariable getVariable(String variableName, boolean mustExist)
      Returns a normal variable.

      If mustExist is true and the normal variable doesn't exist, then this method will throw a GroovyBugError. It is not the intention of this method to let this happen! And the exception should not be used for flow control - it is just acting as an assertion. If the exception is thrown then it indicates a bug in the class using CompileStack. This method can also not be used to return a temporary variable. Temporary variables are not normal variables.

      Parameters:
      variableName - name of the variable
      mustExist - throw exception if variable does not exist
      Returns:
      the normal variable or null if not found (and mustExist not true)
    • defineTemporaryVariable

      public int defineTemporaryVariable(String name, boolean store)
      Creates a temporary variable.
      Parameters:
      name - defines type and name
      store - defines if the top-level argument of the stack should be stored
      Returns:
      the index used for this temporary variable
    • defineTemporaryVariable

      public int defineTemporaryVariable(String name, ClassNode type, boolean store)
      Creates a temporary variable.
      Parameters:
      name - the variable name
      type - the variable type
      store - indicates if the top-level argument of the stack should be stored
      Returns:
      the index used for this temporary variable
    • clear

      public void clear()
      Clears the state of the class. This method should be called after a MethodNode is visited. Note that a call to init will fail if clear is not called before
    • addExceptionBlock

      public void addExceptionBlock(org.objectweb.asm.Label start, org.objectweb.asm.Label end, org.objectweb.asm.Label goal, String sig)
      Adds a typed or untyped exception handler to the exception table for the current method. Typed entries (non-null sig) are emitted before untyped ones to ensure correct handler ordering in the bytecode.
      Parameters:
      start - the start label of the guarded range
      end - the end label of the guarded range
      goal - the label of the handler block
      sig - the internal name of the caught exception type, or null for a catch-all handler
    • init

      public void init(VariableScope scope, Parameter[] parameters)
      initializes this class for a MethodNode. This method will automatically define variables for the method parameters and will create references if needed. The created variables can be accessed by calling getVariable().
    • pushVariableScope

      public void pushVariableScope(VariableScope scope)
      Causes the state-stack to add an element and sets the given scope as new current variable scope. Creates an element for the state stack so pop has to be called later
    • pushLoop

      public void pushLoop(VariableScope scope, List<String> labelNames)
      Should be called when descending into a loop that defines also a scope. Calls pushVariableScope and prepares labels for a loop structure. Creates an element for the state stack so pop has to be called later
    • pushLoop

      @Deprecated(since="6.0.0") public void pushLoop(VariableScope scope, String labelName)
      Deprecated.
      Should be called when descending into a loop that defines also a scope. Calls pushVariableScope and prepares labels for a loop structure. Creates a element for the state stack so pop has to be called later.
    • pushLoop

      public void pushLoop(List<String> labelNames)
      Should be called when descending into a loop that does not define a scope Creates a element for the state stack so pop has to be called later.
    • pushLoop

      @Deprecated(since="6.0.0") public void pushLoop(String labelName)
      Deprecated.
      Should be called when descending into a loop that does not define a scope. Creates a element for the state stack so pop has to be called later.
    • pushSwitch

      public org.objectweb.asm.Label pushSwitch()
      Creates a new break label and an element for the state stack so pop has to be called later.
      Returns:
      the break label
    • pushSwitch

      public org.objectweb.asm.Label pushSwitch(List<String> labelNames)
      Creates a new break label, registers it as the named break target for each label name, and pushes an element onto the state stack so that a later call to pop() restores the previous state.
      Parameters:
      labelNames - the statement labels on the switch (may be null)
      Returns:
      the break label
      Since:
      6.0.0
    • pushBreakable

      public org.objectweb.asm.Label pushBreakable(List<String> labelNames)
      Creates a new break label and an element for the state stack so pop has to be called later.
      Returns:
      the break label
      Since:
      6.0.0
    • getNamedBreakLabel

      public org.objectweb.asm.Label getNamedBreakLabel(String name)
      Returns:
      the break label for name
    • getNamedContinueLabel

      public org.objectweb.asm.Label getNamedContinueLabel(String name)
      Returns:
      the continue label for name
    • getLabel

      public org.objectweb.asm.Label getLabel(String name)
      Returns the label for the given name.
    • createLocalLabel

      public org.objectweb.asm.Label createLocalLabel(String name)
      Creates or returns the label for the given name.
    • pushBooleanExpression

      @Deprecated(since="5.0.0") public void pushBooleanExpression()
      Deprecated.
      Use pushState() directly.
      Because a boolean Expression may not be evaluated completely it is important to keep the registers clean.
    • defineVariable

      public BytecodeVariable defineVariable(Variable v, boolean initFromStack)
      Defines a new Variable using an AST variable.
      Parameters:
      initFromStack - if true the last element of the stack will be used to initialize the new variable. If false null will be used.
    • defineVariable

      public BytecodeVariable defineVariable(Variable v, ClassNode variableType, boolean initFromStack)
      Defines a variable for the given AST variable using an explicitly specified bytecode type (which may differ from the declared type, e.g. when widening for closure-shared variables).
      Parameters:
      v - the AST variable to define
      variableType - the bytecode type to assign to the slot
      initFromStack - if true the top of the operand stack is stored into the new slot; otherwise a default/null value is used
      Returns:
      the created BytecodeVariable
    • containsVariable

      public boolean containsVariable(String name)
      Parameters:
      name - the name of the variable of interest
      Returns:
      true if a variable is already defined
    • applyFinallyBlocks

      public void applyFinallyBlocks(org.objectweb.asm.Label label, boolean isBreakLabel)
      Applies any pending finally blocks on the path to label. Walks the state stack to determine which finally blocks are between the current position and the target label and inlines their bytecode.
      Parameters:
      label - the target label (break or continue destination)
      isBreakLabel - true for a break label, false for continue
    • applyBlockRecorder

      public void applyBlockRecorder()
      Applies all currently active finally blocks for a normal (non-jump) fall-through.
    • hasBlockRecorder

      public boolean hasBlockRecorder()
      Returns true if there are any active finally/synchronized blocks on the stack.
    • pushBlockRecorder

      public void pushBlockRecorder(CompileStack.BlockRecorder recorder)
      Pushes a new CompileStack.BlockRecorder (finally or synchronized guard) onto the block-recorder stack and saves state so that pop() will remove it.
      Parameters:
      recorder - the recorder to push
    • pushBlockRecorderVisit

      public void pushBlockRecorderVisit(CompileStack.BlockRecorder finallyBlock)
      Marks finallyBlock as currently being visited so that recursive finally-block application does not re-enter it.
      Parameters:
      finallyBlock - the block being visited
    • popBlockRecorderVisit

      public void popBlockRecorderVisit(CompileStack.BlockRecorder finallyBlock)
      Removes finallyBlock from the visited-block set after its inline emission is complete.
      Parameters:
      finallyBlock - the block that finished being visited
    • visitExcludedFinally

      public void visitExcludedFinally(CompileStack.BlockRecorder recorder, Runnable visit)
      Inlines an excluded finally block via visit while hiding the variables of the current (try) scope, then fully restores that scope — including its variables.

      Popping the current scope keeps try-block locals out of scope in the finally body (GROOVY-4721); restoring the saved variables afterwards ensures any subsequent re-emission of the same statement (e.g. the OptimizingStatementWriter fast/slow fork) still resolves those locals rather than falling back to property access (GROOVY-12062).

      Parameters:
      recorder - the block recorder being visited
      visit - emits the finally body
    • writeExceptionTable

      public void writeExceptionTable(CompileStack.BlockRecorder block, org.objectweb.asm.Label goal, String sig)
      Writes the exception-table entries for all label ranges recorded in block.
      Parameters:
      block - the block recorder containing the try-range labels
      goal - the handler label
      sig - the internal name of the caught type, or null for catch-all
    • isLHS

      public boolean isLHS()
      Returns true if the current expression is being compiled as a left-hand side.
    • pushLHS

      public void pushLHS(boolean lhs)
      Pushes a new left-hand-side flag onto the LHS stack.
      Parameters:
      lhs - true if the next expression is compiled as an assignment target
    • popLHS

      public void popLHS()
      Pops the top left-hand-side flag, restoring the previous LHS state.
    • isImplicitThis

      public boolean isImplicitThis()
      Returns true if the current this reference is implicit (no explicit qualifier).
    • pushImplicitThis

      public void pushImplicitThis(boolean implicitThis)
      Pushes a new implicit-this flag onto the stack.
      Parameters:
      implicitThis - true if this is used implicitly in the current context
    • popImplicitThis

      public void popImplicitThis()
      Pops the top implicit-this flag, restoring the previous state.
    • isInSpecialConstructorCall

      public boolean isInSpecialConstructorCall()
      Returns true if the current context is inside a special constructor call (super(...) or this(...)).
    • pushInSpecialConstructorCall

      public void pushInSpecialConstructorCall()
      Enters a special constructor call context (super(...) or this(...)). Pushes state so that pop() will restore the previous context.