/*
* This file is part of JOP, the Java Optimized Processor
* see <http://www.jopdesign.com/>
*
* Copyright (C) 2010, Stefan Hepp (stefan@stefant.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.common.processormodel;
import com.jopdesign.common.AppInfo;
import com.jopdesign.common.ClassInfo;
import com.jopdesign.common.MethodInfo;
import com.jopdesign.common.config.Config;
import com.jopdesign.common.misc.JavaClassFormatError;
import com.jopdesign.tools.JopInstr;
import org.apache.bcel.generic.ANEWARRAY;
import org.apache.bcel.generic.ATHROW;
import org.apache.bcel.generic.BasicType;
import org.apache.bcel.generic.FieldInstruction;
import org.apache.bcel.generic.GETFIELD;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.NEW;
import org.apache.bcel.generic.NEWARRAY;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUTFIELD;
import org.apache.bcel.generic.PUTSTATIC;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;
import org.apache.bcel.generic.VariableLengthInstruction;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author Stefan Hepp (stefan@stefant.org)
*/
public class JOPModel implements ProcessorModel {
public static final String JVM_CLASS = "com.jopdesign.sys.JVM";
public static final String STARTUP_CLASS = "com.jopdesign.sys.Startup";
public static final String JOP_NATIVE = "com.jopdesign.sys.Native";
public static final String BOOT_METHOD = "com.jopdesign.sys.Startup#boot()V";
private final String identifier;
private final JOPConfig config;
public static boolean isNewOp(Instruction ii) {
return (ii instanceof NEW || ii instanceof NEWARRAY || ii instanceof ANEWARRAY);
}
public static boolean isThrowOp(Instruction ii) {
return ii instanceof ATHROW;
}
public JOPModel(Config configData) {
StringBuilder key = new StringBuilder();
this.config = new JOPConfig(configData);
key.append("jop");
if(config.isCmp()) key.append("-cmp");
// TODO this may differ from WCETProcessorModel.getName(), check.
key.append("-").append(config.getMethodCacheImpl());
identifier = key.toString();
}
public String getName() {
return identifier;
}
public JOPConfig getConfig() {
return config;
}
public boolean isSpecialInvoke(MethodInfo context, Instruction i) {
if(! (i instanceof INVOKESTATIC)) return false;
INVOKESTATIC isi = (INVOKESTATIC) i;
ReferenceType refTy = isi.getReferenceType(context.getConstantPoolGen());
if(refTy instanceof ObjectType){
ObjectType objTy = (ObjectType) refTy;
String className = objTy.getClassName();
return (className.equals(JOP_NATIVE));
} else {
return false;
}
}
/* FIXME: [NO THROW HACK] */
public boolean isImplementedInJava(MethodInfo context, Instruction ii) {
return (JopInstr.isInJava(getNativeOpCode(context, ii))
// && !isNewOp(ii)
&& !isThrowOp(ii));
}
/* performance hot spot */
public int getNativeOpCode(MethodInfo context, Instruction instr) {
if(isSpecialInvoke(context,instr)) {
INVOKESTATIC isi = (INVOKESTATIC) instr;
String methodName = isi.getMethodName(context.getConstantPoolGen());
return JopInstr.getNative(methodName);
} else if(instr instanceof FieldInstruction) {
FieldInstruction finstr = (FieldInstruction) instr;
Type ftype = finstr.getFieldType(context.getConstantPoolGen());
boolean isRef = ftype instanceof ReferenceType;
boolean isLong = ftype == BasicType.LONG || ftype == BasicType.DOUBLE;
if (finstr instanceof GETSTATIC) {
if (isRef) {
return JopInstr.get("getstatic_ref");
} else if (isLong) {
return JopInstr.get("getstatic_long");
}
} else if (finstr instanceof PUTSTATIC) {
if (isRef) {
if (!com.jopdesign.build.JOPizer.USE_RTTM) { /* FIXME: This should not be hardcoded? */
return JopInstr.get("putstatic_ref");
}
} else if (isLong) {
return JopInstr.get("putstatic_long");
}
} else if (finstr instanceof GETFIELD) {
if (isRef) {
return JopInstr.get("getfield_ref");
} else if (isLong) {
return JopInstr.get("getfield_long");
}
} else if (finstr instanceof PUTFIELD) {
if (isRef) {
if (!com.jopdesign.build.JOPizer.USE_RTTM) { /* FIXME: This should not be hardcoded? */
return JopInstr.get("putfield_ref");
}
} else if (isLong) {
return JopInstr.get("putfield_long");
}
}
return instr.getOpcode();
} else {
return instr.getOpcode();
}
}
public MethodInfo getJavaImplementation(AppInfo ai, MethodInfo context, Instruction instr) {
ClassInfo receiver = ai.getClassInfo(JVM_CLASS);
String methodName = "f_" + JopInstr.name(getNativeOpCode(context, instr));
Set<MethodInfo> mi = receiver.getMethodByName(methodName);
if (!mi.isEmpty()) {
if (mi.size() > 1) {
throw new JavaClassFormatError("JVM class " + JVM_CLASS + " has more than one implementation of "
+ methodName);
}
return mi.iterator().next();
}
return null;
}
public int getNumberOfBytes(MethodInfo context, Instruction instruction) {
int opCode = getNativeOpCode(context, instruction);
if(opCode >= 0) {
// To correctly support TableSwitch,..
// TODO move this into JopInstr.len()?
if (instruction instanceof VariableLengthInstruction) {
return instruction.getLength();
}
return JopInstr.len(opCode);
}
else throw new AssertionError("Invalid opcode: "+context+" : "+instruction);
}
public List<String> getJVMClasses() {
List<String> jvmClasses = new ArrayList<String>(1);
jvmClasses.add(JVM_CLASS);
jvmClasses.add(STARTUP_CLASS);
return jvmClasses;
}
@Override
public List<String> getNativeClasses() {
List<String> jvmClasses = new ArrayList<String>(1);
jvmClasses.add(JOP_NATIVE);
return jvmClasses;
}
@Override
public List<String> getJVMRoots() {
List<String> roots = new ArrayList<String>(1);
// TODO anything else we need?
// Hardware objects, <clinit> are handled by AppSetup/UnusedCodeRemover, Runnables are always added as roots
roots.add(BOOT_METHOD);
return roots;
}
@Override
public boolean keepJVMClasses() {
// TODO maybe return enum here, keep only classes but allow removal of methods (or make them abstract?)
return true;
}
@Override
public int getMaxMethodSize() {
// TODO get this from cache config
return 512;
}
@Override
public int getMaxStackSize() {
return 32;
}
@Override
public int getMaxLocals() {
// TODO can this be changed for JOP?
return 32;
}
}