package org.glassfish.pfl.dynamic.codegen.impl ;
import java.io.PrintStream ;
import java.lang.reflect.Modifier ;
import java.util.List ;
import java.util.Map ;
import java.util.HashMap ;
import java.util.Collections ;
import java.util.ArrayList ;
import java.util.Comparator ;
import org.glassfish.pfl.dynamic.codegen.spi.Type ;
import org.glassfish.pfl.dynamic.codegen.spi.Signature ;
import org.glassfish.pfl.dynamic.codegen.spi.Variable ;
import org.glassfish.pfl.dynamic.codegen.spi.ClassInfo ;
import org.glassfish.pfl.dynamic.codegen.spi.MethodInfo ;
import org.glassfish.pfl.objectweb.asm.MethodVisitor ;
import org.glassfish.pfl.objectweb.asm.ClassWriter ;
import org.glassfish.pfl.objectweb.asm.Label ;
import org.glassfish.pfl.objectweb.asm.util.TraceMethodVisitor ;
import static java.lang.reflect.Modifier.* ;
import static org.glassfish.pfl.objectweb.asm.Opcodes.* ;
public final class ByteCodeUtility {
private ClassWriter cw ;
private MethodVisitor mv ;
private boolean debug ;
private PrintStream ps ;
private String methodName ;
private String methodSignature ;
public ByteCodeUtility( ClassWriter cw, ClassGeneratorImpl cg,
boolean debug, PrintStream ps ) {
this.cw = cw ;
this.mv = null ;
this.debug = debug ;
this.ps = ps ;
String[] interfaces = new String[cg.impls().size()] ;
int ctr=0 ;
for (Type impl : cg.impls()) {
interfaces[ctr++] =
ASMUtil.bcName(impl);
}
int modifiers = cg.modifiers() ;
if (cg.isInterface()) {
modifiers |= ACC_INTERFACE;
}
String superType = (cg.superType() == null) ?
ASMUtil.bcName( Type._Object() ) :
ASMUtil.bcName( cg.superType() ) ;
cw.visit( V1_5, modifiers, ASMUtil.bcName( cg.thisType() ),
null, superType, interfaces ) ;
cw.visitSource( cg.name().replace( '.', '/' ) + ".java", null ) ;
}
public void addField( FieldGenerator arg ) {
String descriptor = arg.type().signature() ;
cw.visitField( arg.modifiers(), arg.name(), descriptor, null, null ) ;
}
public ByteCodeUtility( ClassWriter cw, ClassGeneratorImpl cg ) {
this( cw, cg, false, System.out ) ;
}
private void dump() {
if (debug) {
List<String> data = TraceMethodVisitor.class.cast( mv ).getText() ;
ps.printf( "MethodVisitor calls for method %s%s\n",
methodName, methodSignature ) ;
for (String str : data) {
ps.print( str ) ;
}
}
}
public void emitMethodStart( MethodGenerator mg ) {
List<Type> types = new ArrayList<Type>() ;
for (Variable var : mg.arguments()) {
types.add( ((VariableInternal)var).type() ) ;
}
methodName = mg.name() ;
methodSignature =
Signature.make( mg.returnType(), types ).signature() ;
String[] strs = new String[mg.exceptions().size()] ;
int ctr = 0 ;
for (Type exception : mg.exceptions()) {
strs[ctr++] = ASMUtil.bcName( exception ) ;
}
mv = cw.visitMethod( mg.modifiers(), methodName, methodSignature, null,
strs ) ;
if (debug) {
mv = new TraceMethodVisitor(mv);
}
mv.visitCode() ;
}
private void emitLineNumberTable( MethodGenerator mg ) {
ASMUtil.LineNumberTable lnt = ASMUtil.lineNumberTable.get( mg ) ;
if (lnt != null) {
List<MyLabel> labels = new ArrayList( lnt.keySet() ) ;
Collections.sort( labels,
new Comparator<MyLabel>() {
@Override
public int compare( MyLabel l1, MyLabel l2 ) {
return l1.getOffset() - l2.getOffset() ;
}
}
) ;
int currentLineNum = -1 ;
for (MyLabel label : labels) {
int lineNum = lnt.get( label ) ;
if (lineNum != currentLineNum) {
currentLineNum = lineNum ;
mv.visitLineNumber( lineNum, label ) ;
}
}
}
}
private void emitLocalVariableTable( MethodGenerator mg ) {
ASMUtil.VariablesInMethod vm = ASMUtil.variablesInMethod.get( mg ) ;
for (Variable var : vm) {
Label start ;
Label end ;
Statement stmt = ((VariableInternal)var).getAncestor(
Statement.class ) ;
if (stmt == null) {
end = ASMUtil.returnLabel.get( mg ) ;
BlockStatement bs = mg.body() ;
if (bs.isEmpty()) {
start = end ;
} else {
List<Statement> stmts = bs.body() ;
Statement first = stmts.iterator().next() ;
start = ASMUtil.statementStartLabel.get( first ) ;
}
} else {
start = ASMUtil.statementStartLabel.get( stmt ) ;
end = ASMUtil.statementEndLabel.get( stmt ) ;
}
VariableInternal ivar = (VariableInternal)var ;
int index = ASMUtil.stackFrameSlot.get( ivar ) ;
mv.visitLocalVariable( ivar.ident(), ivar.type().signature(), null,
start, end, index ) ;
}
}
public void emitMethodEnd( MethodGenerator mg, Label returnLabel,
Variable returnVariable, boolean dump ) {
if ((mg.modifiers() & ABSTRACT) == 0) {
mv.visitLabel( returnLabel ) ;
if (returnVariable != null) {
EmitterFactory.Emitter emitter =
ASMUtil.getEmitter.get( (VariableInternal)returnVariable ) ;
assert emitter != null ;
emitter.evaluate( mv ) ;
}
emitReturn(
returnVariable == null
? Type._void()
: ((VariableInternal)returnVariable).type() ) ;
emitLineNumberTable( mg ) ;
emitLocalVariableTable( mg ) ;
}
mv.visitMaxs(0,0) ;
mv.visitEnd() ;
if (dump) {
dump();
}
mv = null ;
}
private void emitReturn( Type returnType ) {
if (returnType.equals(Type._void())) {
mv.visitInsn( RETURN ) ;
} else if (returnType.isPrimitive()) {
if (returnType.equals(Type._long())) {
mv.visitInsn( LRETURN ) ;
} else if (returnType.equals(Type._float())) {
mv.visitInsn( FRETURN ) ;
} else if (returnType.equals(Type._double())) {
mv.visitInsn( DRETURN ) ;
} else {
mv.visitInsn( IRETURN ) ;
}
} else {
mv.visitInsn( ARETURN ) ;
}
}
public void emitRet( Variable var ) {
VariableInternal ivar = (VariableInternal)var ;
assert ivar.type().equals( Type._Object() ) ;
Integer slot = ASMUtil.stackFrameSlot.get( ivar ) ;
assert slot != null ;
mv.visitVarInsn( RET, slot ) ;
}
public void emitConstantExpression( Type type, Object value ) {
if (type.equals(Type._null())) {
mv.visitInsn( ACONST_NULL ) ;
} else if (type.equals(Type._Class())) {
Type vtype = Type.class.cast( value ) ;
org.glassfish.pfl.objectweb.asm.Type atype =
org.glassfish.pfl.objectweb.asm.Type.getType( vtype.signature() ) ;
mv.visitLdcInsn( atype ) ;
} else if (type.equals( Type._String())) {
mv.visitLdcInsn( value ) ;
} else if (type.equals( Type._float() )) {
float val = Float.class.cast( value ).floatValue() ;
if (val == 0.0) {
mv.visitInsn(FCONST_0);
} else if (val == 1.0) {
mv.visitInsn(FCONST_1);
} else if (val == 2.0) {
mv.visitInsn(FCONST_2);
} else {
mv.visitLdcInsn(value);
}
} else if (type.equals( Type._double() )) {
double val = Double.class.cast( value ).doubleValue() ;
if (val == 0.0) {
mv.visitInsn(DCONST_0);
} else if (val == 1.0) {
mv.visitInsn(DCONST_1);
} else {
mv.visitLdcInsn(value);
}
} else if (type.equals( Type._long() )) {
long val = Long.class.cast( value ).longValue() ;
if (val == 0) {
mv.visitInsn(LCONST_0);
} else if (val == 1) {
mv.visitInsn(LCONST_1);
} else {
mv.visitLdcInsn(value);
}
} else if (type.equals( Type._boolean() )) {
mv.visitInsn(
Boolean.class.cast( value ).booleanValue()
? ICONST_1 : ICONST_0 ) ;
} else {
int val = Integer.class.cast( value ).intValue() ;
if (val == -1) {
mv.visitInsn(ICONST_M1);
} else if (val == 0) {
mv.visitInsn( ICONST_0);
} else if (val == 1) {
mv.visitInsn( ICONST_1);
} else if (val == 2) {
mv.visitInsn( ICONST_2);
} else if (val == 3) {
mv.visitInsn( ICONST_3);
} else if (val == 4) {
mv.visitInsn( ICONST_4);
} else if (val == 5) {
mv.visitInsn( ICONST_5);
} else if ((val >= Byte.MIN_VALUE) && (val <= Byte.MAX_VALUE)) {
mv.visitIntInsn( BIPUSH, val ) ;
} else if ((val >= Short.MIN_VALUE) && (val <= Short.MAX_VALUE)) {
mv.visitIntInsn( SIPUSH, val ) ;
} else {
mv.visitLdcInsn( value ) ;
}
}
}
public void emitThisExpression() {
mv.visitIntInsn( ALOAD, 0 ) ;
}
public void emitConditionalBranch( MyLabel falseBranch ) {
mv.visitJumpInsn( IFEQ, falseBranch ) ;
}
public void emitBranch( MyLabel target ) {
mv.visitJumpInsn( GOTO, target ) ;
}
public void emitLabel( Attribute<MyLabel> attr, Node node ) {
if (attr.isSet( node )) {
MyLabel label = attr.get( node ) ;
if (label.emitted()) {
if (debug) {
TraceMethodVisitor.class.cast(mv).getText().
add(" Already emitted label " + label);
}
} else {
int lineNumber = CodegenPrinter.lineNumberAttribute.get( node ) ;
if (lineNumber > 0) {
MethodGenerator mg = node.getAncestor( MethodGenerator.class ) ;
ASMUtil.LineNumberTable lnt = ASMUtil.lineNumberTable.get( mg ) ;
lnt.put( label, lineNumber ) ;
}
label.emitted( true ) ;
mv.visitLabel( label ) ;
}
}
}
public void emitNewCall( Type type ) {
String typeName = ASMUtil.bcName( type ) ;
mv.visitTypeInsn( NEW, typeName ) ;
mv.visitInsn( DUP ) ;
}
public void emitInstanceof( Type type ) {
String typeName = ASMUtil.bcName( type ) ;
mv.visitTypeInsn( INSTANCEOF, typeName ) ;
}
public void emitCast( Type from, Type to ) {
if (from.isPrimitive()) {
if (to.isPrimitive()) {
if (from.isNumber() && to.isNumber()) {
emitConversion(from, to);
} else {
throw new IllegalArgumentException("No conversion is possible from " +
from.name() + " to " + to.name());
}
} else {
throw new IllegalArgumentException( "Type " + from.name() +
" is a primitive type, but type " + to.name() +
" is a reference type: no conversion is possible" ) ;
}
} else {
if (to.isPrimitive()) {
throw new IllegalArgumentException( "Type " + from.name() +
" is a reference type, but type " + to.name() +
" is a primitive type: no conversion is possible" ) ;
} else {
String sig = to.isArray() ?
to.signature() :
ASMUtil.bcName(to) ;
mv.visitTypeInsn( CHECKCAST, sig ) ;
}
}
}
public void emitDup() {
mv.visitInsn( DUP ) ;
}
public void emitArrayStore() {
mv.visitInsn( AASTORE ) ;
}
public int typeCode( Type type ) {
if (type.equals(Type._boolean())) {
return T_BOOLEAN;
}
if (type.equals(Type._byte())) {
return T_BYTE;
}
if (type.equals(Type._char())) {
return T_CHAR;
}
if (type.equals(Type._short())) {
return T_SHORT;
}
if (type.equals(Type._int())) {
return T_INT;
}
if (type.equals(Type._long())) {
return T_LONG;
}
if (type.equals(Type._float())) {
return T_FLOAT;
}
if (type.equals(Type._double())) {
return T_DOUBLE;
}
throw new IllegalArgumentException(
"Can only get a NEWARRAY typecode for a primitive type" ) ;
}
public void emitNewArrayCall( Type type ) {
if (type.isPrimitive()) {
mv.visitIntInsn(NEWARRAY, typeCode(type));
} else {
mv.visitTypeInsn(ANEWARRAY,
ASMUtil.bcName(type));
}
}
public void emitStaticInvoke( Type type,
String name, Signature sig ) {
mv.visitMethodInsn( INVOKESTATIC, ASMUtil.bcName(type), name,
sig.signature() ) ;
}
public void emitInvoke( Type type, String name, Signature sig ) {
String sigString = sig.signature() ;
ClassInfo targetInfo ;
targetInfo = type.classInfo() ;
MethodInfo minfo = targetInfo.findMethodInfo( name, sig ) ;
if (minfo == null) {
throw new IllegalArgumentException("Could not find a method "
+ name +
" with signature " + sig + " in class " + targetInfo.name());
}
ClassInfo mcinfo = minfo.myClassInfo() ;
boolean privateMethod = Modifier.isPrivate( minfo.modifiers() ) ;
int opcode ;
if (mcinfo.isInterface()) {
opcode = INVOKEINTERFACE;
} else if (privateMethod) {
opcode = INVOKESPECIAL;
} else {
opcode = INVOKEVIRTUAL;
}
String typeName = ASMUtil.bcName(mcinfo.thisType()) ;
mv.visitMethodInsn( opcode, typeName, name, sigString ) ;
}
public void emitNewInvoke( Type type, Signature sig ) {
String typeName = ASMUtil.bcName(type) ;
mv.visitMethodInsn( INVOKESPECIAL, typeName,
CodeGeneratorUtil.CONSTRUCTOR_METHOD_NAME, sig.signature()) ;
}
public void emitSpecialInvoke( Type type, String name, Signature sig ) {
String typeName = ASMUtil.bcName(type) ;
mv.visitMethodInsn( INVOKESPECIAL, typeName,
name, sig.signature() ) ;
}
public void emitThrow() {
mv.visitInsn( ATHROW ) ;
}
public void emitExceptionTableEntry( Label start, Label end, Label handler,
Type exceptionType ) {
String exceptionTypeName =
exceptionType == null ? null : ASMUtil.bcName(exceptionType) ;
mv.visitTryCatchBlock( start, end, handler, exceptionTypeName ) ;
}
public void emitJsr( Label label ) {
mv.visitJumpInsn( JSR, label ) ;
}
public void callEmitter( EmitterFactory.Emitter emitter ) {
emitter.evaluate( mv ) ;
}
public void emitPop() {
mv.visitInsn( POP ) ;
}
private static Map<Type,Integer> typeIndex = new HashMap<Type,Integer>() ;
static {
typeIndex.put( Type._byte(), 0 ) ;
typeIndex.put( Type._short(), 1 ) ;
typeIndex.put( Type._char(), 2 ) ;
typeIndex.put( Type._int(), 3 ) ;
typeIndex.put( Type._long(), 4 ) ;
typeIndex.put( Type._float(), 5 ) ;
typeIndex.put( Type._double(), 6 ) ;
}
private static final EmitterFactory.Emitter E_NOP = new EmitterFactory.NullEmitter() ;
private static final EmitterFactory.Emitter E_I2B = new EmitterFactory.SimpleEmitter( I2B ) ;
private static final EmitterFactory.Emitter E_I2C = new EmitterFactory.SimpleEmitter( I2C ) ;
private static final EmitterFactory.Emitter E_I2S = new EmitterFactory.SimpleEmitter( I2S ) ;
private static final EmitterFactory.Emitter E_I2L = new EmitterFactory.SimpleEmitter( I2L ) ;
private static final EmitterFactory.Emitter E_I2F = new EmitterFactory.SimpleEmitter( I2F ) ;
private static final EmitterFactory.Emitter E_I2D = new EmitterFactory.SimpleEmitter( I2D ) ;
private static final EmitterFactory.Emitter E_L2I = new EmitterFactory.SimpleEmitter( L2I ) ;
private static final EmitterFactory.Emitter E_F2I = new EmitterFactory.SimpleEmitter( F2I ) ;
private static final EmitterFactory.Emitter E_D2I = new EmitterFactory.SimpleEmitter( D2I ) ;
private static final EmitterFactory.Emitter E_L2F = new EmitterFactory.SimpleEmitter( L2F ) ;
private static final EmitterFactory.Emitter E_L2D = new EmitterFactory.SimpleEmitter( L2D ) ;
private static final EmitterFactory.Emitter E_F2L = new EmitterFactory.SimpleEmitter( F2L ) ;
private static final EmitterFactory.Emitter E_D2L = new EmitterFactory.SimpleEmitter( D2L ) ;
private static final EmitterFactory.Emitter E_F2D = new EmitterFactory.SimpleEmitter( F2D ) ;
private static final EmitterFactory.Emitter E_D2F = new EmitterFactory.SimpleEmitter( D2F ) ;
private static final EmitterFactory.Emitter E_L2B = new EmitterFactory.CompoundEmitter(
E_L2I, E_I2B ) ;
private static final EmitterFactory.Emitter E_F2B = new EmitterFactory.CompoundEmitter(
E_F2I, E_I2B ) ;
private static final EmitterFactory.Emitter E_D2B = new EmitterFactory.CompoundEmitter(
E_D2I, E_I2B ) ;
private static final EmitterFactory.Emitter E_L2S = new EmitterFactory.CompoundEmitter(
E_L2I, E_I2S ) ;
private static final EmitterFactory.Emitter E_F2S = new EmitterFactory.CompoundEmitter(
E_F2I, E_I2S ) ;
private static final EmitterFactory.Emitter E_D2S = new EmitterFactory.CompoundEmitter(
E_D2I, E_I2S ) ;
private static final EmitterFactory.Emitter E_L2C = new EmitterFactory.CompoundEmitter(
E_L2I, E_I2C ) ;
private static final EmitterFactory.Emitter E_F2C = new EmitterFactory.CompoundEmitter(
E_F2I, E_I2C ) ;
private static final EmitterFactory.Emitter E_D2C = new EmitterFactory.CompoundEmitter(
E_D2I, E_I2C ) ;
EmitterFactory.Emitter[][] numericConversions = new EmitterFactory.Emitter[][] {
{ E_I2B, E_I2S, E_I2C, E_NOP, E_I2L, E_I2F, E_I2D },
{ E_I2B, E_I2S, E_I2C, E_NOP, E_I2L, E_I2F, E_I2D },
{ E_I2B, E_I2S, E_I2C, E_NOP, E_I2L, E_I2F, E_I2D },
{ E_I2B, E_I2S, E_I2C, E_NOP, E_I2L, E_I2F, E_I2D },
{ E_L2B, E_L2S, E_L2C, E_L2I, E_NOP, E_L2F, E_L2D },
{ E_F2B, E_F2S, E_F2C, E_F2I, E_F2L, E_NOP, E_F2D },
{ E_D2B, E_D2S, E_D2C, E_D2I, E_D2L, E_D2F, E_NOP }} ;
public void emitConversion( Type from, Type to ) {
if (!from.isNumber()) {
throw new IllegalArgumentException("From type " + from.name() +
" is not a numeric type");
}
if (!to.isNumber()) {
throw new IllegalArgumentException("To type " + to.name() +
" is not a numeric type");
}
int fromIndex = typeIndex.get( from ) ;
int toIndex = typeIndex.get( to ) ;
EmitterFactory.Emitter emitter = numericConversions[fromIndex][toIndex] ;
emitter.evaluate( mv ) ;
}
private static Map<ExpressionFactory.BinaryOperator,Map<Type,Integer>> opInstructions =
new HashMap<ExpressionFactory.BinaryOperator,Map<Type,Integer>>() ;
private static Map<ExpressionFactory.BinaryOperator,Integer> ifOpInstructions =
new HashMap<ExpressionFactory.BinaryOperator,Integer>() ;
static {
Map<Type,Integer> map = new HashMap<Type,Integer>() ;
map.put( Type._boolean(), ISUB ) ;
map.put( Type._byte(), ISUB ) ;
map.put( Type._char(), ISUB ) ;
map.put( Type._short(), ISUB ) ;
map.put( Type._int(), ISUB ) ;
map.put( Type._long(), LCMP ) ;
map.put( Type._float(), FCMPG ) ;
map.put( Type._double(), DCMPG ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.EQ, map ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.NE, map ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.GT, map ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.GE, map ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.LT, map ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.LE, map ) ;
map.clear() ;
map.put( Type._int(), IADD ) ;
map.put( Type._long(), LADD ) ;
map.put( Type._float(), FADD ) ;
map.put( Type._double(), DADD ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.PLUS, map ) ;
map.clear() ;
map.put( Type._int(), ISUB ) ;
map.put( Type._long(), LSUB ) ;
map.put( Type._float(), FSUB ) ;
map.put( Type._double(), DSUB ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.MINUS, map ) ;
map.clear() ;
map.put( Type._int(), IMUL ) ;
map.put( Type._long(), LMUL ) ;
map.put( Type._float(), FMUL ) ;
map.put( Type._double(), DMUL ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.TIMES, map ) ;
map.clear() ;
map.put( Type._int(), IDIV ) ;
map.put( Type._long(), LDIV ) ;
map.put( Type._float(), FDIV ) ;
map.put( Type._double(), DDIV ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.DIV, map ) ;
map.clear() ;
map.put( Type._int(), IREM ) ;
map.put( Type._long(), LREM ) ;
map.put( Type._float(), FREM ) ;
map.put( Type._double(), DREM ) ;
opInstructions.put( ExpressionFactory.BinaryOperator.REM, map ) ;
ifOpInstructions.put( ExpressionFactory.BinaryOperator.EQ, IFEQ ) ;
ifOpInstructions.put( ExpressionFactory.BinaryOperator.NE, IFNE ) ;
ifOpInstructions.put( ExpressionFactory.BinaryOperator.GT, IFGT ) ;
ifOpInstructions.put( ExpressionFactory.BinaryOperator.GE, IFGE ) ;
ifOpInstructions.put( ExpressionFactory.BinaryOperator.LT, IFLT ) ;
ifOpInstructions.put( ExpressionFactory.BinaryOperator.LE, IFLE ) ;
}
private void emitBooleanCodeForPrimitive( ExpressionFactory.BinaryOperatorExpression arg ) {
MyLabel internalLabel = new MyLabel() ;
MyLabel exitLabel = ASMByteCodeVisitor.nextLabel( arg ) ;
if (!ifOpInstructions.containsKey( arg.operator() )) {
throw new IllegalStateException(
"emitBooleanCode called with operator " +
arg + ", which is not a relational operator");
}
mv.visitJumpInsn( ifOpInstructions.get(arg.operator()), internalLabel ) ;
mv.visitInsn( ICONST_0 ) ;
mv.visitJumpInsn( GOTO, exitLabel ) ;
mv.visitLabel( internalLabel ) ;
mv.visitInsn( ICONST_1 ) ;
}
private void emitBooleanCodeForReference(
ExpressionFactory.BinaryOperatorExpression arg ) {
MyLabel internalLabel = new MyLabel() ;
MyLabel exitLabel = new MyLabel() ;
if (arg.operator() == ExpressionFactory.BinaryOperator.EQ) {
mv.visitJumpInsn( IF_ACMPEQ, internalLabel ) ;
} else if (arg.operator() == ExpressionFactory.BinaryOperator.NE) {
mv.visitJumpInsn( IF_ACMPNE, internalLabel ) ;
}
mv.visitInsn( ICONST_0 ) ;
mv.visitJumpInsn( GOTO, exitLabel ) ;
mv.visitLabel( internalLabel ) ;
mv.visitInsn( ICONST_1 ) ;
mv.visitLabel( exitLabel ) ;
}
public void emitBinaryOperator( ExpressionFactory.BinaryOperatorExpression arg ) {
Type type = ((ExpressionInternal)arg.left()).type() ;
ExpressionFactory.BinaryOperator op = arg.operator() ;
if (type.isPrimitive()) {
mv.visitInsn( opInstructions.get(op).get(type) ) ;
if (op.kind() == ExpressionFactory.BinaryOperatorKind.RELATIONAL) {
emitBooleanCodeForPrimitive( arg ) ;
}
} else {
if ((op == ExpressionFactory.BinaryOperator.EQ) ||
(op == ExpressionFactory.BinaryOperator.NE)) {
emitBooleanCodeForReference( arg ) ;
} else {
throw new IllegalStateException(
"Binary operator argument types are " + type.name()
+ " but operator is not EQ or NE" ) ;
}
}
}
}