org.robovm.compiler.MarshalerLookup Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2013 RoboVM AB
*
* 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 2
* 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 .
*/
package org.robovm.compiler;
import static org.robovm.compiler.Annotations.*;
import static org.robovm.compiler.Types.*;
import static org.robovm.compiler.llvm.Type.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.robovm.compiler.clazz.Clazz;
import org.robovm.compiler.config.Arch;
import org.robovm.compiler.config.Config;
import org.robovm.compiler.llvm.Type;
import org.robovm.compiler.trampoline.Invokestatic;
import soot.ArrayType;
import soot.BooleanType;
import soot.ByteType;
import soot.CharType;
import soot.DoubleType;
import soot.FloatType;
import soot.IntType;
import soot.LongType;
import soot.PrimType;
import soot.RefLikeType;
import soot.RefType;
import soot.Scene;
import soot.ShortType;
import soot.SootClass;
import soot.SootMethod;
import soot.SootResolver;
import soot.VoidType;
import soot.tagkit.AnnotationArrayElem;
import soot.tagkit.AnnotationClassElem;
import soot.tagkit.AnnotationElem;
import soot.tagkit.AnnotationLongElem;
import soot.tagkit.AnnotationTag;
import soot.tagkit.InnerClassTag;
import soot.tagkit.Tag;
/**
* Looks up Bro marshalers.
*/
public class MarshalerLookup {
private final String BUILTIN_MARSHALERS = "org/robovm/rt/bro/BuiltinMarshalers";
private final Config config;
private final Map> cache = new HashMap<>();
private boolean searchBuiltins = true;
public MarshalerLookup(Config config) {
this.config = config;
}
/**
* Sets whether a call to {@link #findMarshalers(Clazz)} should include
* the builtin marshalers.
*
* @param b {@code true} to include builtins, {@code false} otherwise.
* @return this {@link MarshalerLookup}.
*/
public MarshalerLookup searchBuiltins(boolean b) {
this.searchBuiltins = b;
return this;
}
public Marshaler findMarshalers(MarshalSite marshalSite) {
soot.Type type = marshalSite.getType();
SootClass sc = null;
if (type instanceof RefType) {
sc = ((RefType) type).getSootClass();
} else if (type instanceof ArrayType && ((ArrayType) type).baseType instanceof RefType) {
sc = ((RefType) ((ArrayType) type).baseType).getSootClass();
}
List result = new ArrayList<>();
Set visited = new HashSet<>();
Set seen = new HashSet<>();
if (sc != null) {
findMarshalers(sc, result, visited, seen, false);
}
findMarshalers(marshalSite.method.getDeclaringClass(), result, visited, seen, searchBuiltins);
for (Marshaler marshaler : result) {
if (marshaler.canMarshal(marshalSite)) {
return marshaler;
}
}
return null;
}
public List findMarshalers(SootClass sc) {
List result = new ArrayList<>();
Set visited = new HashSet<>();
Set seen = new HashSet<>();
findMarshalers(sc, result, visited, seen, searchBuiltins);
return result;
}
private void findMarshalers(SootClass sc, List result,
Set visited, Set seen, boolean searchBuiltins) {
findMarshalersOnClasses(sc, result, visited, seen);
findMarshalersOnInterfaces(sc, result, visited, seen);
findMarshalersOnOuterClasses(sc, result, visited, seen);
if (searchBuiltins) {
Clazz builtinMarshalersClazz = config.getClazzes().load(BUILTIN_MARSHALERS);
if (builtinMarshalersClazz != null) {
findMarshalersOnClasses(builtinMarshalersClazz.getSootClass(),
result, visited, seen);
}
}
}
public MarshalerMethod findMarshalerMethod(MarshalSite marshalSite) {
int pidx = marshalSite.paramIdx;
if (pidx != MarshalSite.RECEIVER) {
// Use @Marshaler annotation on method or parameter at paramIndex if there is one
AnnotationTag anno = pidx == MarshalSite.RETURN_TYPE
? getMarshalerAnnotation(marshalSite.method)
: getMarshalerAnnotation(marshalSite.method, pidx);
if (anno != null) {
AnnotationClassElem elem = (AnnotationClassElem) getElemByName(anno, "value");
String name = getInternalNameFromDescriptor(elem.getDesc());
Clazz marshalerClazz = config.getClazzes().load(name);
if (marshalerClazz != null) {
Marshaler marshaler = new Marshaler(marshalerClazz);
if (marshaler.canMarshal(marshalSite)) {
return marshaler.getMarshalerMethod(marshalSite);
}
}
throw new IllegalArgumentException(String.format(
"@Marshaler %s specified for %s of %s method %s can "
+ "not be used to marshal %s",
name.replace('/', '.'),
(pidx == MarshalSite.RETURN_TYPE ? "return type" : "parameter " + (pidx + 1)),
marshalSite.callTypeName, marshalSite.method, marshalSite.type));
}
}
Marshaler marshaler = findMarshalers(marshalSite);
if (marshaler != null) {
return marshaler.getMarshalerMethod(marshalSite);
}
throw new IllegalArgumentException(String.format(
"No @Marshaler found for %s of %s method %s",
(pidx == MarshalSite.RECEIVER ? "receiver"
: (pidx == MarshalSite.RETURN_TYPE ? "return type"
: "parameter " + (pidx + 1))),
marshalSite.callTypeName, marshalSite.method));
}
private void findMarshalersOnClasses(SootClass sc, List result,
Set visited, Set seen) {
SootResolver.v().bringToHierarchy(sc);
result.addAll(findMarshalersOn(sc, visited, seen));
if (sc.hasSuperclass()) {
findMarshalersOnClasses(sc.getSuperclass(), result, visited, seen);
}
}
private void findMarshalersOnInterfaces(SootClass sc, List result,
Set visited, Set seen) {
SootResolver.v().bringToHierarchy(sc);
for (SootClass ifs : sc.getInterfaces()) {
result.addAll(findMarshalersOn(ifs, visited, seen));
}
for (SootClass ifs : sc.getInterfaces()) {
findMarshalersOnInterfaces(ifs, result, visited, seen);
}
if (sc.hasSuperclass()) {
findMarshalersOnInterfaces(sc.getSuperclass(), result, visited, seen);
}
}
private void findMarshalersOnOuterClasses(SootClass sc, List result,
Set visited, Set seen) {
SootClass outer = getOuterClass(sc);
if (outer != null) {
findMarshalersOnClasses(outer, result, visited, seen);
findMarshalersOnInterfaces(outer, result, visited, seen);
findMarshalersOnOuterClasses(outer, result, visited, seen);
}
}
private List findMarshalersOn(SootClass sc, Set visited, Set seen) {
String internalName = getInternalName(sc);
if (visited.contains(internalName)) {
return Collections.emptyList();
}
visited.contains(internalName);
List all = cache.get(sc.getName());
if (all == null) {
all = new ArrayList<>();
for (AnnotationTag tag : getMarshalerAnnotations(sc)) {
AnnotationClassElem elem = (AnnotationClassElem) getElemByName(tag, "value");
String name = getInternalNameFromDescriptor(elem.getDesc());
Clazz marshalerClazz = config.getClazzes().load(name);
if (marshalerClazz != null) {
all.add(new Marshaler(marshalerClazz));
}
}
cache.put(sc.getName(), all);
}
List result = new ArrayList<>();
for (Marshaler m : all) {
String name = m.clazz.getInternalName();
if (!seen.contains(name)) {
seen.add(name);
result.add(m);
}
}
return result;
}
private SootClass getOuterClass(SootClass clazz) {
String name = getInternalName(clazz);
for (Tag tag : clazz.getTags()) {
if (tag instanceof InnerClassTag) {
InnerClassTag innerClassTag = (InnerClassTag) tag;
String inner = innerClassTag.getInnerClass();
String outer = innerClassTag.getOuterClass();
if (inner != null && outer != null && inner.equals(name)) {
return config.getClazzes().load(outer).getSootClass();
}
}
}
return null;
}
private Set getSupportedCallTypes(AnnotationTag anno) {
AnnotationArrayElem el =
(AnnotationArrayElem) getElemByName(anno, "supportedCallTypes");
if (el == null) {
return new HashSet(Arrays.asList(
Bro.MarshalerFlags.CALL_TYPE_BRIDGE,
Bro.MarshalerFlags.CALL_TYPE_CALLBACK,
Bro.MarshalerFlags.CALL_TYPE_STRUCT_MEMBER,
Bro.MarshalerFlags.CALL_TYPE_GLOBAL_VALUE,
Bro.MarshalerFlags.CALL_TYPE_PTR
));
}
ArrayList values = ((AnnotationArrayElem) el).getValues();
Set callTypes = new HashSet<>();
for (AnnotationElem value : values) {
callTypes.add(((AnnotationLongElem) value).getValue());
}
return callTypes;
}
private soot.Type getBaseType(SootMethod m, AnnotationTag anno) {
AnnotationClassElem el = (AnnotationClassElem) getElemByName(anno, "baseType");
if (el != null) {
switch (el.getDesc().charAt(0)) {
case 'Z': return BooleanType.v();
case 'B': return ByteType.v();
case 'S': return ShortType.v();
case 'C': return CharType.v();
case 'I': return IntType.v();
case 'J': return LongType.v();
case 'F': return FloatType.v();
case 'D': return DoubleType.v();
}
return null;
}
soot.Type t = m.getReturnType();
if (t == VoidType.v()) {
t = m.getParameterType(0);
}
if (t instanceof RefType) {
SootClass c = ((RefType) t).getSootClass();
if (isInstanceOfClass(c, "java.nio.ByteBuffer")) {
return ByteType.v();
} else if (isInstanceOfClass(c, "java.nio.ShortBuffer")) {
return ShortType.v();
} else if (isInstanceOfClass(c, "java.nio.CharBuffer")) {
return CharType.v();
} else if (isInstanceOfClass(c, "java.nio.IntBuffer")) {
return IntType.v();
} else if (isInstanceOfClass(c, "java.nio.LongBuffer")) {
return LongType.v();
} else if (isInstanceOfClass(c, "java.nio.FloatBuffer")) {
return FloatType.v();
} else if (isInstanceOfClass(c, "java.nio.DoubleBuffer")) {
return DoubleType.v();
} else if (isInstanceOfClass(c, "org.robovm.rt.bro.Struct")) {
return config.getClazzes().load("org/robovm/rt/bro/Struct")
.getSootClass().getType();
}
} else if (t instanceof ArrayType) {
ArrayType arrayType = (ArrayType) t;
if (arrayType.baseType instanceof PrimType
|| isInstanceOfClass(arrayType.baseType, "org.robovm.rt.bro.Struct")) {
return arrayType.baseType;
}
}
return null;
}
public static class MarshalSite {
public static final int RETURN_TYPE = -1;
public static final int RECEIVER = -2;
private final SootMethod method;
private final int paramIdx;
private final long callType;
private final String callTypeName;
private final soot.Type type;
private final boolean array;
public MarshalSite(SootMethod method) {
this(method, RETURN_TYPE);
}
public MarshalSite(SootMethod method, int paramIdx) {
this.method = method;
this.paramIdx = paramIdx;
this.type = paramIdx == RETURN_TYPE ? method.getReturnType() :
(paramIdx == RECEIVER ? method.getDeclaringClass().getType()
: method.getParameterType(paramIdx));
if (hasBridgeAnnotation(method)) {
callType = Bro.MarshalerFlags.CALL_TYPE_BRIDGE;
callTypeName = "@Bridge";
array = false;
} else if (hasCallbackAnnotation(method)) {
callType = Bro.MarshalerFlags.CALL_TYPE_CALLBACK;
callTypeName = "@Callback";
array = false;
} else if (hasStructMemberAnnotation(method)) {
callType = Bro.MarshalerFlags.CALL_TYPE_STRUCT_MEMBER;
callTypeName = "@StructMember";
array = paramIdx == RETURN_TYPE ? hasArrayAnnotation(method)
: hasArrayAnnotation(method, paramIdx);
} else if (hasGlobalValueAnnotation(method)) {
callType = Bro.MarshalerFlags.CALL_TYPE_GLOBAL_VALUE;
callTypeName = "@GlobalValue";
array = paramIdx == RETURN_TYPE ? hasArrayAnnotation(method)
: hasArrayAnnotation(method, paramIdx);
} else {
throw new IllegalArgumentException();
}
}
public SootMethod getMethod() {
return method;
}
public long getCallType() {
return callType;
}
public soot.Type getType() {
return type;
}
public boolean isToNative() {
if (callType == Bro.MarshalerFlags.CALL_TYPE_CALLBACK) {
return paramIdx == RETURN_TYPE;
} else {
return paramIdx != RETURN_TYPE;
}
}
public boolean isArray() {
return array;
}
}
public abstract class MarshalerMethod {
protected final SootMethod method;
protected final Set supportedCallTypes;
MarshalerMethod(SootMethod method, Set supportedCallTypes) {
this.method = method;
this.supportedCallTypes = supportedCallTypes;
}
public SootMethod getMethod() {
return method;
}
public boolean supportsCallType(long callType) {
return supportedCallTypes.contains(callType);
}
public Invokestatic getInvokeStatic(SootClass caller) {
return new Invokestatic(
getInternalName(caller),
getInternalName(method.getDeclaringClass()),
method.getName(),
getDescriptor(method));
}
}
public class PointerMarshalerMethod extends MarshalerMethod {
private boolean hasSearchedForAfterBridgeCallMethod = false;
private SootMethod afterBridgeCallMethod = null;
private boolean hasSearchedForAfterCallbackCallMethod = false;
private SootMethod afterCallbackCallMethod = null;
PointerMarshalerMethod(SootMethod method, Set supportedCallTypes) {
super(method, supportedCallTypes);
}
public SootMethod getAfterBridgeCallMethod() {
if (hasSearchedForAfterBridgeCallMethod) {
return afterBridgeCallMethod;
}
hasSearchedForAfterBridgeCallMethod = true;
List paramTypes = Arrays.asList(method.getParameterType(0), LongType.v(), LongType.v());
for (SootMethod m : method.getDeclaringClass().getMethods()) {
if (hasAfterBridgeCallAnnotation(m)) {
if (m.getReturnType() == VoidType.v()
&& m.getParameterTypes().equals(paramTypes)) {
afterBridgeCallMethod = m;
break;
}
}
}
return afterBridgeCallMethod;
}
public SootMethod getAfterCallbackCallMethod() {
if (hasSearchedForAfterCallbackCallMethod) {
return afterCallbackCallMethod;
}
hasSearchedForAfterCallbackCallMethod = true;
List paramTypes = Arrays.asList(LongType.v(), method.getReturnType(), LongType.v());
for (SootMethod m : method.getDeclaringClass().getMethods()) {
if (hasAfterCallbackCallAnnotation(m)) {
if (m.getReturnType() == VoidType.v()
&& m.getParameterTypes().equals(paramTypes)) {
afterCallbackCallMethod = m;
break;
}
}
}
return afterCallbackCallMethod;
}
}
public class ValueMarshalerMethod extends MarshalerMethod {
ValueMarshalerMethod(SootMethod method, Set supportedCallTypes) {
super(method, supportedCallTypes);
}
public Type getNativeType(Arch arch) {
if (method.getReturnType() instanceof PrimType) {
if (hasPointerAnnotation(method)) {
return I8_PTR;
}
if (arch.is32Bit() && (hasMachineSizedSIntAnnotation(method)
|| hasMachineSizedUIntAnnotation(method))) {
return I32;
}
if (arch.is32Bit() && (hasMachineSizedFloatAnnotation(method))) {
return FLOAT;
}
if (!arch.is32Bit() && (hasMachineSizedFloatAnnotation(method))) {
return DOUBLE;
}
return Types.getType(method.getReturnType());
} else {
if (hasPointerAnnotation(method, 1)) {
return I8_PTR;
}
if (arch.is32Bit() && (hasMachineSizedSIntAnnotation(method, 1)
|| hasMachineSizedUIntAnnotation(method, 1))) {
return I32;
}
if (arch.is32Bit() && (hasMachineSizedFloatAnnotation(method, 1))) {
return FLOAT;
}
if (!arch.is32Bit() && (hasMachineSizedFloatAnnotation(method, 1))) {
return DOUBLE;
}
return Types.getType(method.getParameterType(1));
}
}
}
public class ArrayMarshalerMethod extends MarshalerMethod {
private final soot.Type baseType;
ArrayMarshalerMethod(SootMethod method, Set supportedCallTypes, soot.Type baseType) {
super(method, supportedCallTypes);
this.baseType = baseType;
}
public soot.Type getBaseType() {
return baseType;
}
}
public class Marshaler {
private final Clazz clazz;
private Map toObjectMethods = null;
private Map toNativeMethods = null;
private Map> toArrayObjectMethods = null;
private Map> toNativeArrayMethods = null;
private Marshaler(Clazz clazz) {
this.clazz = clazz;
}
private boolean isToObject(SootMethod m, AnnotationTag pointerAnno,
AnnotationTag valueAnno, AnnotationTag arrayAnno) {
// The method must be annotated
if (pointerAnno == null && valueAnno == null && arrayAnno == null) {
return false;
}
// Fail if there are several annotations
if (pointerAnno != null && (valueAnno != null || arrayAnno != null)
|| (valueAnno != null && arrayAnno != null)) {
return false;
}
// All toObject(...) methods take at least 3 parameters
@SuppressWarnings("unchecked")
List paramTypes = m.getParameterTypes();
if (paramTypes.size() < 3) {
return false;
}
// All toObject(...) methods take a Class as first parameter
if (!(paramTypes.get(0) instanceof RefType)) {
return false;
}
SootClass sc = ((RefType) paramTypes.get(0)).getSootClass();
if (!sc.getName().equals("java.lang.Class")) {
return false;
}
soot.Type returnType = m.getReturnType();
if (pointerAnno != null) {
// T toObject(Class> cls, long handle, long flags)
if (!(returnType instanceof RefLikeType)) {
return false;
}
if (paramTypes.size() == 3) {
if (paramTypes.get(1) == LongType.v()
&& paramTypes.get(2) == LongType.v()) {
return true;
}
}
} else if (valueAnno != null) {
// T toObject(Class> cls, value, long flags)
if (!(returnType instanceof RefLikeType)) {
return false;
}
if (paramTypes.size() == 3) {
if (paramTypes.get(1) instanceof PrimType
&& paramTypes.get(2) == LongType.v()) {
if (hasPointerAnnotation(m, 1)) {
return paramTypes.get(1).equals(LongType.v());
}
if (hasMachineSizedFloatAnnotation(m, 1)) {
return paramTypes.get(1).equals(FloatType.v())
|| paramTypes.get(1).equals(DoubleType.v());
}
if (hasMachineSizedSIntAnnotation(m, 1)) {
return paramTypes.get(1).equals(LongType.v());
}
if (hasMachineSizedUIntAnnotation(m, 1)) {
return paramTypes.get(1).equals(LongType.v());
}
return true;
}
}
} else if (arrayAnno != null) {
// T toObject(Class> cls, long handle, long flags, int d1[, int d2[, int d3]])
if (!(returnType instanceof RefLikeType)) {
return false;
}
if (getBaseType(m, arrayAnno) == null) {
return false;
}
if (paramTypes.size() > 3) {
if (paramTypes.get(1) == LongType.v()
&& paramTypes.get(2) == LongType.v()) {
for (int i = 3; i < paramTypes.size(); i++) {
if (paramTypes.get(i) != IntType.v()) {
return false;
}
}
return true;
}
}
}
return false;
}
private boolean isToNative(SootMethod m, AnnotationTag pointerAnno,
AnnotationTag valueAnno, AnnotationTag arrayAnno) {
// The method must be annotated
if (pointerAnno == null && valueAnno == null && arrayAnno == null) {
return false;
}
// Fail if there are several annotations
if (pointerAnno != null && (valueAnno != null || arrayAnno != null)
|| (valueAnno != null && arrayAnno != null)) {
return false;
}
// All toNative(...) methods take at least 2 parameters
@SuppressWarnings("unchecked")
List paramTypes = m.getParameterTypes();
if (paramTypes.size() < 2) {
return false;
}
// All toNative(...) methods take a reference as first parameter
if (!(paramTypes.get(0) instanceof RefLikeType)) {
return false;
}
soot.Type returnType = m.getReturnType();
if (pointerAnno != null) {
// long toNative(T t, long flags)
if (returnType != LongType.v()) {
return false;
}
if (paramTypes.size() == 2) {
if (paramTypes.get(1) == LongType.v()) {
return true;
}
}
} else if (valueAnno != null) {
// toNative(T value, long flags)
if (!(returnType instanceof PrimType)) {
return false;
}
if (paramTypes.size() == 2) {
if (paramTypes.get(1) == LongType.v()) {
if (hasPointerAnnotation(m)) {
return returnType.equals(LongType.v());
}
if (hasMachineSizedFloatAnnotation(m)) {
return returnType.equals(FloatType.v())
|| returnType.equals(DoubleType.v());
}
if (hasMachineSizedSIntAnnotation(m)) {
return returnType.equals(LongType.v());
}
if (hasMachineSizedUIntAnnotation(m)) {
return returnType.equals(LongType.v());
}
return true;
}
}
} else if (arrayAnno != null) {
// void toNative(T t, long handle, long flags, int d1[, int d2[, int d3]])
if (returnType != VoidType.v()) {
return false;
}
if (getBaseType(m, arrayAnno) == null) {
return false;
}
if (paramTypes.size() > 3) {
if (paramTypes.get(1) == LongType.v()
&& paramTypes.get(2) == LongType.v()) {
for (int i = 3; i < paramTypes.size(); i++) {
if (paramTypes.get(i) != IntType.v()) {
return false;
}
}
return true;
}
}
}
return false;
}
private void buildMaps() {
if (toObjectMethods == null && toNativeMethods == null
&& toArrayObjectMethods == null && toNativeArrayMethods == null) {
toObjectMethods = new HashMap<>();
toNativeMethods = new HashMap<>();
toArrayObjectMethods = new HashMap<>();
toNativeArrayMethods = new HashMap<>();
for (SootMethod m : clazz.getSootClass().getMethods()) {
if (m.isStatic() && m.isPublic()) {
AnnotationTag pointerAnno = getMarshalsPointerAnnotation(m);
AnnotationTag valueAnno = getMarshalsValueAnnotation(m);
AnnotationTag arrayAnno = getMarshalsArrayAnnotation(m);
if (isToObject(m, pointerAnno, valueAnno, arrayAnno)) {
AnnotationTag anno = pointerAnno != null ? pointerAnno
: (valueAnno != null ? valueAnno : arrayAnno);
Set supportedCallTypes = getSupportedCallTypes(anno);
if (pointerAnno != null) {
toObjectMethods.put(getDescriptor(m.getReturnType()),
new PointerMarshalerMethod(m, supportedCallTypes));
} else if (valueAnno != null) {
toObjectMethods.put(getDescriptor(m.getReturnType()),
new ValueMarshalerMethod(m, supportedCallTypes));
} else {
int dimCount = m.getParameterCount() - 3;
Map map = toArrayObjectMethods.get(dimCount);
if (map == null) {
map = new HashMap<>();
toArrayObjectMethods.put(dimCount, map);
}
map.put(getDescriptor(m.getReturnType()),
new ArrayMarshalerMethod(m, supportedCallTypes,
getBaseType(m, arrayAnno)));
}
} else if (isToNative(m, pointerAnno, valueAnno, arrayAnno)) {
AnnotationTag anno = pointerAnno != null ? pointerAnno
: (valueAnno != null ? valueAnno : arrayAnno);
Set supportedCallTypes = getSupportedCallTypes(anno);
if (pointerAnno != null) {
toNativeMethods.put(getDescriptor(m.getParameterType(0)),
new PointerMarshalerMethod(m, supportedCallTypes));
} else if (valueAnno != null) {
toNativeMethods.put(getDescriptor(m.getParameterType(0)),
new ValueMarshalerMethod(m, supportedCallTypes));
} else {
int dimCount = m.getParameterCount() - 3;
Map map = toNativeArrayMethods.get(dimCount);
if (map == null) {
map = new HashMap<>();
toNativeArrayMethods.put(dimCount, map);
}
map.put(getDescriptor(m.getParameterType(0)),
new ArrayMarshalerMethod(m, supportedCallTypes,
getBaseType(m, arrayAnno)));
}
} else if (pointerAnno != null || valueAnno != null || arrayAnno != null) {
config.getLogger().warn("Ignoring invalid marshaler method %s", m);
}
}
}
}
}
private soot.Type makeArrayType(soot.Type baseType, int numDimensions) {
soot.Type newType = baseType;
for (int i = 0; i < numDimensions; i++) {
newType = newType.makeArrayType();
}
return newType;
}
private MarshalerMethod findMarshalerMethod(soot.Type type, Map map) {
MarshalerMethod m = map.get(getDescriptor(type));
if (m != null) {
return m;
}
if (type instanceof RefType) {
SootClass sc = ((RefType) type).getSootClass();
if (sc.hasSuperclass()) {
m = findMarshalerMethod(sc.getSuperclass().getType(), map);
if (m != null) {
return m;
}
}
for (SootClass ifs : sc.getInterfaces()) {
m = findMarshalerMethod(ifs.getType(), map);
if (m != null) {
return m;
}
}
} else if (type instanceof ArrayType) {
ArrayType arrayType = (ArrayType) type;
if (arrayType.baseType instanceof RefType) {
SootClass sc = ((RefType) arrayType.baseType).getSootClass();
if (sc.hasSuperclass()) {
m = findMarshalerMethod(makeArrayType(sc.getSuperclass().getType(),
arrayType.numDimensions), map);
if (m != null) {
return m;
}
}
for (SootClass ifs : sc.getInterfaces()) {
m = findMarshalerMethod(makeArrayType(ifs.getType(),
arrayType.numDimensions), map);
if (m != null) {
return m;
}
}
}
}
return null;
}
public Clazz getClazz() {
return clazz;
}
public boolean canMarshal(MarshalSite marshalSite) {
return getMarshalerMethod(marshalSite) != null;
}
public MarshalerMethod getMarshalerMethod(MarshalSite marshalSite) {
buildMaps();
Map map = null;
if (marshalSite.isArray()) {
int dimCount = Bro.getArrayDimensions(marshalSite.method, marshalSite.paramIdx).length;
map = marshalSite.isToNative() ? toNativeArrayMethods.get(dimCount)
: toArrayObjectMethods.get(dimCount);
if (map == null) {
return null;
}
} else {
map = marshalSite.isToNative() ? toNativeMethods : toObjectMethods;
}
MarshalerMethod m = findMarshalerMethod(marshalSite.getType(), map);
if (m != null) {
if (m.supportsCallType(marshalSite.getCallType())) {
return m;
}
}
return null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy