Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.codename1.tools.translator.BytecodeMethod Maven / Gradle / Ivy
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.tools.translator;
import com.codename1.tools.translator.bytecodes.ArithmeticExpression;
import com.codename1.tools.translator.bytecodes.ArrayLengthExpression;
import com.codename1.tools.translator.bytecodes.ArrayLoadExpression;
import com.codename1.tools.translator.bytecodes.AssignableExpression;
import com.codename1.tools.translator.bytecodes.BasicInstruction;
import com.codename1.tools.translator.bytecodes.CustomIntruction;
import com.codename1.tools.translator.bytecodes.CustomInvoke;
import com.codename1.tools.translator.bytecodes.CustomJump;
import com.codename1.tools.translator.bytecodes.DupExpression;
import com.codename1.tools.translator.bytecodes.Field;
import com.codename1.tools.translator.bytecodes.IInc;
import com.codename1.tools.translator.bytecodes.Instruction;
import com.codename1.tools.translator.bytecodes.Invoke;
import com.codename1.tools.translator.bytecodes.Jump;
import com.codename1.tools.translator.bytecodes.LabelInstruction;
import com.codename1.tools.translator.bytecodes.Ldc;
import com.codename1.tools.translator.bytecodes.LineNumber;
import com.codename1.tools.translator.bytecodes.LocalVariable;
import com.codename1.tools.translator.bytecodes.MultiArray;
import com.codename1.tools.translator.bytecodes.SwitchInstruction;
import com.codename1.tools.translator.bytecodes.TryCatch;
import com.codename1.tools.translator.bytecodes.TypeInstruction;
import com.codename1.tools.translator.bytecodes.VarOp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
/**
*
* @author Shai Almog
*/
public class BytecodeMethod implements SignatureSet {
/**
* @return the acceptStaticOnEquals
*/
public static boolean isAcceptStaticOnEquals() {
return acceptStaticOnEquals;
}
/**
* @param aAcceptStaticOnEquals the acceptStaticOnEquals to set
*/
public static void setAcceptStaticOnEquals(boolean aAcceptStaticOnEquals) {
acceptStaticOnEquals = aAcceptStaticOnEquals;
}
private List arguments = new ArrayList();
private Set localVariables = new HashSet();
private ByteCodeMethodArg returnType;
private String methodName;
private String clsName;
private boolean constructor;
private boolean staticMethod;
private boolean privateMethod;
private boolean nativeMethod;
private List dependentClasses = new ArrayList();
//private List exportedClasses = new ArrayList();
private List instructions = new ArrayList();
private String declaration = "";
private String sourceFile;
private int maxStack;
private int maxLocals;
private static boolean acceptStaticOnEquals;
private int methodOffset;
private boolean forceVirtual;
private boolean virtualOverriden;
private boolean finalMethod;
private boolean synchronizedMethod;
private final static Set virtualMethodsInvoked = new TreeSet();
private String desc;
private boolean eliminated;
static boolean optimizerOn;
static {
String op = System.getProperty("optimizer");
optimizerOn = op == null || op.equalsIgnoreCase("on");
//optimizerOn = false;
}
public BytecodeMethod(String clsName, int access, String name, String desc, String signature, String[] exceptions) {
methodName = name;
this.clsName = clsName;
this.desc = desc;
privateMethod = (access & Opcodes.ACC_PRIVATE) == Opcodes.ACC_PRIVATE;
nativeMethod = (access & Opcodes.ACC_NATIVE) == Opcodes.ACC_NATIVE;
staticMethod = (access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC;
finalMethod = (access & Opcodes.ACC_FINAL) == Opcodes.ACC_FINAL;
synchronizedMethod = (access & Opcodes.ACC_SYNCHRONIZED) == Opcodes.ACC_SYNCHRONIZED;
int pos = desc.lastIndexOf(')');
if (!staticMethod) {
if (!dependentClasses.contains("java_lang_NullPointerException")) {
dependentClasses.add("java_lang_NullPointerException");
}
} //
if(methodName.equals("")) {
methodName = "__INIT__";
constructor = true;
returnType = new ByteCodeMethodArg(Void.TYPE, 0);
} else {
if(methodName.equals("")) {
methodName = "__CLINIT__";
returnType = new ByteCodeMethodArg(Void.TYPE, 0);
staticMethod = true;
} else {
String retType = desc.substring(pos + 1);
if(retType.equals("V")) {
returnType = new ByteCodeMethodArg(Void.TYPE, 0);
} else {
int dim = 0;
while(retType.startsWith("[")) {
retType = retType.substring(1);
dim++;
}
char currentType = retType.charAt(0);
switch(currentType) {
case 'L':
// Object skip until ;
int idx = retType.indexOf(';');
String objectType = retType.substring(1, idx);
objectType = objectType.replace('/', '_').replace('$', '_');
if(!dependentClasses.contains(objectType)) {
dependentClasses.add(objectType);
}
//if (!this.isPrivate() && !exportedClasses.contains(objectType)) {
// exportedClasses.add(objectType);
//}
returnType = new ByteCodeMethodArg(objectType, dim);
break;
case 'I':
returnType = new ByteCodeMethodArg(Integer.TYPE, dim);
break;
case 'J':
returnType = new ByteCodeMethodArg(Long.TYPE, dim);
break;
case 'B':
returnType = new ByteCodeMethodArg(Byte.TYPE, dim);
break;
case 'S':
returnType = new ByteCodeMethodArg(Short.TYPE, dim);
break;
case 'F':
returnType = new ByteCodeMethodArg(Float.TYPE, dim);
break;
case 'D':
returnType = new ByteCodeMethodArg(Double.TYPE, dim);
break;
case 'Z':
returnType = new ByteCodeMethodArg(Boolean.TYPE, dim);
break;
case 'C':
returnType = new ByteCodeMethodArg(Character.TYPE, dim);
break;
}
}
}
}
int currentArrayDim = 0;
desc = desc.substring(1, pos);
for(int i = 0 ; i < desc.length() ; i++) {
char currentType = desc.charAt(i);
switch(currentType) {
case '[':
// array of...
currentArrayDim++;
continue;
case 'L':
// Object skip until ;
int idx = desc.indexOf(';', i);
String objectType = desc.substring(i + 1, idx);
objectType = objectType.replace('/', '_').replace('$', '_');
if(!dependentClasses.contains(objectType)) {
dependentClasses.add(objectType);
}
//if (!this.isPrivate() && !exportedClasses.contains(objectType)) {
// exportedClasses.contains(objectType);
//}
i = idx;
arguments.add(new ByteCodeMethodArg(objectType, currentArrayDim));
break;
case 'I':
arguments.add(new ByteCodeMethodArg(Integer.TYPE, currentArrayDim));
break;
case 'J':
arguments.add(new ByteCodeMethodArg(Long.TYPE, currentArrayDim));
break;
case 'B':
arguments.add(new ByteCodeMethodArg(Byte.TYPE, currentArrayDim));
break;
case 'S':
arguments.add(new ByteCodeMethodArg(Short.TYPE, currentArrayDim));
break;
case 'F':
arguments.add(new ByteCodeMethodArg(Float.TYPE, currentArrayDim));
break;
case 'D':
arguments.add(new ByteCodeMethodArg(Double.TYPE, currentArrayDim));
break;
case 'Z':
arguments.add(new ByteCodeMethodArg(Boolean.TYPE, currentArrayDim));
break;
case 'C':
arguments.add(new ByteCodeMethodArg(Character.TYPE, currentArrayDim));
break;
}
currentArrayDim = 0;
}
}
// use this instead of isMethodUsed to compare traditional with new results
public boolean isMethodUsedTester(BytecodeMethod bm)
{
boolean oldway = isMethodUsedOldWay(bm);
boolean newway = isMethodUsed(bm);
if(oldway!=newway)
{ throw new Error("different result");
}
return newway;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
appendFunctionPointer(sb);
return sb.toString();
}
private Hashtable usedSigs;
// [ddyer 4/2017] avoid creating a lot of temporary objects.
// more than 3x faster than the old way.
public boolean isMethodUsed(BytecodeMethod bm0) {
SignatureSet bm = (SignatureSet)bm0;
if(usedSigs == null) {
usedSigs = new Hashtable();
for(Instruction ins : instructions) {
String sname = ins.getMethodName();
if(sname!=null)
{
SignatureSet ss = usedSigs.get(sname);
// either use the instruction itself, or create a set of them
ss = ss==null ? ins : new MultipleSignatureSet((SignatureSet)ins,ss);
usedSigs.put(sname,ss);
}
}
}
String name = bm.getMethodName();
SignatureSet ss = usedSigs.get("__INIT__".equals(name)?"":name);
return ((ss==null) ? false : ss.containsSignature(bm));
}
/**
* Flag to indicate whether this method is used by native sources.
*/
private boolean usedByNative;
/**
* Internal use: to track the list of native sources that were used to calculate the
* usedByNative flag.
*/
private String[] usedByNativeSources;
/**
* Checks to see if this method is used by any of the provided native sources.
* @param nativeSources The native sources to check.
* @param cls The class that the method belongs to. This is used to improve performance by first checking to
* see if the class is Not referenced in native sources. If the class is not referenced, then we know that
* neither is the method. This method will also set the {@link ByteCodeClass#setUsedByNative(boolean)} flag
* to improve the performance for the next method that is checked in the same class.
* @return True if the method is used by native.
*/
public boolean isMethodUsedByNative(String[] nativeSources, ByteCodeClass cls) {
if (nativeSources == null) return false;
if (nativeSources == usedByNativeSources) {
return usedByNative;
}
usedByNativeSources = nativeSources;
if (cls != null && cls.getUsedByNative() == ByteCodeClass.UsedByNativeResult.Unused) {
// If the class isn't used, then neither is the method.
usedByNative = false;
return false;
}
// check native code
StringBuilder b = new StringBuilder();
this.appendFunctionPointer(b);
String str = b.toString();
boolean foundClassName = false;
for(String s : nativeSources) {
if (cls != null && !foundClassName && s.contains(clsName)) {
// For later we record whether the class is used.
foundClassName = true;
}
if(s.contains(str)) {
usedByNative = true;
if (cls != null) {
cls.setUsedByNative(true);
}
return true;
}
}
if (!foundClassName && cls != null) {
// We didn't find the class at all.
// Let's record that as it will save us time
// when looking up other methods in this class.
cls.setUsedByNative(false);
}
usedByNative = false;
return false;
}
private Set usedMethods;
public boolean isMethodUsedOldWay(BytecodeMethod bm) {
if(usedMethods == null) {
usedMethods = new TreeSet();
for(Instruction ins : instructions) {
String s = ins.getMethodUsed();
if(s != null && !usedMethods.contains(s)) {
usedMethods.add(s);
}
}
}
if(bm.methodName.equals("__INIT__")) {
return usedMethods.contains(bm.desc + ".");
}
return usedMethods.contains(bm.desc + "." + bm.methodName);
}
public void findWritableFields(Set outSet) {
int len = instructions.size();
for (int i=0; i arguments) {
int currentArrayDim = 0;
desc = desc.substring(1);
boolean returnVal = false;
String returnType = null;
for(int i = 0 ; i < desc.length() ; i++) {
char currentType = desc.charAt(i);
switch(currentType) {
// return type parsing, and void return type
case ')':
case 'V':
returnVal = true;
continue;
case '[':
// array of...
currentArrayDim++;
continue;
case 'L':
if(!returnVal) {
arguments.add("o");
} else {
b.append("_R");
returnType = "JAVA_OBJECT";
}
// Object skip until ;
int idx = desc.indexOf(';', i);
String objectType = desc.substring(i + 1, idx);
objectType = objectType.replace('/', '_').replace('$', '_');
i = idx;
b.append("_");
b.append(objectType);
break;
case 'I':
if(!returnVal) {
arguments.add("i");
} else {
b.append("_R");
returnType = "JAVA_INT";
}
b.append("_int");
break;
case 'J':
if(!returnVal) {
arguments.add("l");
} else {
b.append("_R");
returnType = "JAVA_LONG";
}
b.append("_long");
break;
case 'B':
if(!returnVal) {
arguments.add("i");
} else {
b.append("_R");
returnType = "JAVA_INT";
}
b.append("_byte");
break;
case 'S':
if(!returnVal) {
arguments.add("i");
} else {
b.append("_R");
returnType = "JAVA_INT";
}
b.append("_short");
break;
case 'F':
if(!returnVal) {
arguments.add("f");
} else {
b.append("_R");
returnType = "JAVA_FLOAT";
}
b.append("_float");
break;
case 'D':
if(!returnVal) {
arguments.add("d");
} else {
returnType = "JAVA_DOUBLE";
b.append("_R");
}
b.append("_double");
break;
case 'Z':
if(!returnVal) {
arguments.add("i");
} else {
returnType = "JAVA_INT";
b.append("_R");
}
b.append("_boolean");
break;
case 'C':
if(!returnVal) {
arguments.add("i");
} else {
b.append("_R");
returnType = "JAVA_INT";
}
b.append("_char");
break;
}
if(currentArrayDim > 0) {
if(!returnVal) {
arguments.remove(arguments.size() - 1);
arguments.add("o");
} else {
returnType = "JAVA_OBJECT";
}
b.append("_");
b.append(currentArrayDim);
b.append("ARRAY");
}
currentArrayDim = 0;
}
return returnType;
}
public List getDependentClasses() {
return dependentClasses;
}
//public List getExportedClasses() {
// return exportedClasses;
//}
private void appendCMethodPrefix(StringBuilder b, String prefix) {
appendCMethodPrefix(b, prefix, clsName);
}
private void appendCMethodPrefix(StringBuilder b, String prefix, String clsName) {
appendCMethodPrefix("\n", "", b, prefix, clsName);
}
public void appendArgumentTypes(StringBuilder b) {
for(ByteCodeMethodArg args : arguments) {
args.appendCMethodExt(b);
}
if(!returnType.isVoid()) {
b.append("_R");
returnType.appendCMethodExt(b);
}
}
private void appendCMethodPrefix(String before, String after, StringBuilder b, String prefix, String clsName) {
b.append(before);
returnType.appendCSig(b);
b.append(prefix);
b.append(clsName);
b.append("_");
b.append(getCMethodName());
b.append("__");
for(ByteCodeMethodArg args : arguments) {
args.appendCMethodExt(b);
}
if(!returnType.isVoid()) {
b.append("_R");
returnType.appendCMethodExt(b);
}
b.append(after);
b.append("(CODENAME_ONE_THREAD_STATE");
int arg = 1;
if(!staticMethod) {
b.append(", ");
new ByteCodeMethodArg(clsName, 0).appendCSig(b);
b.append(" __cn1ThisObject");
}
for(ByteCodeMethodArg args : arguments) {
b.append(", ");
args.appendCSig(b);
b.append("__cn1Arg");
b.append(arg);
arg++;
}
b.append(")");
}
public void addToConstantPool() {
for(Instruction i : instructions) {
i.addToConstantPool();
}
}
public boolean isSynchronizedMethod() {
return synchronizedMethod;
}
private boolean hasLocalVariableWithIndex(char qualifier, int index) {
for (LocalVariable lv : localVariables) {
if (lv.getIndex() == index && lv.getQualifier() == qualifier) {
return true;
}
}
return false;
}
public void appendMethodC(StringBuilder b) {
if(nativeMethod) {
return;
}
appendCMethodPrefix(b, "");
b.append(" {\n");
if(eliminated) {
if(returnType.isVoid()) {
b.append(" return;\n}\n\n");
} else {
b.append(" return 0;\n}\n\n");
}
return;
}
b.append(declaration);
boolean hasInstructions = true;
if(optimizerOn) {
hasInstructions = optimize();
}
if(hasInstructions) {
Set added = new HashSet();
for (LocalVariable lv : localVariables) {
String variableName = lv.getQualifier() + "locals_"+lv.getIndex()+"_";
if (!added.contains(variableName) && lv.getQualifier() != 'o') {
added.add(variableName);
b.append(" volatile ");
switch (lv.getQualifier()) {
case 'i' :
b.append("JAVA_INT"); break;
case 'l' :
b.append("JAVA_LONG"); break;
case 'f' :
b.append("JAVA_FLOAT"); break;
case 'd' :
b.append("JAVA_DOUBLE"); break;
}
b.append(" ").append(lv.getQualifier()).append("locals_").append(lv.getIndex()).append("_ = 0; /* ").append(lv.getOrigName()).append(" */\n");
}
}
if(staticMethod) {
if(methodName.equals("__CLINIT__")) {
b.append(" DEFINE_METHOD_STACK(");
} else {
b.append(" __STATIC_INITIALIZER_");
b.append(clsName.replace('/', '_').replace('$', '_'));
b.append("(threadStateData);\n DEFINE_METHOD_STACK(");
}
} else {
b.append(" DEFINE_INSTANCE_METHOD_STACK(");
}
b.append(maxStack);
b.append(", ");
b.append(maxLocals);
b.append(", 0, ");
b.append(Parser.addToConstantPool(clsName));
b.append(", ");
b.append(Parser.addToConstantPool(methodName));
b.append(");\n");
int startOffset = 0;
if(synchronizedMethod) {
if(staticMethod) {
b.append(" monitorEnterBlock(threadStateData, (JAVA_OBJECT)&class__");
b.append(clsName);
b.append(");\n");
} else {
b.append(" monitorEnterBlock(threadStateData, __cn1ThisObject);\n");
}
}
if(!staticMethod) {
b.append(" locals[0].data.o = __cn1ThisObject; locals[0].type = CN1_TYPE_OBJECT; ");
startOffset++;
}
int localsOffset = startOffset;
for(int iter = 0 ; iter < arguments.size() ; iter++) {
ByteCodeMethodArg arg = arguments.get(iter);
if (arg.getQualifier() == 'o') {
b.append(" locals[");
b.append(localsOffset);
b.append("].data.");
b.append(arg.getQualifier());
b.append(" = __cn1Arg");
b.append(iter + 1);
b.append(";\n");
b.append(" locals[");
b.append(localsOffset);
b.append("].type = CN1_TYPE_OBJECT;\n");
} else {
b.append(" ");
if (!hasLocalVariableWithIndex(arg.getQualifier(), localsOffset)) {
switch (arg.getQualifier()) {
case 'i' : b.append("JAVA_INT"); break;
case 'f' : b.append("JAVA_FLOAT"); break;
case 'd' : b.append("JAVA_DOUBLE"); break;
case 'l' : b.append("JAVA_LONG"); break;
default: b.append("JAVA_INT"); break;
}
b.append(" ");
}
b.append(arg.getQualifier());
b.append("locals_");
b.append(localsOffset);
b.append("_");
b.append(" = __cn1Arg");
b.append(iter + 1);
b.append(";\n");
}
// For now we'll still allocate space for locals that we're not using
// so we keep the indexes the same for objects.
localsOffset++;
if(arg.isDoubleOrLong()) {
localsOffset++;
}
}
} else {
if(synchronizedMethod) {
if(staticMethod) {
b.append(" monitorEnterBlock(threadStateData, (JAVA_OBJECT)&class__");
b.append(clsName);
b.append(");\n");
} else {
b.append(" monitorEnterBlock(threadStateData, __cn1ThisObject);\n");
}
}
}
BasicInstruction.setSynchronizedMethod(synchronizedMethod, staticMethod, clsName);
TryCatch.reset();
BasicInstruction.setHasInstructions(hasInstructions);
for(Instruction i : instructions) {
i.setMaxes(maxStack, maxLocals);
i.appendInstruction(b, instructions);
}
if(instructions.size() == 0) {
if(returnType.isVoid()) {
b.append(" return;\n}\n\n");
} else {
b.append(" return 0;\n}\n\n");
}
return;
}
Instruction inst = instructions.get(instructions.size() - 1);
int lastInstruction = inst.getOpcode();
if(lastInstruction == -1 || inst instanceof LabelInstruction) {
if(instructions.size() > 2) {
inst = instructions.get(instructions.size() - 2);
lastInstruction = inst.getOpcode();
}
}
if(lastInstruction == Opcodes.RETURN || lastInstruction == Opcodes.ARETURN || lastInstruction == Opcodes.IRETURN || lastInstruction == Opcodes.LRETURN ||
lastInstruction == Opcodes.FRETURN || lastInstruction == Opcodes.DRETURN || lastInstruction == -1) {
b.append("}\n\n");
} else {
if(returnType.isVoid()) {
b.append(" return;\n}\n\n");
} else {
b.append(" return 0;\n}\n\n");
}
}
}
public void appendInterfaceMethodC(StringBuilder b) {
appendCMethodPrefix(b, "", clsName);
b.append(" {\n");
if(!returnType.isVoid()) {
b.append("return virtual_");
} else {
b.append("virtual_");
}
b.append(clsName);
b.append("_");
b.append(getCMethodName());
b.append("__");
for(ByteCodeMethodArg args : arguments) {
args.appendCMethodExt(b);
}
if(!returnType.isVoid()) {
b.append("_R");
returnType.appendCMethodExt(b);
}
b.append("(threadStateData");
int arg = 1;
b.append(", __cn1ThisObject");
for(int iter = 0 ; iter < arguments.size() ; iter++) {
b.append(", ");
b.append("__cn1Arg");
b.append(arg);
arg++;
}
b.append(");\n}\n\n");
}
public void appendSuperCall(StringBuilder b, String cls) {
if(nativeMethod) {
return;
}
appendCMethodPrefix(b, "", cls);
b.append(" {\n");
if(!returnType.isVoid()) {
b.append(" return ");
}
b.append(clsName);
b.append("_");
b.append(getCMethodName());
b.append("__");
for(ByteCodeMethodArg args : arguments) {
args.appendCMethodExt(b);
}
if(!returnType.isVoid()) {
b.append("_R");
returnType.appendCMethodExt(b);
}
b.append("(threadStateData");
int arg = 1;
if(!staticMethod) {
b.append(", __cn1ThisObject");
}
for(int iter = 0 ; iter < arguments.size() ; iter++) {
b.append(", ");
b.append("__cn1Arg");
b.append(arg);
arg++;
}
b.append(");\n}\n\n");
}
public void appendMethodHeader(StringBuilder b) {
appendMethodHeader(b, clsName);
}
public void appendMethodHeader(StringBuilder b, String clsName) {
appendCMethodPrefix(b, "", clsName);
b.append(";\n");
}
public void appendVirtualMethodC(String cls, StringBuilder b, int offset) {
appendVirtualMethodC(cls, b, Integer.toString(offset));
}
public void appendVirtualMethodC(String cls, StringBuilder b, String offset) {
appendVirtualMethodC(cls, b, offset, false);
}
public static void addVirtualMethodsInvoked(String m) {
if(!virtualMethodsInvoked.contains(m)) {
virtualMethodsInvoked.add(m);
}
}
public void setForceVirtual(boolean forceVirtual) {
this.forceVirtual = forceVirtual;
}
public boolean isForceVirtual() {
return forceVirtual;
}
public String getFullCName() {
return this.clsName + "_"+this.getCMethodName();
}
public void appendVirtualMethodC(String cls, StringBuilder b, String offset, boolean includeStaticInitializer) {
if(virtualOverriden) {
return;
}
StringBuilder bld = new StringBuilder();
bld.append(cls);
bld.append("_");
bld.append(getCMethodName());
bld.append("__");
for(ByteCodeMethodArg args : arguments) {
args.appendCMethodExt(bld);
}
if(!returnType.isVoid()) {
bld.append("_R");
returnType.appendCMethodExt(bld);
}
if(!forceVirtual && !virtualMethodsInvoked.contains(bld.toString())) {
return;
}
// generate the function pointer declaration
appendCMethodPrefix("\ntypedef ", ")", b, "(*functionPtr_", cls);
b.append(";\n");
appendCMethodPrefix(b, "virtual_", cls);
b.append(" {\n ");
if(includeStaticInitializer) {
b.append("__STATIC_INITIALIZER_");
b.append(cls);
b.append("(threadStateData);\n ");
}
if (System.getProperty("INCLUDE_NPE_CHECKS", "false").equals("true")) {
b.append("\n if(__cn1ThisObject == JAVA_NULL) THROW_NULL_POINTER_EXCEPTION();\n ");
}
if(!returnType.isVoid()) {
b.append("return (*(functionPtr_");
} else {
b.append("(*(functionPtr_");
}
b.append(bld);
b.append(")__cn1ThisObject->__codenameOneParentClsReference->vtable[");
b.append(offset);
b.append("])(threadStateData, ");
int arg = 1;
b.append("__cn1ThisObject");
for(int iter = 0 ; iter < arguments.size() ; iter++) {
b.append(", ");
b.append("__cn1Arg");
b.append(arg);
arg++;
}
b.append(");\n}\n\n");
}
public void appendVirtualMethodHeader(StringBuilder b, String cls) {
StringBuilder bld = new StringBuilder();
bld.append(cls);
bld.append("_");
bld.append(getCMethodName());
bld.append("__");
for(ByteCodeMethodArg args : arguments) {
args.appendCMethodExt(bld);
}
if(!returnType.isVoid()) {
bld.append("_R");
returnType.appendCMethodExt(bld);
}
if(!forceVirtual && !virtualMethodsInvoked.contains(bld.toString())) {
return;
}
appendCMethodPrefix(b, "virtual_", cls);
b.append(";\n");
}
public void appendFunctionPointer(StringBuilder b) {
appendFunctionPointer(b, clsName);
}
public void appendFunctionPointer(StringBuilder b, String className) {
b.append(className);
b.append("_");
b.append(getCMethodName());
b.append("__");
for(ByteCodeMethodArg args : arguments) {
args.appendCMethodExt(b);
}
if(!returnType.isVoid()) {
b.append("_R");
returnType.appendCMethodExt(b);
}
}
public void appendMethodCSharp(StringBuilder b) {
// todo
}
/**
* @return the methodName
*/
public String getMethodName() {
return methodName;
}
public boolean equals(Object o) {
BytecodeMethod bm = (BytecodeMethod)o;
int val = bm.methodName.compareTo(methodName);
if(val != 0) {
return false;
}
if(acceptStaticOnEquals) {
if(bm.arguments.size() != arguments.size()) {
return false;
}
} else {
if(staticMethod || bm.staticMethod || bm.arguments.size() != arguments.size()) {
return false;
}
}
for(int iter = 0 ; iter < arguments.size() ; iter++) {
ByteCodeMethodArg arg1 = arguments.get(iter);
ByteCodeMethodArg arg2 = bm.arguments.get(iter);
if(!arg1.equals(arg2)) {
return false;
}
}
return returnType.equals(bm.returnType);
}
public int hashCode() {
return methodName.hashCode();
}
public boolean isStatic() {
return staticMethod;
}
public boolean isPrivate() {
return privateMethod;
}
/*public boolean isVirtualBlockedDueToFinal() {
return (!privateMethod && !staticMethod && !constructor) && finalMethod;
}*/
public boolean canBeVirtual() {
return !privateMethod && !staticMethod && !constructor;
}
public boolean isNative() {
return nativeMethod;
}
public String getVariableNameForTypeIndex(int index, char type) {
for(Instruction i : instructions) {
if(i instanceof LocalVariable) {
if(((LocalVariable)i).isRightVariable(index, type)) {
return ((LocalVariable)i).getVarName();
}
} else {
return null;
}
}
return null;
}
public void addMultiArray(String desc, int dims) {
addInstruction(new MultiArray(desc, dims));
}
public void addTryCatchBlock(Label start, Label end, Label handler, String type) {
addInstruction(new TryCatch(start, end, handler, type));
}
public void addLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
//addInstruction(0, new LocalVariable(name, desc, signature, start, end, index));
localVariables.add(new LocalVariable(name, desc, signature, start, end, index));
}
public void setSourceFile(String sourceFile) {
this.sourceFile = sourceFile;
}
public void addDebugInfo(int line) {
addInstruction(new LineNumber(sourceFile, line));
}
public void addLabel(Label l) {
addInstruction(new com.codename1.tools.translator.bytecodes.LabelInstruction(l));
}
public void addInvoke(int opcode, String owner, String name, String desc, boolean itf) {
addInstruction(new Invoke(opcode, owner, name, desc, itf));
}
public void setMaxes(int maxStack, int maxLocals) {
this.maxLocals = maxLocals;
this.maxStack = maxStack;
}
private void addInstruction(Instruction i) {
instructions.add(i);
i.addDependencies(dependentClasses);
}
public void addVariableOperation(int opcode, int var) {
VarOp op = new VarOp(opcode, var);
LocalVariable lv = null;
switch (opcode) {
case Opcodes.ISTORE:
lv = new LocalVariable("v"+var, "I", "I", null, null, var); break;
case Opcodes.LSTORE:
lv = new LocalVariable("v"+var, "J", "J", null, null, var); break;
case Opcodes.FSTORE:
lv = new LocalVariable("v"+var, "F", "F", null, null, var); break;
case Opcodes.DSTORE:
lv = new LocalVariable("v"+var, "D", "D", null, null, var); break;
}
if (lv != null && !localVariables.contains(lv)) {
localVariables.add(lv);
}
addInstruction(op);
}
public void addTypeInstruction(int opcode, String type) {
addInstruction(new TypeInstruction(opcode, type));
}
/**
* Allows us to detect if this is a very simple getter/setter in which case we
* can significantly optimize some operations
*/
public boolean hasExceptionHandlingOrMethodCalls() {
for(Instruction i : instructions) {
if(i.isComplexInstruction()) {
return true;
}
}
return false;
}
public void addIInc(int var, int num) {
addInstruction(new IInc(var, num));
}
public void addLdc(Object o) {
addInstruction(new Ldc(o));
}
public void addJump(int opcode, Label label) {
addInstruction(new Jump(opcode, label));
}
public void addField(ByteCodeClass cls, int opcode, String owner, String name, String desc) {
if (cls.getOriginalClassName().equals(owner) && (opcode == Opcodes.PUTFIELD || opcode == Opcodes.PUTSTATIC)) {
cls.addWritableField(name);
}
addInstruction(new Field(opcode, owner, name, desc));
}
public void addInstruction(int opcode) {
addInstruction(new BasicInstruction(opcode, 0));
}
public void addInstruction(int opcode, int value) {
addInstruction(new BasicInstruction(opcode, value));
}
public void addSwitch(Label dflt, int[] keys, Label[] labels) {
addInstruction(new SwitchInstruction(dflt, keys, labels));
}
/**
* @return the methodOffset
*/
public int getMethodOffset() {
return methodOffset;
}
/**
* @param methodOffset the methodOffset to set
*/
public void setMethodOffset(int methodOffset) {
this.methodOffset = methodOffset;
}
/**
* @return the staticMethod
*/
public boolean isMain() {
return staticMethod && methodName.equals("main") && arguments.size() == 1 && arguments.get(0).getArrayDimensions() == 1;
}
public boolean isDefaultConstructor() {
return constructor && arguments.size() == 0;
}
private String cMethodName;
/**
* Gets the method name, mangled to be usable as the C method name. This will replace illegal characters
* with underscores.
* @return
*/
public String getCMethodName() {
if (cMethodName == null) {
cMethodName = methodName.replace('-','_');
}
return cMethodName;
}
/**
* @return the clsName
*/
public String getClsName() {
return clsName;
}
public boolean isFinalizer() {
return methodName.equals("finalize") && arguments.size() == 0;
}
/**
* @return the virtualOverriden
*/
public boolean isVirtualOverriden() {
return virtualOverriden;
}
/**
* @param virtualOverriden the virtualOverriden to set
*/
public void setVirtualOverriden(boolean virtualOverriden) {
this.virtualOverriden = virtualOverriden;
}
/**
* @return the eliminated
*/
public boolean isEliminated() {
return eliminated;
}
/**
* @param eliminated the eliminated to set
*/
public void setEliminated(boolean eliminated) {
this.eliminated = eliminated;
}
private int varCounter = 0;
boolean optimize() {
int instructionCount = instructions.size();
// optimize away a method that only contains the void return instruction e.g. blank constructors etc.
if(instructionCount < 6) {
int realCount = instructionCount;
Instruction actual = null;
for(int iter = 0 ; iter < instructionCount ; iter++) {
Instruction current = instructions.get(iter);
if(current instanceof LabelInstruction) {
realCount--;
continue;
}
if(current instanceof LineNumber) {
realCount--;
continue;
}
actual = current;
}
if(realCount == 1 && actual != null && actual.getOpcode() == Opcodes.RETURN) {
return false;
}
}
boolean astoreCalls = false;
boolean hasInstructions = false;
boolean hasTryCatch = false;
for (int iter=0; iter < instructionCount - 1; iter++) {
Instruction current = instructions.get(iter);
if (current instanceof TryCatch) {
hasTryCatch = true;
}
current.setMethod(this);
if (current.isOptimized()) {
continue;
}
int currentOpcode = current.getOpcode();
switch(currentOpcode) {
case Opcodes.CHECKCAST: {
// Remove the check cast for now as it gets in the way of other optimizations
instructions.remove(iter);
iter--;
instructionCount--;
break;
}
}
}
for(int iter = 0 ; iter < instructionCount - 1 ; iter++) {
Instruction current = instructions.get(iter);
if (current.isOptimized()) {
// This instruction has already been optimized
// we should skip it and proceed to the next one
continue;
}
Instruction next = instructions.get(iter + 1);
int currentOpcode = current.getOpcode();
int nextOpcode = next.getOpcode();
if (ArithmeticExpression.isArithmeticOp(current)) {
int addedIndex = ArithmeticExpression.tryReduce(instructions, iter);
if (addedIndex >= 0) {
iter = addedIndex;
instructionCount = instructions.size();
continue;
}
}
if (current instanceof Field) {
int newIter = Field.tryReduce(instructions, iter);
if (newIter >= 0) {
iter = newIter;
instructionCount = instructions.size();
continue;
}
}
switch(currentOpcode) {
case Opcodes.ARRAYLENGTH: {
if (!dependentClasses.contains("java_lang_NullPointerException")) {
dependentClasses.add("java_lang_NullPointerException");
}
int newIter = ArrayLengthExpression.tryReduce(instructions, iter);
if (newIter >= 0) {
instructionCount = instructions.size();
iter = newIter;
continue;
}
break;
}
case Opcodes.DUP: {
int newIter = DupExpression.tryReduce(instructions, iter);
if (newIter >= 0) {
iter = newIter;
instructionCount = instructions.size();
continue;
}
break;
}
case Opcodes.POP: {
if (iter > 0) {
Instruction prev = instructions.get(iter-1);
if (prev instanceof CustomInvoke) {
CustomInvoke inv = (CustomInvoke)prev;
if (inv.methodHasReturnValue() && !inv.isNoReturn()) {
inv.setNoReturn(true);
instructions.remove(iter);
iter--;
instructionCount--;
continue;
}
}
}
break;
}
case Opcodes.ASTORE:
case Opcodes.ISTORE:
case Opcodes.DSTORE:
case Opcodes.LSTORE:
case Opcodes.FSTORE: {
if (iter > 0 && current instanceof VarOp) {
VarOp currentVarOp = (VarOp) current;
Instruction prev = instructions.get(iter-1);
if (prev instanceof AssignableExpression) {
AssignableExpression expr = (AssignableExpression)prev;
StringBuilder sb = new StringBuilder();
if (currentVarOp.assignFrom(expr, sb)) {
instructions.remove(iter-1);
instructions.remove(iter-1);
instructions.add(iter-1, new CustomIntruction(sb.toString(), sb.toString(), dependentClasses));
iter = iter-1;
instructionCount = instructions.size();
continue;
}
} else if (prev instanceof CustomInvoke) {
CustomInvoke inv = (CustomInvoke)prev;
StringBuilder sb = new StringBuilder();
if (currentVarOp.assignFrom(inv, sb)) {
instructions.remove(iter-1);
instructions.remove(iter-1);
instructions.add(iter-1, new CustomIntruction(sb.toString(), sb.toString(), dependentClasses));
iter = iter-1;
instructionCount = instructions.size();
continue;
}
}
}
break;
}
case Opcodes.IRETURN:
case Opcodes.FRETURN:
case Opcodes.ARETURN:
case Opcodes.LRETURN:
case Opcodes.DRETURN: {
if (iter > 0 && current instanceof BasicInstruction) {
Instruction prev = instructions.get(iter-1);
if (prev instanceof AssignableExpression) {
AssignableExpression expr = (AssignableExpression)prev;
StringBuilder sb= new StringBuilder();
if (expr.assignTo(null, sb)) {
instructions.remove(iter-1);
instructions.remove(iter-1);
String exprString = sb.toString().trim();
String retVal = exprString;
sb.setLength(0);
if (!prev.isConstant()) {
sb.append("\n{\n ");
switch (currentOpcode) {
case Opcodes.IRETURN:
sb.append("JAVA_INT");
break;
case Opcodes.FRETURN:
sb.append("JAVA_FLOAT");
break;
case Opcodes.ARETURN:
sb.append("JAVA_OBJECT");
break;
case Opcodes.LRETURN:
sb.append("JAVA_LONG");
break;
case Opcodes.DRETURN:
sb.append("JAVA_DOUBLE");
break;
}
sb.append(" ___returnValue=").append(exprString).append(";\n");
retVal = "___returnValue";
}
if(synchronizedMethod) {
if(staticMethod) {
sb.append(" monitorExitBlock(threadStateData, (JAVA_OBJECT)&class__");
sb.append(getClsName());
sb.append(");\n");
} else {
sb.append(" monitorExitBlock(threadStateData, __cn1ThisObject);\n");
}
}
if(hasTryCatch) {
sb.append(" releaseForReturnInException(threadStateData, cn1LocalsBeginInThread, methodBlockOffset); return ").append(retVal).append(";\n");
} else {
sb.append(" releaseForReturn(threadStateData, cn1LocalsBeginInThread); return ").append(retVal).append(";\n");
}
if (!prev.isConstant()) {
sb.append("}\n");
}
instructions.add(iter-1, new CustomIntruction(sb.toString(), sb.toString(), dependentClasses));
iter--;
instructionCount = instructions.size();
continue;
}
} else if (prev instanceof CustomInvoke) {
CustomInvoke expr = (CustomInvoke)prev;
String returnType = expr.getReturnValue();
if (returnType != null && !"JAVA_OBJECT".equals(returnType)) {
// We can't safely return a JAVA_OBJECT directly because it needs to be added
// to the stack for the GC
StringBuilder sb= new StringBuilder();
if (expr.appendExpression(sb)) {
instructions.remove(iter-1);
instructions.remove(iter-1);
String exprString = sb.toString().trim();
String retVal = exprString;
sb.setLength(0);
if (!expr.isConstant()) {
sb.append("\n{\n ");
switch (currentOpcode) {
case Opcodes.IRETURN:
sb.append("JAVA_INT");
break;
case Opcodes.FRETURN:
sb.append("JAVA_FLOAT");
break;
case Opcodes.ARETURN:
sb.append("JAVA_OBJECT");
break;
case Opcodes.LRETURN:
sb.append("JAVA_LONG");
break;
case Opcodes.DRETURN:
sb.append("JAVA_DOUBLE");
break;
}
sb.append(" ___returnValue=").append(exprString).append(";\n");
retVal = "___returnValue";
}
if(synchronizedMethod) {
if(staticMethod) {
sb.append(" monitorExitBlock(threadStateData, (JAVA_OBJECT)&class__");
sb.append(getClsName());
sb.append(");\n");
} else {
sb.append(" monitorExitBlock(threadStateData, __cn1ThisObject);\n");
}
}
if(hasTryCatch) {
sb.append(" releaseForReturnInException(threadStateData, cn1LocalsBeginInThread, methodBlockOffset); return ").append(retVal).append(";\n");
} else {
sb.append(" releaseForReturn(threadStateData, cn1LocalsBeginInThread); return ").append(retVal).append(";\n");
}
if (!expr.isConstant()) {
sb.append("}\n");
}
instructions.add(iter-1, new CustomIntruction(sb.toString(), sb.toString(), dependentClasses));
iter--;
instructionCount = instructions.size();
continue;
}
}
}
}
break;
}
case Opcodes.BASTORE:
case Opcodes.SASTORE:
case Opcodes.CASTORE:
case Opcodes.AASTORE:
case Opcodes.IASTORE:
case Opcodes.DASTORE:
case Opcodes.LASTORE:
case Opcodes.FASTORE: {
if (iter > 2 && current instanceof BasicInstruction) {
StringBuilder devNull = new StringBuilder();
String arrayLiteral = null;
String indexLiteral = null;
String valueLiteral = null;
Instruction prev3 = instructions.get(iter-3);
if (prev3 instanceof AssignableExpression) {
if (((AssignableExpression)prev3).assignTo(null, devNull)) {
arrayLiteral = devNull.toString().trim();
}
}
devNull.setLength(0);
Instruction prev2 = instructions.get(iter-2);
if (prev2 instanceof AssignableExpression) {
if (((AssignableExpression)prev2).assignTo(null, devNull)) {
indexLiteral = devNull.toString().trim();
}
}
devNull.setLength(0);
Instruction prev1 = instructions.get(iter-1);
if (prev1 instanceof AssignableExpression) {
if (((AssignableExpression)prev1).assignTo(null, devNull)) {
valueLiteral = devNull.toString().trim();
}
} else if (prev1 instanceof CustomInvoke) {
devNull.setLength(0);
if (((CustomInvoke)prev1).appendExpression(devNull)) {
valueLiteral = devNull.toString().trim();
}
}
if (arrayLiteral != null && indexLiteral != null && valueLiteral != null) {
String elementType = null;
switch (current.getOpcode()) {
case Opcodes.AASTORE:
elementType = "OBJECT";break;
case Opcodes.IASTORE:
elementType = "INT"; break;
case Opcodes.DASTORE:
elementType = "DOUBLE"; break;
case Opcodes.LASTORE:
elementType = "LONG"; break;
case Opcodes.FASTORE:
elementType = "FLOAT"; break;
case Opcodes.CASTORE:
elementType = "CHAR";break;
case Opcodes.BASTORE:
elementType = "BYTE"; break;
case Opcodes.SASTORE:
elementType = "SHORT"; break;
}
if (elementType == null) {
break;
}
instructions.remove(iter-3);
instructions.remove(iter-3);
instructions.remove(iter-3);
instructions.remove(iter-3);
String code = " CN1_SET_ARRAY_ELEMENT_"+elementType+"(" + arrayLiteral + ", "+indexLiteral+", "+valueLiteral+");\n";
instructions.add(iter-3, new CustomIntruction(code, code, dependentClasses));
iter = iter-3;
instructionCount = instructions.size();
continue;
}
}
break;
}
case Opcodes.FALOAD:
case Opcodes.BALOAD:
case Opcodes.IALOAD:
case Opcodes.LALOAD:
case Opcodes.DALOAD:
case Opcodes.AALOAD:
case Opcodes.SALOAD:
case Opcodes.CALOAD: {
int newIter = ArrayLoadExpression.tryReduce(instructions, iter);
if (newIter >= 0) {
iter = newIter;
instructionCount = instructions.size();
continue;
}
break;
}
/* Try to optimize if statements that just use constants
and local variables so that they don't need the intermediate
push and pop from the stack.
*/
case Opcodes.IF_ACMPEQ:
case Opcodes.IF_ACMPNE:
case Opcodes.IF_ICMPLE:
case Opcodes.IF_ICMPLT:
case Opcodes.IF_ICMPNE:
case Opcodes.IF_ICMPGT:
case Opcodes.IF_ICMPEQ:
case Opcodes.IF_ICMPGE: {
if (iter > 1) {
Instruction leftArg = instructions.get(iter-2);
Instruction rightArg = instructions.get(iter-1);
String leftLiteral = null;
String rightLiteral = null;
if (leftArg instanceof AssignableExpression) {
StringBuilder sb = new StringBuilder();
if (((AssignableExpression)leftArg).assignTo(null, sb)) {
leftLiteral = sb.toString().trim();
}
} else if (leftArg instanceof CustomInvoke) {
CustomInvoke inv = (CustomInvoke)leftArg;
StringBuilder sb = new StringBuilder();
if (!"JAVA_OBJECT".equals(inv.getReturnValue()) && inv.appendExpression(sb)) {
leftLiteral = sb.toString().trim();
}
}
if (rightArg instanceof AssignableExpression) {
StringBuilder sb = new StringBuilder();
if (((AssignableExpression)rightArg).assignTo(null, sb)) {
rightLiteral = sb.toString().trim();
}
} else if (rightArg instanceof CustomInvoke) {
CustomInvoke inv = (CustomInvoke)rightArg;
StringBuilder sb = new StringBuilder();
if (!"JAVA_OBJECT".equals(inv.getReturnValue()) && inv.appendExpression(sb)) {
rightLiteral = sb.toString().trim();
}
}
if (rightLiteral != null && leftLiteral != null) {
Jump jmp = (Jump)current;
instructions.remove(iter-2);
instructions.remove(iter-2);
instructions.remove(iter-2);
//instructions.remove(iter-2);
iter-=2;
//instructionCount -= 2;
StringBuilder sb = new StringBuilder();
String operator = null;
String opName = null;
switch (currentOpcode) {
case Opcodes.IF_ICMPLE:
operator = "<="; opName = "IF_ICMPLE"; break;
case Opcodes.IF_ICMPLT:
operator = "<"; opName = "IF_IMPLT"; break;
case Opcodes.IF_ICMPNE:
operator = "!="; opName = "IF_ICMPNE"; break;
case Opcodes.IF_ICMPGT:
operator = ">"; opName = "IF_ICMPGT"; break;
case Opcodes.IF_ICMPGE:
operator = ">="; opName = "IF_ICMPGE"; break;
case Opcodes.IF_ICMPEQ:
operator = "=="; opName = "IF_ICMPEQ"; break;
case Opcodes.IF_ACMPEQ:
operator = "=="; opName = "IF_ACMPEQ"; break;
case Opcodes.IF_ACMPNE:
operator = "!="; opName = "IF_ACMPNE"; break;
default :
throw new RuntimeException("Invalid operator during optimization of integer comparison");
}
sb.append("if (").append(leftLiteral).append(operator).append(rightLiteral).append(") /* ").append(opName).append(" CustomJump */ ");
CustomJump newJump = CustomJump.create(jmp, sb.toString());
//jmp.setCustomCompareCode(sb.toString());
newJump.setOptimized(true);
instructions.add(iter, newJump);
instructionCount = instructions.size();
}
}
break;
}
case Opcodes.IFNONNULL:
case Opcodes.IFNULL:
case Opcodes.IFLE:
case Opcodes.IFLT:
case Opcodes.IFNE:
case Opcodes.IFGT:
case Opcodes.IFEQ:
case Opcodes.IFGE: {
String rightArg = "0";
if (currentOpcode == Opcodes.IFNONNULL || currentOpcode == Opcodes.IFNULL) {
rightArg = "JAVA_NULL";
}
if (iter > 0) {
Instruction leftArg = instructions.get(iter-1);
String leftLiteral = null;
if (leftArg instanceof AssignableExpression) {
StringBuilder sb = new StringBuilder();
if (((AssignableExpression)leftArg).assignTo(null, sb)) {
leftLiteral = sb.toString().trim();
}
} else if (leftArg instanceof CustomInvoke) {
CustomInvoke inv = (CustomInvoke)leftArg;
StringBuilder sb = new StringBuilder();
if (inv.appendExpression(sb)) {
leftLiteral = sb.toString().trim();
}
}
if (leftLiteral != null) {
Jump jmp = (Jump)current;
instructions.remove(iter-1);
instructions.remove(iter-1);
//instructions.remove(iter-2);
iter-=1;
//instructionCount -= 2;
StringBuilder sb = new StringBuilder();
String operator = null;
String opName = null;
switch (currentOpcode) {
case Opcodes.IFLE:
operator = "<="; opName = "IFLE"; break;
case Opcodes.IFLT:
operator = "<"; opName = "IFLT"; break;
case Opcodes.IFNE:
operator = "!="; opName = "IFNE"; break;
case Opcodes.IFGT:
operator = ">"; opName = "IFGT"; break;
case Opcodes.IFGE:
operator = ">="; opName = "IFGE"; break;
case Opcodes.IFEQ:
operator = "=="; opName = "IFEQ"; break;
case Opcodes.IFNULL:
operator = "=="; opName = "IFNULL"; break;
case Opcodes.IFNONNULL:
operator = "!="; opName = "IFNONNULL"; break;
default :
throw new RuntimeException("Invalid operator during optimization of integer comparison");
}
sb.append("if (").append(leftLiteral).append(operator).append(rightArg).append(") /* ").append(opName).append(" CustomJump */ ");
CustomJump newJump = CustomJump.create(jmp, sb.toString());
//jmp.setCustomCompareCode(sb.toString());
newJump.setOptimized(true);
instructions.add(iter, newJump);
instructionCount = instructions.size();
}
}
break;
}
case Opcodes.INVOKEVIRTUAL:
case Opcodes.INVOKESTATIC:
case Opcodes.INVOKESPECIAL:
case Opcodes.INVOKEINTERFACE: {
if (current instanceof Invoke) {
Invoke inv = (Invoke)current;
List invocationArgs = inv.getArgs();
int numArgs = invocationArgs.size();
//if (current.getOpcode() != Opcodes.INVOKESTATIC) {
// numArgs++;
//}
if (iter >= numArgs) {
String[] argLiterals = new String[numArgs];
StringBuilder devNull = new StringBuilder();
for (int i=0; i 0) {
if(staticMethod) {
instructions.add(iter, new CustomIntruction(" monitorExit(threadStateData, (JAVA_OBJECT)&class__" + clsName + ");\n" +
" return " + value + ";\n",
" monitorExit(threadStateData, (JAVA_OBJECT)&class__" + clsName + ");\n" +
" RETURN_AND_RELEASE_FROM_METHOD(" + value + ", " + maxLocals + ");\n", dependentClasses));
} else {
instructions.add(iter, new CustomIntruction(" monitorExit(threadStateData, __cn1ThisObject);\n" +
" return " + value + ";\n",
" monitorExit(threadStateData, __cn1ThisObject);\n" +
" RETURN_AND_RELEASE_FROM_METHOD(" + value + ", " + maxLocals + ");\n", dependentClasses));
}
} else {
instructions.add(iter, new CustomIntruction(" return " + value + ";\n",
" RETURN_AND_RELEASE_FROM_METHOD(" + value + ", " + maxLocals + ");\n", dependentClasses));
}
return true;
}
return false;
}
private int localsOffsetToArgOffset(int offset) {
int localsOffset = 0;
if(!staticMethod) {
localsOffset++;
}
for(int iter = 0 ; iter < arguments.size() ; iter++) {
ByteCodeMethodArg arg = arguments.get(iter);
if(localsOffset == offset) {
return iter + 1;
}
localsOffset++;
if(arg.isDoubleOrLong()) {
localsOffset++;
}
}
return -1;
}
// support for the SignatureSet interface
public boolean containsSignature(SignatureSet sig) {
return desc.equals(sig.getSignature());
}
public String getSignature() {
return desc;
}
@Override
public SignatureSet nextSignature() {
return null;
}
}