/*
* This file is part of JOP, the Java Optimized Processor
* see <http://www.jopdesign.com/>
*
* Copyright (C) 2011, 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.type;
import com.jopdesign.common.MethodInfo;
import com.jopdesign.common.misc.AppInfoError;
import org.apache.bcel.Constants;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ASTORE;
import org.apache.bcel.generic.BasicType;
import org.apache.bcel.generic.DLOAD;
import org.apache.bcel.generic.DSTORE;
import org.apache.bcel.generic.FLOAD;
import org.apache.bcel.generic.FSTORE;
import org.apache.bcel.generic.ILOAD;
import org.apache.bcel.generic.ISTORE;
import org.apache.bcel.generic.LLOAD;
import org.apache.bcel.generic.LSTORE;
import org.apache.bcel.generic.LoadInstruction;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.StoreInstruction;
import org.apache.bcel.generic.Type;
/**
* @author Stefan Hepp (stefan@stefant.org)
*/
public class TypeHelper {
public static int getNumSlots(Type[] types) {
if (types == null) return 0;
int i = 0;
for (Type t : types) {
i += t.getSize();
}
return i;
}
public static int getNumInvokeSlots(MethodInfo method) {
int slots = getNumSlots(method.getArgumentTypes());
if (!method.isStatic()) {
slots += 1;
}
return slots;
}
public static StoreInstruction createStoreInstruction(Type type, int slot) {
switch (type.getType()) {
case Constants.T_BOOLEAN:
case Constants.T_BYTE:
case Constants.T_CHAR:
case Constants.T_SHORT:
case Constants.T_INT:
return new ISTORE(slot);
case Constants.T_FLOAT:
return new FSTORE(slot);
case Constants.T_LONG:
return new LSTORE(slot);
case Constants.T_DOUBLE:
return new DSTORE(slot);
case Constants.T_OBJECT:
case Constants.T_ARRAY:
return new ASTORE(slot);
default:
throw new AppInfoError("Unsupported type "+type+" for slot "+slot);
}
}
public static LoadInstruction createLoadInstruction(Type type, int slot) {
switch (type.getType()) {
case Constants.T_BOOLEAN:
case Constants.T_BYTE:
case Constants.T_CHAR:
case Constants.T_SHORT:
case Constants.T_INT:
return new ILOAD(slot);
case Constants.T_FLOAT:
return new FLOAD(slot);
case Constants.T_LONG:
return new LLOAD(slot);
case Constants.T_DOUBLE:
return new DLOAD(slot);
case Constants.T_OBJECT:
case Constants.T_ARRAY:
return new ALOAD(slot);
default:
throw new AppInfoError("Unsupported type "+type+" for slot "+slot);
}
}
/**
* Check if we can assign something with type 'from' to something with type 'to'.
*
* @see ReferenceType#isAssignmentCompatibleWith(Type)
* @param from source type.
* @param to target type.
* @return true if source type can be implicitly converted to target type.
*/
public static boolean canAssign(Type from, Type to) {
// TODO should we do size-check first??
if (from.equals(Type.UNKNOWN) || to.equals(Type.UNKNOWN)) return true;
if (to.equals(Type.VOID)) return true;
if (from.getSize() != to.getSize()) return false;
if (from instanceof BasicType) {
if (!(to instanceof BasicType)) return false;
if (from.getType() == to.getType()) return true;
switch (from.getType()) {
case Constants.T_BOOLEAN:
return to.getType() == Constants.T_CHAR ||
to.getType() == Constants.T_SHORT ||
to.getType() == Constants.T_INT;
case Constants.T_CHAR:
return to.getType() == Constants.T_SHORT ||
to.getType() == Constants.T_INT;
case Constants.T_SHORT:
return to.getType() == Constants.T_INT;
default:
return false;
}
}
if (from instanceof ReferenceType) {
try {
return ((ReferenceType)from).isCastableTo(to);
} catch (ClassNotFoundException e) {
// TODO maybe silently ignore, just return true / false?
throw new AppInfoError("Error checking assignment from "+from+" to "+to, e);
}
}
// should not happen..
throw new AppInfoError("Unknown Type type "+from);
}
/**
* Check if an array of types is assignment-compatible to another array of types.
* If the arrays have different length, then the suffix of the longer one is compared to the shorter
* array.
*
* @see #canAssign(Type, Type)
* @param from source types
* @param to target types
* @return true if the types from source can be assigned to the target
*/
public static boolean canAssign(Type[] from, Type[] to) {
int p1 = (from.length > to.length) ? from.length - to.length : 0;
int p2 = (from.length < to.length) ? to.length - from.length : 0;
while (p1 < from.length) {
if (!canAssign(from[p1++], to[p2++])) {
return false;
}
}
return true;
}
}