/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package edu.umass.bc;
import org.objectweb.asm.*;
import edu.umass.pql.*;
import edu.umass.pql.container.PSet;
import edu.umass.pql.il.Arithmetic;
import edu.umass.pql.il.Field;
import edu.umass.pql.il.NoFail.Bool;
import edu.umass.pql.il.ReductionImpl;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.objectweb.asm.util.TraceClassVisitor;
/**
*
* @author Hilmar
*/
public class RuntimeCreator implements Opcodes, VarConstants, BcFlags {
/*
* compiler konnte erstellt werden => was weiter..?
*
* //benchmarks.webgraph.Generator.init(); in Bench.java musste auskommentiert werden => zuwenig heap..
*
* benchmarks in pql implementieren
* R s <- (0.123, 0.3242, ..)
* R boxplot(s)
* in allen benchmarks Manual.java
* versuchen, per makefile compiler zu erzeugen
* bool nochmal richtig
*
* ==============
*
* code etwas "aufräumen"
* Strings so einbauen, dass sie im Code der Ausgabe sichtbar sind..
*
* Notes:
* noch nicht implementiert: arrays, die in N_map / Default_n_map als inner_reductor verwendet werden..
* bei arrays, die %32 != 0 sind, kann es bei 0/0 abfragen zu problemen kommen.. (allgemein, darf auch nicht auf null abgefragt werden..)
*
* fehlende Implementierungen:
* ========
* (POLY_SIZE/SET_SIZE/MAP_SIZE/..S)
* JAVA_TYPE / INT / CHAR => typ überprüfung
* INSTANTIATE
* DisjunctiveBlock / BOOL / NOFAIL / NOT / FORALL
*/
public static final boolean quietRuntimeCreator = true;
public static final boolean useRuntimeCreator = true;
public static boolean alreadyInitialized = false;
private static Method pql_eval = null;
private static Join pql_query = null;
private static ASMFlagTranslations ast = new ASMFlagTranslations ();
private static ReturnBehaviorStack returnBehaviorStack;
private static int usedLocalVariables;
protected static ArrayList <Method> methods;
public static void init (Join new_query) {
pql_query = new_query;
pql_eval = null;
methods = new ArrayList <Method> ();
}
public static boolean test (Env env) {
try {
if (pql_eval == null) {
RuntimeClassLoader cl = new RuntimeClassLoader ();
Class c = cl.defineClass("Evaluator", genEvalFor(pql_query) );
for (int i=0; i<c.getMethods().length; i++) {
if (c.getMethods()[i].getName().equals("evaluate")) {
pql_eval = c.getMethods()[i];
break;
}
}
}
/*Method methodArg [] = new Method [methods.size()];
for (int i=0; i<methods.size(); i++)
methodArg[i] = methods.get(i);*/
Boolean result = (Boolean)pql_eval.invoke(null, new Object[] { env });
if (!quietRuntimeCreator)
System.out.println(" Ergebnis: " + result);
return result;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
private static byte[] genEvalFor (Join pql_query) throws Exception {
/*
ClassReader cr2 = new ClassReader("bc.RuntimeCreator");
ClassVisitor cv2 = new ClassWriter(cr2, 0);
PrintWriter pw2 = new PrintWriter(System.out);
TraceClassVisitor cw2 = new TraceClassVisitor(cv2, pw2);
cr2.accept(cw2, 0);
int i=0;
if (i != 3452) {
Thread.sleep(100);
throw new Exception("BREAK");
}*/
usedLocalVariables = 1;
returnBehaviorStack = new ReturnBehaviorStack ();
ClassWriter cv;
ClassVisitor cw = null;
//=====
if (quietRuntimeCreator) {
cv = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
cw = cv;
} else {
cv = new ClassWriter(ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
PrintWriter pw = new PrintWriter(System.out);
cw = new TraceClassVisitor(cv, pw);
}
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_6, ACC_PUBLIC, "Evaluator", null, "java/lang/Object", null);
cw.visitSource("Evaluator.java", null);
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(1, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitInsn(RETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable("this", "LEvaluator;", null, l0, l1, 0);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "evaluate", "(Ledu/umass/pql/Env;)Z", null, null);
mv.visitCode();
createASMCode (pql_query, mv);
mv.visitLdcInsn(new Integer(1));
mv.visitInsn(IRETURN);
//returnBehaviorStack.insertReturnCode(true, mv);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
return cv.toByteArray();
}
private static void createASMCode (Join query, MethodVisitor mv) throws Exception {
int flags = -1;
flags = query.accept(new JoinFlagsVisitor());
if ((flags & 0xE000) == 0) {
if ((flags & 0xFF00) <= TYPE_BITSSHR)
createArithmeticCode(mv, query, flags);
else
createComparisonCode(mv, query, flags);
}
else
createSpecialInstructionCode(mv, query, flags);
}
private static void createSpecialInstructionCode (MethodVisitor mv, Join query, int flags) throws Exception {
int type = flags & 0xFF;
int instruction = (flags & 0xFF00);
switch (instruction) {
case TYPE_CONJUCTIVE:
/*int backupUsedLocalVariables = usedLocalVariables, stackSizeBefore = returnBehaviorStack.getSize();
Join [] elements = ((AbstractBlock.PreConjunctive)query).getComponents();
Label endLabelConjuctive = new Label();
returnBehaviorStack.push(ReturnBehavior.getJumpBehavior(endLabelConjuctive));
for (int i=0; i<elements.length; i++ ) {
createASMCode(elements[i], mv);
}
usedLocalVariables = backupUsedLocalVariables;
while (returnBehaviorStack.getSize() > stackSizeBefore)
returnBehaviorStack.pop();
mv.visitLabel(endLabelConjuctive);
returnBehaviorStack.insertReturnCode(true, mv, returnBehaviorStack.getSize());*/
//int stackSizeBefore = returnBehaviorStack.getSize();
returnBehaviorStack.saveStack();
Join [] elements = ((AbstractBlock.PreConjunctive)query).getComponents();
for (int i=0; i<elements.length; i++ ) {
createASMCode(elements[i], mv);
}
returnBehaviorStack.restoreStack();
//returnBehaviorStack.insertReturnCode(true, mv);
break;
case TYPE_BOOL:
createASMCode( ((Bool)query).getComponentInternal(0), mv);
/*Label endLabelBool = new Label();
int backupUsedLocalVariablesBool = usedLocalVariables, stackSizeBeforeBool = returnBehaviorStack.getSize();
returnBehaviorStack.push(ReturnBehavior.getJumpBehavior(endLabelBool));
preliminaryStoreValue(mv, query.getArg(0));
mv.visitLdcInsn(new Integer(0));
storeValue(mv, query.getArg(0), TYPE_INT);
createASMCode( ((Bool)query).getComponentInternal(0), mv);
preliminaryStoreValue(mv, query.getArg(0));
mv.visitLdcInsn(new Integer(1));
storeValue(mv, query.getArg(0), TYPE_INT);
mv.visitLabel(endLabelBool);
usedLocalVariables = backupUsedLocalVariablesBool;
while (returnBehaviorStack.getSize() > stackSizeBeforeBool)
returnBehaviorStack.pop();*/
break;
case TYPE_RANGE_CONTAINS:
if ((query.getArg(2) & VAR_READ_FLAG) != 0) {
Label checkedLabel = new Label();
//check the range
for (int i=0; i<2; i++) {
pushValue(mv, query.getArg(i), type);
pushValue(mv, query.getArg(2), type);
if (type == TYPE_INT) mv.visitJumpInsn( (i == 0 ? IF_ICMPGE : IF_ICMPLE), checkedLabel);
else {
mv.visitInsn(LCMP);
mv.visitJumpInsn( (i == 0 ? IFGE : IFLE), checkedLabel);
}
}
returnBehaviorStack.insertReturnCode(false, mv);
mv.visitLabel(checkedLabel);
}
else {
pushValue(mv, query.getArg(1), type);
mv.visitVarInsn(ast.getSpecialCommand(TYPE_STORE, type), 1 + usedLocalVariables);
pushValue(mv, query.getArg(0), type);
mv.visitVarInsn(ast.getSpecialCommand(TYPE_STORE, type), (type == TYPE_LONG ? 3 : 2) + usedLocalVariables );
Label iterationLabel = new Label();
Label checkLabel = new Label();
Label endLabel = new Label();
mv.visitJumpInsn(GOTO, checkLabel);
mv.visitLabel(iterationLabel);
mv.visitVarInsn(ast.getSpecialCommand(TYPE_LOAD, type), (type == TYPE_LONG ? 3 : 2) + usedLocalVariables );
if (type == TYPE_INT) mv.visitLdcInsn(new Integer(1));
else mv.visitLdcInsn(new Long(1));
mv.visitInsn( ast.getArithmeticInstruction(TYPE_ADD, type) );
mv.visitVarInsn(ast.getSpecialCommand(TYPE_STORE, type), (type == TYPE_LONG ? 3 : 2) + usedLocalVariables );
mv.visitLabel(checkLabel);
//mv.visitInsn( ast.getStackCommand(DUP, type) );
preliminaryStoreValue(mv, query.getArg(2));
mv.visitVarInsn(ast.getSpecialCommand(TYPE_LOAD, type), (type == TYPE_LONG ? 3 : 2) + usedLocalVariables );
storeValue(mv, query.getArg(2), type);
mv.visitVarInsn(ast.getSpecialCommand(TYPE_LOAD, type), 1 + usedLocalVariables );
mv.visitVarInsn(ast.getSpecialCommand(TYPE_LOAD, type), (type == TYPE_LONG ? 3 : 2) + usedLocalVariables );
//storeValueWithoutPreliminary(mv, query.getArg(2), type);
//mv.visitInsn( ast.getStackCommand(DUP_X1, type) );
//mv.visitInsn( ast.getStackCommand(DUP_X1, type) );
if (type == TYPE_INT) mv.visitJumpInsn(IF_ICMPGE, endLabel);
else {
mv.visitInsn(LCMP);
mv.visitJumpInsn(IFGE, endLabel);
}
//mv.visitInsn( ast.getStackCommand(POP, type) );
//mv.visitInsn( ast.getStackCommand(POP, type) );
returnBehaviorStack.insertReturnCode(false, mv);
mv.visitLabel(endLabel);
returnBehaviorStack.push( ReturnBehavior.getJumpBehavior(iterationLabel) );
usedLocalVariables += (type == TYPE_LONG ? 4 : 2);
}
break;
case TYPE_REDUCTION:
/*ReductionImpl extends Reduction
{
public static final boolean DEBUG = false;
protected Join body;
protected int initialised_count;
protected Reductor[] reductors;*/
Join body = ((ReductionImpl)query).getComponentInternal(0);
Reductor[] reductors = ((ReductionImpl)query).getReductors();
int startUsedLocalVariables = usedLocalVariables;
int reductorsArguments [][] = new int [reductors.length][3];
for (int i=0; i<reductors.length; i++) {
int reductorFlags = reductors[i].accept(new ReductorFlagsVisitor() );
if ((reductorFlags & 0xFF00) == REDUCTOR_EXISTS) {
preliminaryStoreValue(mv, reductors[i].getArg( 1 ));
mv.visitLdcInsn(new Integer(0));
storeValue(mv, reductors[i].getArg( 1 ), TYPE_INT);
//reductorsArguments[i][0] = reductors[i].getArg( 0 );
reductorsArguments[i][1] = reductors[i].getArg( 1 );
reductorsArguments[i][2] = reductorFlags;
} else if ((reductorFlags & 0xFF00) == REDUCTOR_METHOD_ADAPTER) {
reductorsArguments[i][0] = reductors[i].getArg( 0 );
reductorsArguments[i][1] = reductors[i].getArg( 1 );
reductorsArguments[i][2] = reductorFlags;
} else {
if ((reductorFlags & 0xFF00) == REDUCTOR_ARRAY)
{
mv.visitLdcInsn(0);
mv.visitVarInsn(ISTORE, 1 + usedLocalVariables );
++usedLocalVariables;
mv.visitIntInsn(BIPUSH, 32);
if ((reductorFlags & 0xFF) == TYPE_OBJECT)
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
else
mv.visitIntInsn(NEWARRAY, ast.getReductorArray(reductorFlags));
}
else {
mv.visitTypeInsn(NEW, ast.getReductorTypeName(reductorFlags));
mv.visitInsn(DUP);
if ((reductorFlags & 0xFF00) != REDUCTOR_DEFAULTMAP)
mv.visitMethodInsn(INVOKESPECIAL, ast.getReductorTypeName(reductorFlags), "<init>", "()V");
else {
pushValue(mv, reductors[i].getArg(0), TYPE_OBJECT);
mv.visitMethodInsn(INVOKESPECIAL, ast.getReductorTypeName(reductorFlags), "<init>", "(Ljava/lang/Object;)V");
}
}
mv.visitVarInsn(ASTORE, 1 + usedLocalVariables );
preliminaryStoreValue (mv, reductors[i].getArg( ((reductorFlags & 0xFF00) == REDUCTOR_SET ? 1 : 2) + ((reductorFlags & 0xFF00) == REDUCTOR_DEFAULTMAP ? 1 : 0) ) );
mv.visitVarInsn(ALOAD, 1 + usedLocalVariables );
storeValue (mv, reductors[i].getArg( ((reductorFlags & 0xFF00) == REDUCTOR_SET ? 1 : 2) + ((reductorFlags & 0xFF00) == REDUCTOR_DEFAULTMAP ? 1 : 0) ), TYPE_OBJECT);
reductorsArguments[i][0] = reductors[i].getArg( 0 + ((reductorFlags & 0xFF00) == REDUCTOR_DEFAULTMAP ? 1 : 0) );
if ((reductorFlags & 0xFF00) != REDUCTOR_SET)
reductorsArguments[i][1] = reductors[i].getArg( 1 + ((reductorFlags & 0xFF00) == REDUCTOR_DEFAULTMAP ? 1 : 0) );
reductorsArguments[i][2] = reductorFlags;
++usedLocalVariables;
if ((reductorFlags & 0xFF0000) == WITH_INNER_REDUCTOR)
reductors[i] = reductors[i].getInnerReductor();
}
}
Label endLabelReduction = new Label();
returnBehaviorStack.saveStack();
returnBehaviorStack.push( ReturnBehavior.getReductionBehavior(endLabelReduction, startUsedLocalVariables, reductorsArguments, reductors ) );
createASMCode(body, mv);
returnBehaviorStack.insertReturnCode(true, mv);
returnBehaviorStack.restoreStack();
//usedLocalVariables = startUsedLocalVariables;
mv.visitLabel(endLabelReduction);
returnBehaviorStack.insertReturnCode(true, mv);
break;
case TYPE_CONTAINS:
case TYPE_LOOKUP:
case TYPE_ARRAY_LOOKUP:
//final int startIndex = (instruction == TYPE_CONTAINS ? 5 : 10);
final int elementLength = (instruction == TYPE_CONTAINS ? 1 : 2);
insertComment(mv, (instruction == TYPE_CONTAINS ? "START CONTAINS" : "START LOOKUP") );
int source_ty = (query.getArg(1) >> VAR_TABLE_SHIFT) & VAR_TABLE_MASK;
if (instruction == TYPE_ARRAY_LOOKUP)
source_ty = type;
Label nextIteration = new Label();
Label finishContains = new Label();
pushValue(mv, query.getArg(0), TYPE_OBJECT);
if (instruction != TYPE_ARRAY_LOOKUP) {
mv.visitInsn(DUP);
mv.visitTypeInsn(INSTANCEOF, ast.getContainerName(flags));
Label isInstance = new Label();
mv.visitJumpInsn(IFNE, isInstance);
//mv.visitTypeInsn(CHECKCAST, ast.getJavaContainerName(flags) );
//mv.visitTypeInsn(CHECKCAST, "java/util/HashSet" );
pushValue(mv, query.getArg(1), TYPE_OBJECT);
mv.visitMethodInsn(INVOKEINTERFACE, ast.getJavaContainerName(flags), ast.getJavaContainerMethodName(flags), (instruction == TYPE_CONTAINS ? "(Ljava/lang/Object;)Z" : "(Ljava/lang/Object;)Ljava/lang/Object;") );
//mv.visitMethodInsn(INVOKEVIRTUAL, ast.getJavaContainerName(flags), ast.getJavaContainerMethodName(flags), (instruction == TYPE_CONTAINS ? "(Ljava/lang/Object;)Z" : "(Ljava/lang/Object;)Ljava/lang/Object;") );
Label javaComparisonFailed = new Label();
if (instruction == TYPE_CONTAINS)
mv.visitJumpInsn(IFEQ, javaComparisonFailed);
else {
mv.visitInsn(DUP);
Label javaComparisonNotNull = new Label();
mv.visitJumpInsn(IFNONNULL, javaComparisonNotNull);
mv.visitInsn(POP);
mv.visitJumpInsn(GOTO, javaComparisonFailed);
mv.visitLabel(javaComparisonNotNull);
pushValue(mv, query.getArg(2), TYPE_OBJECT);
//returnBehaviorStack.saveStack();
//returnBehaviorStack.push(ReturnBehavior.getJumpBehavior(javaComparisonFailed));
createComparisonCode(mv, null, TYPE_EQ | TYPE_OBJECT, ReturnBehavior.getJumpBehavior(javaComparisonFailed));
//returnBehaviorStack.restoreStack();
}
returnBehaviorStack.insertReturnCode(true, mv);
mv.visitJumpInsn(GOTO, finishContains);
mv.visitLabel(javaComparisonFailed);
returnBehaviorStack.insertReturnCode(false, mv);
mv.visitJumpInsn(GOTO, finishContains);
mv.visitLabel(isInstance);
mv.visitTypeInsn(CHECKCAST, ast.getContainerName(flags) );
}
//returnBehaviorStack.saveStack();
//returnBehaviorStack.push(ReturnBehavior.getJumpBehavior(nextIteration));
if (instruction != TYPE_ARRAY_LOOKUP)
mv.visitMethodInsn(INVOKEVIRTUAL, ast.getContainerName(flags), "getRepresentation", "()[Ljava/lang/Object;" );
mv.visitInsn(DUP);
mv.visitVarInsn(ASTORE, 1 + usedLocalVariables );
if (instruction == TYPE_ARRAY_LOOKUP)
mv.visitTypeInsn(CHECKCAST, "[" + ast.getTypeSpecifier( (type) ) );
mv.visitInsn(ARRAYLENGTH);
//mv.visitLdcInsn(new Integer(arrayLength));
//mv.visitInsn(ISUB);
//mv.visitLdcInsn( new Integer(startIndex) );
mv.visitLdcInsn( new Integer(0) );
Label startLoop = new Label();
mv.visitLabel(startLoop);
mv.visitInsn(DUP2);
Label endArrayCheck = new Label();
mv.visitJumpInsn(IF_ICMPEQ, endArrayCheck);
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, 1 + usedLocalVariables );
if (instruction == TYPE_ARRAY_LOOKUP)
mv.visitTypeInsn(CHECKCAST, "[" + ast.getTypeSpecifier( (type) ) );
mv.visitInsn(SWAP);
mv.visitInsn(ast.getArrayInstruction(ARRAY_INSTR_LOAD| (instruction != TYPE_ARRAY_LOOKUP ? TYPE_OBJECT : type) ));
Label elementIsNull = new Label();
if ((instruction != TYPE_ARRAY_LOOKUP ? TYPE_OBJECT : type) == TYPE_OBJECT) {
mv.visitInsn(DUP);
mv.visitJumpInsn(IFNULL, elementIsNull);
}
if ( (query.getArg(1) & VAR_READ_FLAG) != 0 ) {
//if (((query.getArg(1) >> VAR_TABLE_SHIFT) & VAR_TABLE_MASK) != TYPE_WILDCARD) {
if (instruction != TYPE_ARRAY_LOOKUP)
castValue(mv, TYPE_OBJECT, source_ty );
pushValue(mv, query.getArg(1), source_ty);
createComparisonCode(mv, null, TYPE_EQ | source_ty, ReturnBehavior.getJumpBehavior(nextIteration));
} else
mv.visitInsn(POP);
if (instruction == TYPE_LOOKUP || instruction == TYPE_ARRAY_LOOKUP) {
mv.visitInsn(DUP);
mv.visitLdcInsn(new Integer(1));
mv.visitInsn(IADD);
mv.visitVarInsn(ALOAD, 1 + usedLocalVariables );
if (instruction == TYPE_ARRAY_LOOKUP)
mv.visitTypeInsn(CHECKCAST, "[" + ast.getTypeSpecifier( (type) ) );
mv.visitInsn(SWAP);
mv.visitInsn(ast.getArrayInstruction(ARRAY_INSTR_LOAD|(instruction != TYPE_ARRAY_LOOKUP ? TYPE_OBJECT : type)));
if ((instruction != TYPE_ARRAY_LOOKUP ? TYPE_OBJECT : type) == TYPE_OBJECT) {
mv.visitInsn(DUP);
mv.visitJumpInsn(IFNULL, elementIsNull);
}
if ( (query.getArg(2) & VAR_READ_FLAG) != 0 ) {
//if (((query.getArg(1) >> VAR_TABLE_SHIFT) & VAR_TABLE_MASK) != TYPE_WILDCARD) {
if (instruction != TYPE_ARRAY_LOOKUP)
castValue(mv, TYPE_OBJECT, source_ty );
pushValue(mv, query.getArg(2), source_ty);
createComparisonCode(mv, null, TYPE_EQ | source_ty, ReturnBehavior.getJumpBehavior(nextIteration));
} else
mv.visitInsn(POP);
}
//returnBehaviorStack.restoreStack();
mv.visitInsn(POP);
mv.visitInsn(POP);
returnBehaviorStack.insertReturnCode(true, mv);
mv.visitJumpInsn(GOTO, finishContains);
mv.visitLabel(elementIsNull);
mv.visitInsn(POP);
mv.visitLabel(nextIteration);
mv.visitLdcInsn(new Integer(elementLength));
mv.visitInsn(IADD);
mv.visitJumpInsn(GOTO, startLoop);
mv.visitLabel(endArrayCheck);
mv.visitInsn(POP);
mv.visitInsn(POP);
returnBehaviorStack.insertReturnCode(false, mv);
mv.visitLabel(finishContains);
break;
case TYPE_POLY_LOOKUP:
insertComment(mv, "START POLY_LOOKUP" );
pushValue(mv, query.getArg(0), TYPE_OBJECT);
/*
* case TYPE_INT:
return "I";
case TYPE_LONG:
return "J";
case TYPE_DOUBLE:
return "D";
case TYPE_OBJECT:
return "Ljava/lang/Object;";
case TYPE_STRING:
return "Ljava/lang/String;";
case TYPE_CHAR:
return "C";
case TYPE_SHORT:
return "S";
case TYPE_BYTE:
return "B";
case TYPE_BOOLEAN:
return "Z";
case TYPE_FLOAT:
return "F";
*/
final String [][] checkInstances = { {"java/util/Map", "java/util/Set", "edu/umass/pql/container/PMap", "edu/umass/pql/container/PDefaultMap"}, {"[I"}, {"[J"}, {"[D"}, {"[C"}, {"[S"}, {"[B"}, {"[Z"}, {"[F"}, {"[Ljava/lang/Object;"} };
final int [] instanceFlags = {TYPE_LOOKUP, TYPE_ARRAY_LOOKUP|TYPE_INT, TYPE_ARRAY_LOOKUP|TYPE_LONG, TYPE_ARRAY_LOOKUP|TYPE_DOUBLE, TYPE_ARRAY_LOOKUP|TYPE_CHAR, TYPE_ARRAY_LOOKUP|TYPE_SHORT, TYPE_ARRAY_LOOKUP|TYPE_BYTE, TYPE_ARRAY_LOOKUP|TYPE_BOOLEAN, TYPE_ARRAY_LOOKUP|TYPE_FLOAT, TYPE_ARRAY_LOOKUP|TYPE_OBJECT};
Label endCheck = new Label();
for (int i=0; i<checkInstances.length; i++) {
Label nextCheck = new Label();
Label validSubCheck = new Label();
for (int j=0; j<checkInstances[i].length; j++) {
mv.visitInsn(DUP);
mv.visitTypeInsn(INSTANCEOF, checkInstances[i][j]);
mv.visitJumpInsn(IFNE, validSubCheck);
if (j == checkInstances[i].length-1)
mv.visitJumpInsn(GOTO, nextCheck);
}
mv.visitLabel(validSubCheck);
mv.visitInsn(POP);
createSpecialInstructionCode(mv, query, instanceFlags[i]);
mv.visitJumpInsn(GOTO, endCheck);
mv.visitLabel(nextCheck);
}
mv.visitInsn(POP);
mv.visitTypeInsn(NEW, "java/lang/Exception");
mv.visitInsn(DUP);
mv.visitLdcInsn(new String("the specified object is not a valid object for POLY_LOOKUP."));
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Exception", "<init>", "(Ljava/lang/String;)V");
mv.visitInsn(ATHROW);
mv.visitLabel(endCheck);
break;
case TYPE_COERCION:
insertComment(mv, "START COERCION" );
preliminaryStoreValue(mv, query.getArg(1));
pushValue(mv, query.getArg(0), (type != TYPE_FLOAT ? TYPE_INT : TYPE_DOUBLE));
castValue(mv, (type != TYPE_FLOAT ? TYPE_INT : TYPE_DOUBLE), type);
storeValue(mv, query.getArg(1), (type != TYPE_FLOAT ? TYPE_INT : TYPE_FLOAT) );
break;
case TYPE_FIELD:
insertComment(mv, "START FIELD" );
Object preField = ((Field)query).getField();
if (!(preField instanceof java.lang.reflect.Field))
throw new Exception("Field member has to be instance of java.lang.reflect.Field");
java.lang.reflect.Field field = ((java.lang.reflect.Field)preField);
String fieldName = field.getType().getName();
Label notInstance = new Label();
if ( (query.getArg(1) & VAR_READ_FLAG) == 0 ) {
preliminaryStoreValue(mv, query.getArg(1));
pushValue(mv, query.getArg(0), TYPE_OBJECT);
mv.visitInsn(DUP);
mv.visitTypeInsn(INSTANCEOF, field.getDeclaringClass().getName().replace(".", "/") );
Label isInstance = new Label();
mv.visitJumpInsn(IFNE, isInstance);
mv.visitInsn(POP);
mv.visitInsn(POP);
mv.visitJumpInsn(GOTO, notInstance);
mv.visitLabel(isInstance);
mv.visitTypeInsn(CHECKCAST, field.getDeclaringClass().getName().replace(".", "/") );
mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace(".", "/"), field.getName(), ast.fieldNameToTypeName(fieldName) );
storeValue(mv, query.getArg(1), ast.fieldNameToType(fieldName));
} else {
pushValue(mv, query.getArg(0), TYPE_OBJECT);
mv.visitInsn(DUP);
mv.visitTypeInsn(INSTANCEOF, field.getDeclaringClass().getName().replace(".", "/") );
mv.visitJumpInsn(IFEQ, notInstance);
mv.visitTypeInsn(CHECKCAST, field.getDeclaringClass().getName().replace(".", "/") );
mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace(".", "/"), field.getName(), ast.fieldNameToTypeName(fieldName) );
pushValue(mv, query.getArg(1), ast.fieldNameToType(fieldName));
createComparisonCode(mv, null, TYPE_EQ | ast.fieldNameToType(fieldName));
}
Label endField = new Label();
mv.visitJumpInsn(GOTO, endField);
mv.visitLabel(notInstance);
mv.visitInsn(POP);
returnBehaviorStack.insertReturnCode(false, mv);
mv.visitLabel(endField);
break;
default:
throw new Exception("unknown instruction (code: " + instruction + ")");
}
}
private static void createArithmeticCode (MethodVisitor mv, Join query, int flags) throws Exception {
int type = flags & 0xFF;
int instruction = (flags & 0xFF00);
int totalArgs = ((instruction != TYPE_BITINV && instruction != TYPE_NEG) ? 3 : 2);
if ( (query.getArg(totalArgs-1) & VAR_READ_FLAG) == 0 )
preliminaryStoreValue(mv, query.getArg(totalArgs-1));
//push one or two values to calculate (argument-amount depends on the operator)
pushValue(mv, query.getArg(0), type);
if (instruction != TYPE_BITINV && instruction != TYPE_NEG) {
if ((instruction == TYPE_BITSHL || instruction == TYPE_BITSHR || instruction == TYPE_BITSSHR) && type == TYPE_LONG)
pushValue(mv, query.getArg(1), TYPE_INT);
else
pushValue(mv, query.getArg(1), type);
}
if (instruction == TYPE_BITINV) {
if (type == TYPE_INT) mv.visitLdcInsn(new Integer(-1));
else if (type == TYPE_LONG) mv.visitLdcInsn(new Long(-1));
else throw new Exception("this combination of instruction and type is not implemented (yet).");
}
//divisor = 0 ?
if (instruction == TYPE_DIV || instruction == TYPE_MOD) {
Label l1 = new Label();
if (type == TYPE_DOUBLE) {
mv.visitInsn(DUP2);
mv.visitInsn(DCONST_0);
mv.visitInsn(DCMPG);
} else if (type == TYPE_LONG) {
mv.visitInsn(DUP2);
mv.visitInsn(LCONST_0);
mv.visitInsn(LCMP);
} else if (type == TYPE_INT)
mv.visitInsn(DUP);
mv.visitJumpInsn(IFNE, l1);
for (int i=0; i<2; i++) {
if (type == TYPE_INT)
mv.visitInsn(POP);
else
mv.visitInsn(POP2);
}
//pop values, before return
if ( (query.getArg(totalArgs-1) & VAR_READ_FLAG) == 0 ) {
mv.visitInsn(POP);
mv.visitInsn(POP);
}
returnBehaviorStack.insertReturnCode(false, mv);
mv.visitLabel(l1);
}
//calculate solution
mv.visitInsn( ast.getArithmeticInstruction( instruction, type) );
//write-flag => write and return true / otherwise check and return true when solution is correct
if ( (query.getArg(totalArgs-1) & VAR_READ_FLAG) == 0 )
storeValue(mv, query.getArg(totalArgs-1), type);
else {
pushValue(mv, query.getArg(totalArgs-1), type);
Label l0 = new Label();
if (type == TYPE_DOUBLE)
mv.visitInsn(DCMPG);
else if (type == TYPE_LONG)
mv.visitInsn(LCMP);
else if (type == TYPE_INT)
mv.visitInsn( ast.getArithmeticInstruction( TYPE_SUB, type) );
mv.visitJumpInsn(IFEQ, l0);
returnBehaviorStack.insertReturnCode(false, mv);
mv.visitLabel(l0);
}
returnBehaviorStack.insertReturnCode(true, mv);
}
private static void createComparisonCode (MethodVisitor mv, Join query, int flags) throws Exception {
createComparisonCode (mv, query, flags, null);
}
private static void createComparisonCode (MethodVisitor mv, Join query, int flags, ReturnBehavior individualReturnBehavior) throws Exception {
int type = flags & 0xFF;
int instruction = (flags & 0xFF00);
/*pushValue(mv, query.getArg(0), type);
insertDebugInformation(mv, "Nummer 1: ");
insertDebugInformation(mv, TYPE_DOUBLE);
pushValue(mv, query.getArg(1), type);
insertDebugInformation(mv, "Nummer 2: ");
insertDebugInformation(mv, TYPE_DOUBLE);*/
Label endComparisonLabel = new Label();
if (query != null && (query.getArg(1) & VAR_READ_FLAG) == 0 && instruction == TYPE_EQ) {
preliminaryStoreValue (mv, query.getArg(1));
pushValue(mv, query.getArg(0), type);
storeValue (mv, query.getArg(1), type);
} else {
if (query != null) {
pushValue(mv, query.getArg(0), type);
pushValue(mv, query.getArg(1), type);
}
Label falseLabel = new Label();
Label endLabel = new Label();
if (type == TYPE_FLOAT) {
mv.visitInsn(F2D);
mv.visitInsn(DUP2_X1);
mv.visitInsn(POP2);
mv.visitInsn(F2D);
mv.visitInsn(DUP2_X2);
mv.visitInsn(POP2);
type = TYPE_DOUBLE;
}
if (type == TYPE_LONG || type == TYPE_DOUBLE) {
mv.visitInsn( (type == TYPE_LONG ? LCMP : DCMPG) );
switch (instruction) {
case TYPE_EQ: mv.visitJumpInsn(IFEQ, endLabel); break;
case TYPE_NEQ: mv.visitJumpInsn(IFNE, endLabel); break;
case TYPE_LT: mv.visitJumpInsn(IFLT, endLabel); break;
case TYPE_LTE: mv.visitJumpInsn(IFLE, endLabel); break;
default: throw new Exception("this combination of instruction and type is not implemented (yet).");
}
}
else if (type == TYPE_INT || type == TYPE_CHAR || type == TYPE_BOOLEAN || type == TYPE_BYTE || type == TYPE_SHORT) {
switch (instruction) {
case TYPE_EQ: mv.visitJumpInsn(IF_ICMPEQ, endLabel); break;
case TYPE_NEQ: mv.visitJumpInsn(IF_ICMPNE, endLabel); break;
case TYPE_LT: mv.visitJumpInsn(IF_ICMPLT, endLabel); break;
case TYPE_LTE: mv.visitJumpInsn(IF_ICMPLE, endLabel); break;
default: throw new Exception("this combination of instruction and type is not implemented (yet).");
}
}
//else if (type == TYPE_OBJECT || type == TYPE_STRING) {
else if (type == TYPE_OBJECT) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
switch (instruction) {
case TYPE_EQ: mv.visitJumpInsn(IFNE, endLabel); break;
case TYPE_NEQ: mv.visitJumpInsn(IFEQ, endLabel); break;
default: throw new Exception("this combination of instruction and type is not implemented (yet).");
}
}
else if (type == TYPE_STRING) {
//mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
switch (instruction) {
case TYPE_EQ: mv.visitJumpInsn(IF_ACMPEQ, endLabel); break;
case TYPE_NEQ: mv.visitJumpInsn( (type == TYPE_OBJECT ? IF_ACMPNE : IF_ACMPEQ) , endLabel); break;
default: throw new Exception("this combination of instruction and type is not implemented (yet).");
/*case TYPE_EQ: mv.visitJumpInsn(IF_ICMPEQ, endLabel); break;
case TYPE_NEQ: mv.visitJumpInsn(IF_ICMPNE, endLabel); break;
default: throw new Exception("this combination of instruction and type is not implemented (yet).");*/
}
if (type == TYPE_STRING) {
pushValue(mv, query.getArg(0), type);
mv.visitJumpInsn( IFNULL, falseLabel);
pushValue(mv, query.getArg(0), type);
pushValue(mv, query.getArg(1), type);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "equals", "(Ljava/lang/Object;)Z");
mv.visitJumpInsn(IFNE, endLabel);
mv.visitLabel(falseLabel);
}
} else
throw new Exception("this combination of instruction and type is not implemented (yet).");
if (individualReturnBehavior == null)
returnBehaviorStack.insertReturnCode( (type == TYPE_STRING && instruction == TYPE_NEQ), mv);
else
individualReturnBehavior.insertReturnCode( (type == TYPE_STRING && instruction == TYPE_NEQ), mv, null);
mv.visitJumpInsn(GOTO, endComparisonLabel);
mv.visitLabel(endLabel);
}
if (individualReturnBehavior == null)
returnBehaviorStack.insertReturnCode(!(type == TYPE_STRING && instruction == TYPE_NEQ), mv);
else
individualReturnBehavior.insertReturnCode( !(type == TYPE_STRING && instruction == TYPE_NEQ), mv, null);
mv.visitLabel(endComparisonLabel);
}
protected static void pushValue (MethodVisitor mv, int val, int type) throws Exception {
if (type == TYPE_STRING)
type = TYPE_OBJECT;
final int index = val >> VAR_INDEX_SHIFT;
final int source_ty = (val >> VAR_TABLE_SHIFT) & VAR_TABLE_MASK;
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "edu/umass/pql/Env", ast.getTypeArrayName(source_ty), "[" + ast.getTypeSpecifier(source_ty) );
mv.visitLdcInsn(new Integer(index));
mv.visitInsn( ast.getArrayInstruction(source_ty|ARRAY_INSTR_LOAD));
castValue(mv, source_ty, type);
}
protected static void preliminaryStoreValue (MethodVisitor mv, int val) throws Exception {
final int index = val >> VAR_INDEX_SHIFT;
final int source_ty = (val >> VAR_TABLE_SHIFT) & VAR_TABLE_MASK;
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "edu/umass/pql/Env", ast.getTypeArrayName(source_ty), "[" + ast.getTypeSpecifier(source_ty) );
mv.visitLdcInsn(new Integer(index));
}
protected static void storeValue (MethodVisitor mv, int val, int type) throws Exception {
final int source_ty = (val >> VAR_TABLE_SHIFT) & VAR_TABLE_MASK;
storeValue(mv, val, type, source_ty);
}
protected static void storeValue (MethodVisitor mv, int val, int type, int sourceType) throws Exception {
//final int index = val >> VAR_INDEX_SHIFT;
final int source_ty = (val >> VAR_TABLE_SHIFT) & VAR_TABLE_MASK;
castValue(mv, type, sourceType);
if (sourceType != source_ty)
castValue(mv, sourceType, source_ty);
/*if (source_ty == TYPE_DOUBLE)
mv.visitVarInsn(DSTORE, 1);
else if (source_ty == TYPE_LONG)
mv.visitVarInsn(LSTORE, 1);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "edu/umass/pql/Env", ast.getTypeArrayName(source_ty), "[" + ast.getTypeSpecifier(source_ty) );
if (source_ty == TYPE_INT || source_ty == TYPE_OBJECT)
mv.visitInsn(SWAP);
mv.visitLdcInsn(new Integer(index));
if (source_ty == TYPE_INT || source_ty == TYPE_OBJECT)
mv.visitInsn(SWAP);
else if (source_ty == TYPE_DOUBLE)
mv.visitVarInsn(DLOAD, 1);
else if (source_ty == TYPE_LONG)
mv.visitVarInsn(LLOAD, 1);*/
mv.visitInsn(ast.getArrayInstruction(source_ty|ARRAY_INSTR_STORE));
}
/*protected static void storeValueWithoutPreliminary (MethodVisitor mv, int val, int type) throws Exception {
final int index = val >> VAR_INDEX_SHIFT;
final int source_ty = (val >> VAR_TABLE_SHIFT) & VAR_TABLE_MASK;
castValue(mv, type, source_ty);
if (source_ty == TYPE_DOUBLE)
mv.visitVarInsn(DSTORE, 1);
else if (source_ty == TYPE_LONG)
mv.visitVarInsn(LSTORE, 1);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, "edu/umass/pql/Env", ast.getTypeArrayName(source_ty), "[" + ast.getTypeSpecifier(source_ty) );
if (source_ty == TYPE_INT || source_ty == TYPE_OBJECT)
mv.visitInsn(SWAP);
mv.visitLdcInsn(new Integer(index));
if (source_ty == TYPE_INT || source_ty == TYPE_OBJECT)
mv.visitInsn(SWAP);
else if (source_ty == TYPE_DOUBLE)
mv.visitVarInsn(DLOAD, 1);
else if (source_ty == TYPE_LONG)
mv.visitVarInsn(LLOAD, 1);
mv.visitInsn(ast.getArrayInstruction(source_ty|ARRAY_INSTR_STORE));
}*/
protected static void insertSpecialTypeCast (MethodVisitor mv, int from, int to) throws Exception {
insertComment(mv, "InsertSpecialTypeCast");
if (from != TYPE_STRING && from != TYPE_FLOAT && from != -1)
return;
if (from == TYPE_STRING)
mv.visitTypeInsn(CHECKCAST, "java/lang/Object");
else if (to == TYPE_STRING)
mv.visitTypeInsn(CHECKCAST, "java/lang/String");
else if (to == TYPE_BOOLEAN) {
Label noChange = new Label();
mv.visitInsn(DUP);
mv.visitJumpInsn(IFEQ, noChange);
mv.visitInsn(POP);
mv.visitLdcInsn(new Integer(1));
mv.visitLabel(noChange);
}
else {
mv.visitInsn(ast.insertSpecialTypeCast(from, to));
}
}
protected static void castValue (MethodVisitor mv, int from, int to) throws Exception {
if (from != to) {
if (from >= 5 || to >= 5) {
int tmpType [] = {TYPE_OBJECT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_DOUBLE};
if (from >= 5) {
insertSpecialTypeCast(mv, from, -1);
castValue(mv, tmpType[from-5], to);
} else if (to >= 5) {
castValue(mv, from, tmpType[to-5]);
insertSpecialTypeCast(mv, -1, to);
}
}
else if ( to == TYPE_OBJECT ) {
switch (from) {
case TYPE_INT:
mv.visitMethodInsn(INVOKESTATIC, "edu/umass/pql/Env", "canonicalInteger", "(I)Ljava/lang/Integer;");
break;
case TYPE_LONG:
mv.visitMethodInsn(INVOKESTATIC, "edu/umass/pql/Env", "canonicalLong", "(J)Ljava/lang/Long;");
break;
case TYPE_DOUBLE:
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueof", "(D)Ljava/lang/Double;");
break;
default:
throw new Exception("the specified type ('" + from + "') is not supported (yet).");
}
} else if ( from == TYPE_OBJECT ) {
String [] checkInstances = {"java/lang/Number", "java/lang/Boolean", "java/lang/Character"};
Label endCheck = new Label();
for (int i=0; i<checkInstances.length; i++) {
mv.visitInsn(DUP);
mv.visitTypeInsn(INSTANCEOF, checkInstances[i]);
Label notInstance = new Label();
mv.visitJumpInsn(IFEQ, notInstance);
mv.visitTypeInsn(CHECKCAST, checkInstances[i]);
if (i == 0)
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", ast.getFullTypeSpecifier(to) + "Value", "()" + ast.getTypeSpecifier(to));
else if (i == 1) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
if (to != TYPE_INT)
mv.visitInsn(ast.getTypeCastFlag("I2" + ast.getTypeSpecifier(to)));
} else if (i == 2) {
mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
if (to != TYPE_INT)
mv.visitInsn(ast.getTypeCastFlag("I2" + ast.getTypeSpecifier(to)));
}
mv.visitJumpInsn(GOTO, endCheck);
mv.visitLabel(notInstance);
}
mv.visitTypeInsn(NEW, "java/lang/Exception");
mv.visitInsn(DUP);
mv.visitLdcInsn(new String("the specified object cannot be converted in a numerical value."));
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Exception", "<init>", "(Ljava/lang/String;)V");
mv.visitInsn(ATHROW);
mv.visitLabel(endCheck);
}
else
mv.visitInsn( ast.getTypeCastFlag(ast.getTypeSpecifier(from) + "2" + ast.getTypeSpecifier(to)) );
}
}
protected static void insertDebugInformation(MethodVisitor mv, String str) {
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn(str);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
}
protected static void insertDebugInformation(MethodVisitor mv, int type) throws Exception {
mv.visitMethodInsn(INVOKESTATIC, "java/lang/String", "valueOf", "(" + ast.getTypeSpecifier(type) + ")Ljava/lang/String;");
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitInsn(SWAP);
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
}
protected static void insertComment (MethodVisitor mv, String comment) throws Exception {
mv.visitLdcInsn(comment);
mv.visitInsn(POP);
}
}