/*
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.glassfish.pfl.dynamic.codegen.impl;
import java.io.PrintStream ;
import java.util.Map ;
import org.glassfish.pfl.objectweb.asm.ClassWriter ;
import org.glassfish.pfl.dynamic.codegen.spi.Type ;
import org.glassfish.pfl.dynamic.codegen.spi.Variable ;
import org.glassfish.pfl.basic.contain.Pair;
Visitor that is used to generate byte code for a class.
SetupVisitor must be called first before this
visitor can be called.
This visitor is also responsible for setting up the
bytecode versions of Variables, since we always define
variables before we reference them.
/** Visitor that is used to generate byte code for a class.
* SetupVisitor must be called first before this
* visitor can be called.
* <P>
* This visitor is also responsible for setting up the
* bytecode versions of Variables, since we always define
* variables before we reference them.
*/
public class ASMByteCodeVisitor extends TreeWalker {
private ClassWriter cw ;
private ByteCodeUtility bcu ;
private boolean debug ;
private PrintStream ps ;
public ASMByteCodeVisitor( TreeWalkerContext context, ClassWriter cw ) {
this( context, cw, false, System.out ) ;
}
public ASMByteCodeVisitor( TreeWalkerContext context,
ClassWriter cw, boolean debug, PrintStream ps ) {
super( context ) ;
context.push( this ) ;
this.cw = cw ;
this.debug = debug ;
this.ps = ps ;
}
private <T> T findNode( Class<T> cls, Node arg ) {
Node current = arg ;
while ((current != null) && !(cls.isInstance(current)))
current = current.parent() ;
assert current != null ;
return cls.cast( current ) ;
}
private MethodGenerator findMethodGenerator( Node arg ) {
MethodGenerator mg = findNode( MethodGenerator.class, arg ) ;
assert mg != null ;
return mg ;
}
private ClassGeneratorImpl findClassGenerator( Node arg ) {
ClassGeneratorImpl cg = findNode( ClassGeneratorImpl.class, arg ) ;
assert cg != null ;
return cg ;
}
// Returns the label of the next node (representing the next
// executable code) to execute after the code represented by Node.
static MyLabel nextLabel( Node node ) {
MyLabel result = null ;
Node pos = node ;
do {
// This method should only be called with children of
// MethodGenerator, and should not ascend further
// than the MethodGenerator in the tree.
assert pos != null ;
// next is non-null for statements in BlockStatement
// (except for the last statement in the list).
// For most other node types, next is null.
Node next = ASMUtil.next.get( pos ) ;
if (next == null) {
pos = pos.parent() ;
} else {
return ASMUtil.statementStartLabel.get( next ) ;
}
} while (!(pos instanceof MethodGenerator)) ;
// If we are here, pos is an instanceof MethodGenerator,
// and so it has a returnLabel, which is the appropriate nextLabel.
return ASMUtil.returnLabel.get( pos ) ;
}
// Node
@Override
public boolean preNode( Node arg ) {
return true ;
}
@Override
public void postNode( Node arg ) {
}
// ClassGeneratorImpl
@Override
public boolean preClassGenerator( ClassGeneratorImpl arg ) {
bcu = new ByteCodeUtility( cw, arg, debug, ps ) ;
return true ;
}
@Override
public boolean classGeneratorBeforeFields( ClassGeneratorImpl arg ) {
// Just make sure the fields get visited.
return true ;
}
@Override
public void classGeneratorBeforeInitializer( ClassGeneratorImpl arg ) {
// XXX need to setup the <clinit> method here
}
@Override
public void classGeneratorBeforeMethod( ClassGeneratorImpl arg ) {
}
@Override
public void classGeneratorBeforeConstructor( ClassGeneratorImpl arg ) {
}
@Override
public void postClassGenerator( ClassGeneratorImpl arg ) {
postNode( arg ) ;
}
// FieldGenerator (in class)
@Override
public boolean preFieldGenerator( FieldGenerator arg ) {
bcu.addField( arg ) ;
return true ;
}
// MethodGenerator
@Override
public boolean preMethodGenerator( MethodGenerator arg ) {
// XXX Is there anything different about handling constructors here?
// Every constructor must start with a call to super() or this(),
// but do we do this here? I think that may be better handled
// at a higher layer.
bcu.emitMethodStart( arg ) ;
for (Variable var : arg.arguments())
recordVariable( var ) ;
return true ;
}
@Override
public boolean methodGeneratorBeforeArguments( MethodGenerator arg ) {
// Don't need to visit arguments; they are handled in preMethodGenerator.
return false ;
}
@Override
public void postMethodGenerator( MethodGenerator arg ) {
bcu.emitMethodEnd( arg, ASMUtil.returnLabel.get(arg),
ASMUtil.returnVariable.get(arg), debug ) ;
}
// Statement
@Override
public boolean preStatement( Statement arg ) {
bcu.emitLabel( ASMUtil.statementStartLabel, arg ) ;
return true ;
}
@Override
public void postStatement( Statement arg ) {
bcu.emitLabel( ASMUtil.statementEndLabel, arg ) ;
postNode( arg ) ;
}
// ThrowStatement
@Override
public boolean preThrowStatement( ThrowStatement arg ) {
return preStatement( arg ) ;
}
@Override
public void postThrowStatement( ThrowStatement arg ) {
bcu.emitThrow() ;
postStatement( arg ) ;
}
// AssignmentStatement
@Override
public boolean preAssignmentStatement( AssignmentStatement arg ) {
// There are several cases here:
// 1. LHS is a local variable.
// 2. LHS is a static field reference.
// 3. LHS is a non-static field reference.
// 4. LHS is an array reference.
// It is easy to get confused between variable references and
// field references, since many fields references are syntactically
// the same in java as variable references. Do not make this
// mistake! Variables are always accessed with xLOAD/xSTORE
// instructions with a stack frame offset. Fields are always
// accessed with [PUT/GET][FIELD/STATIC] instructions with
// symbolic locations. It is only on the LHS of an assignment that
// this is really important, because the code generation needs to
// carefully take this into account.
ExpressionInternal lhs = arg.left() ;
ExpressionInternal rhs = arg.right() ;
assert lhs.isAssignable() ;
if (lhs instanceof Variable) {
rhs.accept( context.current() ) ;
} else if (lhs instanceof ExpressionFactory.NonStaticFieldAccessExpression) {
ExpressionFactory.NonStaticFieldAccessExpression expr =
ExpressionFactory.NonStaticFieldAccessExpression.class.cast( lhs ) ;
((ExpressionInternal)expr.target()).accept( context.current() ) ;
rhs.accept( context.current() ) ;
} else if (lhs instanceof ExpressionFactory.StaticFieldAccessExpression) {
rhs.accept( context.current() ) ;
} else if (lhs instanceof ExpressionFactory.ArrayIndexExpression) {
ExpressionFactory.ArrayIndexExpression expr =
ExpressionFactory.ArrayIndexExpression.class.cast( lhs ) ;
((ExpressionInternal)expr.expr()).accept( context.current() ) ;
((ExpressionInternal)expr.index()).accept( context.current() ) ;
rhs.accept( context.current() ) ;
} else {
throw new IllegalArgumentException(
"ASMByteCodeVisitor.preAssignmentStatement called with " +
"illegal left expression " + lhs ) ;
}
EmitterFactory.Emitter emitter = ASMUtil.emitter.get( lhs ) ;
bcu.callEmitter( emitter ) ;
preStatement( arg ) ;
return false ;
}
@Override
public void assignmentStatementBeforeLeftSide( AssignmentStatement arg ) {
// NOP
}
@Override
public void postAssignmentStatement( AssignmentStatement arg ) {
// NOP
}
// BlockStatement
@Override
public boolean preBlockStatement( BlockStatement arg ) {
// Make sure that this BlockStatement's lastStatement
// attribute is clear, so there is no confusion in
// blockStatementBeforeBodyStatement.
ASMUtil.lastStatement.set( arg, null ) ;
return preStatement( arg ) ;
}
@Override
public void blockStatementBeforeBodyStatement( BlockStatement arg, Statement stmt ) {
Statement lastStatement = ASMUtil.lastStatement.get( arg ) ;
popIfNeeded( lastStatement ) ;
ASMUtil.lastStatement.set( arg, stmt ) ;
}
@Override
public void postBlockStatement( BlockStatement arg ) {
Statement lastStatement = ASMUtil.lastStatement.get( arg ) ;
popIfNeeded( lastStatement ) ;
postStatement( arg ) ;
}
private void popIfNeeded( Statement lastStatement ) {
if (lastStatement != null) {
// If lastStatement is an expression which does not have void type,
// it will generate code that leaves one value on the stack.
// That's fine if arg represents the conditional in an if or while,
// or if the result of arg is an input to another expression.
// However, here such a value must be popped, because it is the
// result of an expression that was executed only for its side-effects.
if (lastStatement instanceof ExpressionInternal) {
ExpressionInternal expr = ExpressionInternal.class.cast( lastStatement ) ;
if (!expr.type().equals( Type._void() ))
bcu.emitPop() ;
}
}
}
// CaseBranch
@Override
public boolean preCaseBranch( CaseBranch arg ) {
return preBlockStatement( arg ) ;
}
@Override
public void caseBranchBeforeBodyStatement( CaseBranch arg ) {
// NOP: just visit the children
}
@Override
public void postCaseBranch( CaseBranch arg ) {
// NOP: just visit the children
postBlockStatement( arg ) ;
}
// DefinitionStatement
@Override
public boolean preDefinitionStatement( DefinitionStatement arg ) {
preStatement( arg ) ;
// TreeWalker visits arg.var() then arg.expr(), which is wrong here,
// so we will do the visiting in this method directly.
((ExpressionInternal)arg.expr()).accept( context.current() ) ;
((VariableInternal)arg.var()).accept( context.current() ) ;
recordVariable( arg.var() ) ;
return false ;
}
@Override
public boolean definitionStatementBeforeExpr( DefinitionStatement arg ) {
// NOP
return false ;
}
@Override
public void postDefinitionStatement( DefinitionStatement arg ) {
postStatement( arg ) ;
}
// IfStatement. Note that arg.truePart and arg.falsePart are
// always BlockStatement instances. We will supress the
// falsePart if it is empty.
@Override
public boolean preIfStatement( IfStatement arg ) {
return preStatement( arg ) ;
}
@Override
public void ifStatementBeforeTruePart( IfStatement arg ) {
// branch if TOS is false to statementStartLabel of false branch
bcu.emitConditionalBranch( ASMUtil.statementStartLabel.get( arg.falsePart() ) ) ;
}
@Override
public boolean ifStatementBeforeFalsePart( IfStatement arg ) {
bcu.emitBranch( nextLabel( arg ) ) ;
bcu.emitLabel( ASMUtil.statementStartLabel, arg.falsePart() ) ;
return true ;
}
@Override
public void postIfStatement( IfStatement arg ) {
postStatement( arg ) ;
}
private void emitJsrToFinallyBlock( TryStatement stmt ) {
BlockStatement fb = stmt.finalPart() ;
if (!fb.isEmpty()) {
bcu.emitJsr( ASMUtil.statementStartLabel.get( fb ) ) ;
}
}
// emit JSR's to enclosing finally blocks, innermost first.
private void callFinallyBlocks( Node arg ) {
Node current = arg ;
while (current != null) {
if (current instanceof TryStatement) {
emitJsrToFinallyBlock( TryStatement.class.cast( current ) ) ;
}
current = current.parent() ;
}
}
// BreakStatement
@Override
public boolean preBreakStatement( BreakStatement arg ) {
preStatement( arg ) ;
return true ;
}
@Override
public void postBreakStatement( BreakStatement arg ) {
Node current = arg.parent() ;
boolean foundBreak = false ;
while (current != null) {
if (current instanceof TryStatement) {
// Must call finally blocks on all enclosing try statements
emitJsrToFinallyBlock( TryStatement.class.cast( current ) ) ;
} else if (current instanceof SwitchStatement) {
// Branch past end of switch statement
bcu.emitBranch( nextLabel( current ) ) ;
} else if (current instanceof WhileStatement) {
// Branch past end of while statement
bcu.emitBranch( nextLabel( current ) ) ;
}
current = current.parent() ;
}
postStatement( arg ) ;
}
// ReturnStatement
@Override
public boolean preReturnStatement( ReturnStatement arg ) {
preStatement( arg ) ;
return true ;
}
@Override
public void postReturnStatement( ReturnStatement arg ) {
MethodGenerator mg = findMethodGenerator( arg ) ;
Variable var = ASMUtil.returnVariable.get( mg ) ;
if (var != null)
bcu.callEmitter( ASMUtil.setEmitter.get( (VariableInternal)var ) ) ;
callFinallyBlocks( arg ) ;
bcu.emitBranch( ASMUtil.returnLabel.get( mg ) ) ;
postStatement( arg ) ;
}
// SwitchStatement
@Override
public boolean preSwitchStatement( SwitchStatement arg ) {
preStatement( arg ) ;
// XXX implement me
// Here we will avoid using TreeWalker completely.
// Sketch:
// 1. Scan branches and add an attribute nextBranch to all
// branches that fall through (that is, the last statement
// in the branch is not a break, throw, or return).
// 2. Create a list of Pair<Integer,Label> that maps each
// case value to the label of the corresponding branch.
// 3. Sort the list by first elements of the Pairs.
// 4. If the density of the tables is at least .5,
// generate a tableswitch, else generate a lookupswitch.
// Note that missing values in a tableswitch either branch
// to default, or next(switch) if there is no default.
// Note that branching to next(switch) may require calling
// finally blocks.
// 5. Visit the branches (and label them) to generate the branch
// code.
postStatement( arg ) ;
return false ;
}
@Override
public boolean switchStatementBeforeCaseBranches( SwitchStatement arg ) {
// not called
return true ;
}
@Override
public boolean switchStatementBeforeDefault( SwitchStatement arg ) {
// not called
return true ;
}
@Override
public void postSwitchStatement( SwitchStatement arg ) {
// not called
}
// TryStatement
@Override
public boolean preTryStatement( TryStatement arg ) {
// Make sure statementStartLabel is emitted by preStatement
ASMUtil.statementStartLabel.get( arg.bodyPart() ) ;
ASMUtil.lastBlock.set( arg, arg.bodyPart() ) ;
return preStatement( arg ) ;
}
@Override
public void tryStatementBeforeBlock( TryStatement arg,
Type type, Variable var, BlockStatement block ) {
finishLastBlock( arg ) ;
ASMUtil.lastBlock.set( arg, block ) ;
// Start codegen for new block
// emit label for handler. Note that this means
// that preStatement on the block will NOT emit
// the label when the block is visited.
ASMUtil.statementStartLabel.get( block ) ;
bcu.emitLabel( ASMUtil.statementStartLabel, block ) ;
// emit store of exception into var
bcu.callEmitter( ASMUtil.setEmitter.get( (VariableInternal)var ) ) ;
recordVariable( var ) ;
}
private void finishLastBlock( TryStatement arg ) {
// emit label at end of previous block. If
// there is a final part, JSR to it, then emit
// branch to whatever is after the try statement.
BlockStatement lastBlock = ASMUtil.lastBlock.get( arg ) ;
ASMUtil.throwEndLabel.get( lastBlock ) ;
bcu.emitLabel( ASMUtil.throwEndLabel, lastBlock ) ;
if (!arg.finalPart().isEmpty()) {
bcu.emitJsr( ASMUtil.statementStartLabel.get( arg.finalPart() ) ) ;
}
bcu.emitBranch( nextLabel( arg ) ) ;
}
@Override
public boolean tryStatementBeforeFinalPart( TryStatement arg ) {
finishLastBlock( arg ) ;
if (!arg.finalPart().isEmpty()) {
// emit handler for uncaught exception:
ASMUtil.uncaughtExceptionHandler.get( arg ) ;
bcu.emitLabel( ASMUtil.uncaughtExceptionHandler, arg ) ;
VariableInternal uncaughtException =
(VariableInternal)ASMUtil.uncaughtException.get( arg ) ;
bcu.callEmitter( ASMUtil.setEmitter.get( uncaughtException ) ) ;
bcu.emitJsr( ASMUtil.statementStartLabel.get( arg.finalPart() ) ) ;
bcu.callEmitter( ASMUtil.getEmitter.get( uncaughtException ) ) ;
bcu.emitThrow() ;
// Start finally code: store TOS into return address
ASMUtil.statementStartLabel.get( arg.finalPart() ) ;
bcu.emitLabel( ASMUtil.statementStartLabel, arg.finalPart() ) ;
Variable ra = ASMUtil.returnAddress.get( arg ) ;
bcu.callEmitter( ASMUtil.setEmitter.get( (VariableInternal)ra ) ) ;
}
return true ;
}
@Override
public void postTryStatement( TryStatement arg ) {
if (!arg.finalPart().isEmpty()) {
// emit return to stored RA
Variable ra = ASMUtil.returnAddress.get( arg ) ;
bcu.emitRet( ra ) ;
}
// Emit handler table entries
// We need an entry for the try block for each exception handler
MyLabel start = ASMUtil.statementStartLabel.get( arg.bodyPart() ) ;
MyLabel end = ASMUtil.throwEndLabel.get( arg.bodyPart() ) ;
for (Map.Entry<Type,Pair<Variable,BlockStatement>> entry :
arg.catches().entrySet()) {
Pair<Variable,BlockStatement> pair = entry.getValue() ;
MyLabel handler = ASMUtil.statementStartLabel.get( pair.second() ) ;
bcu.emitExceptionTableEntry( start, end, handler,
((VariableInternal)pair.first()).type() ) ;
}
if (!arg.finalPart().isEmpty()) {
// The uncaught exception handler applies to the entire
// try-catch statement except for the uncaught exception
// handler and the finally block itself.
end = ASMUtil.uncaughtExceptionHandler.get( arg ) ;
bcu.emitExceptionTableEntry( start, end, end, null ) ;
}
postStatement( arg ) ;
}
// WhileStatement
@Override
public boolean preWhileStatement( WhileStatement arg ) {
// We always need the start label for the branch at the end
ASMUtil.statementStartLabel.get( arg ) ;
bcu.emitLabel( ASMUtil.statementStartLabel, arg ) ;
return preStatement( arg ) ;
}
@Override
public void whileStatementBeforeBody( WhileStatement arg ) {
// branch if TOS is false to next statement after loop.
bcu.emitConditionalBranch( nextLabel( arg ) ) ;
}
@Override
public void postWhileStatement( WhileStatement arg ) {
bcu.emitBranch( ASMUtil.statementStartLabel.get( arg ) ) ;
postStatement( arg ) ;
}
// ExpressionInternal
@Override
public boolean preExpression( ExpressionInternal arg ) {
return preStatement( arg ) ;
}
@Override
public void postExpression( ExpressionInternal arg ) {
postStatement( arg ) ;
}
private void recordVariable( Variable var ) {
MethodGenerator mg = ((VariableInternal)var).getAncestor(
MethodGenerator.class ) ;
if (mg == null)
throw new IllegalStateException(
"No MethodGenerator found!" ) ;
ASMUtil.VariablesInMethod vm = ASMUtil.variablesInMethod.get( mg ) ;
vm.add( var ) ;
}
// Variable
@Override
public boolean preVariable( Variable param ) {
VariableInternal arg = (VariableInternal)param ;
if (ASMUtil.emitter.isSet( arg ))
bcu.callEmitter( ASMUtil.emitter.get( arg ) ) ;
return preExpression( arg ) ;
}
@Override
public void postVariable( Variable arg ) {
postExpression( (VariableInternal)arg ) ;
}
// ConstantExpression
@Override
public boolean preConstantExpression( ExpressionFactory.ConstantExpression arg ) {
bcu.emitConstantExpression( arg.type(), arg.value() ) ;
return preExpression( arg ) ;
}
@Override
public void postConstantExpression( ExpressionFactory.ConstantExpression arg ) {
postExpression( arg ) ;
}
// VoidExpression
@Override
public boolean preVoidExpression( ExpressionFactory.VoidExpression arg ) {
return preExpression( arg ) ;
}
@Override
public void postVoidExpression( ExpressionFactory.VoidExpression arg ) {
postExpression( arg ) ;
}
// ThisExpression
@Override
public boolean preThisExpression( ExpressionFactory.ThisExpression arg ) {
bcu.emitThisExpression() ;
return preExpression( arg ) ;
}
@Override
public void postThisExpression( ExpressionFactory.ThisExpression arg ) {
postExpression( arg ) ;
}
// UnaryOperatorExpression
@Override
public boolean preUnaryOperatorExpression( ExpressionFactory.UnaryOperatorExpression arg ) {
// XXX implement me
return preExpression( arg ) ;
}
@Override
public void postUnaryOperatorExpression( ExpressionFactory.UnaryOperatorExpression arg ) {
// XXX implement me
postExpression( arg ) ;
}
// BinaryOperatorExpression
@Override
public boolean preBinaryOperatorExpression( ExpressionFactory.BinaryOperatorExpression arg ) {
return preExpression( arg ) ;
}
@Override
public void binaryOperatorExpressionBeforeRight(
ExpressionFactory.BinaryOperatorExpression arg ) {
// XXX if coercion is required AND arg.left type is not the required coercion type, emit coercion
}
@Override
public void postBinaryOperatorExpression( ExpressionFactory.BinaryOperatorExpression arg ) {
postExpression( arg ) ;
// XXX if coercion is required AND arg.right type is not the required coercion type, emit coercion
bcu.emitBinaryOperator( arg ) ;
}
// CastExpression
@Override
public boolean preCastExpression( ExpressionFactory.CastExpression arg ) {
return preExpression( arg ) ;
}
@Override
public void postCastExpression( ExpressionFactory.CastExpression arg ) {
bcu.emitCast( ((ExpressionInternal)arg.expr()).type(), arg.type() ) ;
postExpression( arg ) ;
}
// InstofExpression
@Override
public boolean preInstofExpression( ExpressionFactory.InstofExpression arg ) {
return preExpression( arg ) ;
}
@Override
public void postInstofExpression( ExpressionFactory.InstofExpression arg ) {
bcu.emitInstanceof( arg.itype() ) ;
postExpression( arg ) ;
}
// StaticCallExpression
@Override
public boolean preStaticCallExpression( ExpressionFactory.StaticCallExpression arg ) {
// TreeWalker visists the target then the args, which
// generates code that sets up the stack for the call. The target
// in this case is just a type, which generates no code.
return preExpression( arg ) ;
}
@Override
public void staticCallExpressionBeforeArg( ExpressionFactory.StaticCallExpression arg ) {
// NOP
}
@Override
public void postStaticCallExpression( ExpressionFactory.StaticCallExpression arg ) {
bcu.emitStaticInvoke( arg.target(), arg.ident(), arg.signature() ) ;
postExpression( arg ) ;
}
// NonStaticCallExpression
// ExpressionInternal arg.target()
// String arg.ident()
// Signature arg.signature()
// List<ExpressionInternal> args()
@Override
public boolean preNonStaticCallExpression( ExpressionFactory.NonStaticCallExpression arg ) {
// TreeWalker visists the target then the args, which
// generates code that sets up the stack for the call.
return preExpression( arg ) ;
}
@Override
public void nonStaticCallExpressionBeforeArg( ExpressionFactory.NonStaticCallExpression arg ) {
// NOP
}
@Override
public void postNonStaticCallExpression( ExpressionFactory.NonStaticCallExpression arg ) {
bcu.emitInvoke( ((ExpressionInternal)arg.target()).type(),
arg.ident(), arg.signature() ) ;
postExpression( arg ) ;
}
// NewObjExpression
@Override
public boolean preNewObjExpression( ExpressionFactory.NewObjExpression arg ) {
// Create the new object then duplicate it.
bcu.emitNewCall( arg.type() ) ;
// The arguments for the call are pushed by
// code generated by the visitor.
return preExpression( arg ) ;
}
@Override
public void newObjExpressionBeforeArg( ExpressionFactory.NewObjExpression arg ) {
// NOP
}
@Override
public void postNewObjExpression( ExpressionFactory.NewObjExpression arg ) {
// emit the required INVOKESPECIAL
bcu.emitNewInvoke( arg.type(), arg.signature() ) ;
postExpression( arg ) ;
}
// NewArrExpression
// Type ctype()
// ExpressionInternal size()
// List<ExpressionInternal> exprs()
// visit order:
// preNewArrExpression
// newArrExpressionBeforeSize
// newArrExpressionBeforeExpression*
// postNewArrExpression
// General plan:
// first, create array
// then, for each element expression:
// emit dup
// emit constant for index
// emit code for expression
// aastore
@Override
public boolean preNewArrExpression( ExpressionFactory.NewArrExpression arg ) {
// init counter
return preExpression( arg ) ;
}
@Override
public void newArrExpressionAfterSize( ExpressionFactory.NewArrExpression arg ) {
bcu.emitNewArrayCall( arg.ctype() ) ;
}
@Override
public void newArrExpressionBeforeExpression( ExpressionFactory.NewArrExpression arg ) {
bcu.emitDup() ;
int ctr = ASMUtil.ctr.get( arg ) ;
bcu.emitConstantExpression(Type._int(), ctr) ;
ASMUtil.ctr.set( arg, ++ctr ) ;
}
@Override
public void newArrExpressionAfterExpression( ExpressionFactory.NewArrExpression arg ) {
bcu.emitArrayStore() ;
}
@Override
public void postNewArrExpression( ExpressionFactory.NewArrExpression arg ) {
postExpression( arg ) ;
}
// SuperCallExpression
@Override
public boolean preSuperCallExpression( ExpressionFactory.SuperCallExpression arg ) {
bcu.emitThisExpression() ;
return preExpression( arg ) ;
}
@Override
public void superCallExpressionBeforeArg( ExpressionFactory.SuperCallExpression arg ) {
// NOP
}
@Override
public void postSuperCallExpression( ExpressionFactory.SuperCallExpression arg ) {
Type superType = findClassGenerator( arg ).superType() ;
bcu.emitSpecialInvoke( superType, arg.ident(), arg.signature() ) ;
postExpression( arg ) ;
}
// SuperObjExpression (super at start of constructor)
@Override
public boolean preSuperObjExpression( ExpressionFactory.SuperObjExpression arg ) {
bcu.emitThisExpression() ;
return preExpression( arg ) ;
}
@Override
public void superObjExpressionBeforeArg( ExpressionFactory.SuperObjExpression arg ) {
}
@Override
public void postSuperObjExpression( ExpressionFactory.SuperObjExpression arg ) {
Type superType = findClassGenerator( arg ).superType() ;
bcu.emitNewInvoke( superType, arg.signature() ) ;
postExpression( arg ) ;
}
// ThisObjExpression (this at start of constructor)
@Override
public boolean preThisObjExpression( ExpressionFactory.ThisObjExpression arg ) {
bcu.emitThisExpression() ;
return preExpression( arg ) ;
}
@Override
public void thisObjExpressionBeforeArg( ExpressionFactory.ThisObjExpression arg ) {
// NOP
}
@Override
public void postThisObjExpression( ExpressionFactory.ThisObjExpression arg ) {
Type type = findClassGenerator( arg ).thisType() ;
bcu.emitNewInvoke( type, arg.signature() ) ;
postExpression( arg ) ;
}
// Note that (Non)StaticFieldAccessExpression and ArrayIndexExpression can occur
// on either the left or right side of an assignment statement (or in other contexts,
// all of which are read accesses). The AssignmentStatement code handles all of the
// write acess cases, so we only handle read accesses in the following code.
// NonStaticFieldAccessExpression
@Override
public boolean preNonStaticFieldAccessExpression(
ExpressionFactory.NonStaticFieldAccessExpression arg ) {
return preExpression( arg ) ;
}
@Override
public void postNonStaticFieldAccessExpression(
ExpressionFactory.NonStaticFieldAccessExpression arg ) {
EmitterFactory.Emitter emitter = ASMUtil.emitter.get( arg ) ;
bcu.callEmitter( emitter ) ;
postExpression( arg ) ;
}
// StaticFieldAccessExpression
@Override
public boolean preStaticFieldAccessExpression(
ExpressionFactory.StaticFieldAccessExpression arg ) {
return preExpression( arg ) ;
}
@Override
public void postStaticFieldAccessExpression(
ExpressionFactory.StaticFieldAccessExpression arg ) {
EmitterFactory.Emitter emitter = ASMUtil.emitter.get( arg ) ;
bcu.callEmitter( emitter ) ;
postExpression( arg ) ;
}
// ArrayIndexExpression
@Override
public boolean preArrayIndexExpression( ExpressionFactory.ArrayIndexExpression arg ) {
return preExpression( arg ) ;
}
@Override
public void postArrayIndexExpression( ExpressionFactory.ArrayIndexExpression arg ) {
EmitterFactory.Emitter emitter = ASMUtil.emitter.get( arg ) ;
bcu.callEmitter( emitter ) ;
postExpression( arg ) ;
}
// ArrayLengthExpression
@Override
public boolean preArrayLengthExpression( ExpressionFactory.ArrayLengthExpression arg ) {
return preExpression( arg ) ;
}
@Override
public void postArrayLengthExpression( ExpressionFactory.ArrayLengthExpression arg ) {
postExpression( arg ) ;
bcu.callEmitter( EmitterFactory.makeEmitter( arg ) ) ;
}
// IfExpression.
@Override
public boolean preIfExpression( ExpressionFactory.IfExpression arg ) {
return preExpression( arg ) ;
}
@Override
public void ifExpressionBeforeTruePart( ExpressionFactory.IfExpression arg ) {
// branch if TOS is false to statementStartLabel of false branch
bcu.emitConditionalBranch( ASMUtil.statementStartLabel.get(
(ExpressionInternal)arg.falsePart() ) ) ;
}
@Override
public boolean ifExpressionBeforeFalsePart( ExpressionFactory.IfExpression arg ) {
bcu.emitBranch( nextLabel( arg ) ) ;
bcu.emitLabel( ASMUtil.statementStartLabel,
(ExpressionInternal)arg.falsePart() ) ;
return true ;
}
@Override
public void postIfExpression( ExpressionFactory.IfExpression arg ) {
postExpression( arg ) ;
}
}