use of soot.SootClass in project robovm by robovm.
the class LambdaPlugin method transformMethod.
private void transformMethod(Config config, Clazz clazz, SootClass sootClass, SootMethod method, ModuleBuilder moduleBuilder) throws IOException {
if (!method.isConcrete()) {
return;
}
int tmpCounter = 0;
Body body = method.retrieveActiveBody();
PatchingChain<Unit> units = body.getUnits();
for (Unit unit = units.getFirst(); unit != null; unit = body.getUnits().getSuccOf(unit)) {
if (unit instanceof DefinitionStmt) {
if (((DefinitionStmt) unit).getRightOp() instanceof DynamicInvokeExpr) {
DynamicInvokeExpr expr = (DynamicInvokeExpr) ((DefinitionStmt) unit).getRightOp();
if (isLambdaBootstrapMethod(expr.getBootstrapMethodRef())) {
LambdaClassGenerator generator = null;
synchronized (generators) {
generator = generators.get(sootClass);
if (generator == null) {
generator = new LambdaClassGenerator();
generators.put(sootClass, generator);
}
}
List<Value> bsmArgs = expr.getBootstrapArgs();
SootClass caller = sootClass;
String invokedName = expr.getMethodRef().name();
SootMethodRef invokedType = expr.getMethodRef();
SootMethodType samMethodType = (SootMethodType) bsmArgs.get(0);
SootMethodHandle implMethod = (SootMethodHandle) bsmArgs.get(1);
SootMethodType instantiatedMethodType = (SootMethodType) bsmArgs.get(2);
try {
LambdaClass callSite = null;
List<Type> markerInterfaces = new ArrayList<>();
List<SootMethodType> bridgeMethods = new ArrayList<>();
if (expr.getBootstrapMethodRef().name().equals("altMetafactory")) {
int flags = ((IntConstant) bsmArgs.get(3)).value;
int bsmArgsIdx = 4;
if ((flags & FLAG_MARKERS) > 0) {
int count = ((IntConstant) bsmArgs.get(bsmArgsIdx++)).value;
for (int i = 0; i < count; i++) {
Object value = bsmArgs.get(bsmArgsIdx++);
if (value instanceof Type) {
markerInterfaces.add((Type) value);
} else if (value instanceof ClassConstant) {
String className = ((ClassConstant) value).getValue().replace('/', '.');
markerInterfaces.add(SootResolver.v().resolveClass(className, SootClass.HIERARCHY).getType());
}
}
}
if ((flags & FLAG_BRIDGES) > 0) {
int count = ((IntConstant) bsmArgs.get(bsmArgsIdx++)).value;
for (int i = 0; i < count; i++) {
bridgeMethods.add((SootMethodType) bsmArgs.get(bsmArgsIdx++));
}
}
}
// see issue #1087
if (bridgeMethods.size() == 0) {
SootClass targetType = SootResolver.v().resolveClass(invokedType.returnType().toString().replace('/', '.'), SootClass.SIGNATURES);
String samDescriptor = Types.getDescriptor(samMethodType.getParameterTypes(), samMethodType.getReturnType());
for (SootMethod targetTypeMethod : targetType.getMethods()) {
boolean isBridgeMethod = targetTypeMethod.getName().equals(invokedName);
isBridgeMethod &= targetTypeMethod.getName().equals(invokedName);
isBridgeMethod &= targetTypeMethod.getParameterCount() == samMethodType.getParameterTypes().size();
isBridgeMethod &= ((targetTypeMethod.getModifiers() & BRIDGE) != 0);
isBridgeMethod &= ((targetTypeMethod.getModifiers() & SYNTHETIC) != 0);
if (isBridgeMethod) {
String targetTypeMethodDesc = Types.getDescriptor(targetTypeMethod);
if (!targetTypeMethodDesc.equals(samDescriptor)) {
bridgeMethods.add(new BridgeMethodType(targetTypeMethod.getReturnType(), targetTypeMethod.getParameterTypes()));
}
}
}
}
// generate the lambda class
callSite = generator.generate(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType, markerInterfaces, bridgeMethods);
File f = clazz.getPath().getGeneratedClassFile(callSite.getLambdaClassName());
FileUtils.writeByteArrayToFile(f, callSite.getClassData());
// The lambda class is created after the caller is
// compiled.
// This prevents the triggering of a recompile of
// the caller.
f.setLastModified(clazz.lastModified());
SootClass lambdaClass = SootResolver.v().makeClassRef(callSite.getLambdaClassName().replace('/', '.'));
Local l = (Local) ((DefinitionStmt) unit).getLeftOp();
Type samType = callSite.getTargetMethodReturnType();
LinkedList<Unit> newUnits = new LinkedList<>();
if (callSite.getTargetMethodName().equals("<init>")) {
// Constant lambda. Create an instance once and
// reuse for
// every call.
String fieldName = lambdaClass.getName().substring(lambdaClass.getName().lastIndexOf('.') + 1);
SootField field = new SootField(fieldName, lambdaClass.getType(), Modifier.STATIC | Modifier.PRIVATE | Modifier.TRANSIENT | 0x1000);
method.getDeclaringClass().addField(field);
// l = LambdaClass.lambdaField
newUnits.add(Jimple.v().newAssignStmt(l, Jimple.v().newStaticFieldRef(field.makeRef())));
// if l != null goto succOfInvokedynamic
newUnits.add(Jimple.v().newIfStmt(Jimple.v().newNeExpr(l, NullConstant.v()), units.getSuccOf(unit)));
// $tmpX = new LambdaClass()
Local tmp = Jimple.v().newLocal("$tmp" + (tmpCounter++), lambdaClass.getType());
body.getLocals().add(tmp);
newUnits.add(Jimple.v().newAssignStmt(tmp, Jimple.v().newNewExpr(lambdaClass.getType())));
newUnits.add(Jimple.v().newInvokeStmt(Jimple.v().newSpecialInvokeExpr(tmp, Scene.v().makeConstructorRef(lambdaClass, Collections.<Type>emptyList()))));
// LambdaClass.lambdaField = $tmpX
newUnits.add(Jimple.v().newAssignStmt(Jimple.v().newStaticFieldRef(field.makeRef()), tmp));
// l = $tmpX
newUnits.add(Jimple.v().newAssignStmt(l, tmp));
} else {
// Static factory method returns the lambda to
// use.
newUnits.add(Jimple.v().newAssignStmt(l, Jimple.v().newStaticInvokeExpr(Scene.v().makeMethodRef(lambdaClass, callSite.getTargetMethodName(), callSite.getTargetMethodParameters(), samType, true), expr.getArgs())));
}
units.insertAfter(newUnits, unit);
units.remove(unit);
unit = newUnits.getLast();
} catch (Throwable e) {
// LambdaConversionException at runtime.
throw new CompilerException(e);
}
}
}
}
}
}
use of soot.SootClass in project robovm by robovm.
the class ObjCBlockPlugin method getBlockTargetMethod.
protected static SootMethod getBlockTargetMethod(SootMethod method) {
soot.Type type = method.getReturnType();
if (!(type instanceof RefType)) {
throw new CompilerException("@Block annotated return type of method " + method + " must be of interface type");
}
SootClass blockType = ((RefType) type).getSootClass();
if (!blockType.isInterface()) {
throw new CompilerException("@Block annotated parameter return type " + "of method " + method + " must be of interface type");
}
List<SootMethod> allMethods = collectAbstractMethods(blockType);
if (allMethods.isEmpty()) {
throw new CompilerException("No abstract method found in interface " + blockType + " used in @Block annotated return type of method " + method);
}
if (allMethods.size() > 1) {
throw new CompilerException("More than 1 abstract method found in interface " + blockType + " used in @Block annotated return type of method " + method);
}
return allMethods.get(0);
}
use of soot.SootClass in project robovm by robovm.
the class ObjCProtocolProxyPlugin method beforeClass.
@Override
public void beforeClass(Config config, Clazz clazz, ModuleBuilder moduleBuilder) {
init();
SootClass sootClass = clazz.getSootClass();
if (isObjCProtocol(sootClass)) {
try {
String proxyInternalName = clazz.getInternalName() + PROXY_CLASS_NAME_SUFFIX;
ArrayList<String> interfazes = new ArrayList<>();
collectProxyInterfaceInternalNames(sootClass, interfazes);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cw.visit(51, ACC_SUPER + ACC_FINAL + ACC_SYNTHETIC + ACC_PUBLIC, proxyInternalName, null, getProxySuperclassInternalName(sootClass), new String[] { clazz.getInternalName() });
generateProxyMethods(config, interfazes, cw);
cw.visitEnd();
File f = clazz.getPath().getGeneratedClassFile(proxyInternalName);
FileUtils.writeByteArrayToFile(f, cw.toByteArray());
// The proxy class is created after the interface is compiled.
// This prevents the triggering of a recompile of the interface.
f.setLastModified(clazz.lastModified());
// Add the proxy class as a dependency for the protocol interface.
// Important! This must be done AFTER the class file has been written.
clazz.getClazzInfo().addClassDependency(proxyInternalName, false);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
use of soot.SootClass in project robovm by robovm.
the class ObjCBlockPlugin method beforeClass.
@Override
public void beforeClass(Config config, Clazz clazz, ModuleBuilder moduleBuilder) throws IOException {
init();
SootClass sootClass = clazz.getSootClass();
if (!sootClass.isInterface()) {
Map<String, Integer> blockTypeIds = new HashMap<>();
for (SootMethod method : sootClass.getMethods()) {
if (method.isNative() && hasBridgeAnnotation(method) || hasCallbackAnnotation(method)) {
int[] indexes = getBlockParameterIndexes(method);
if (indexes != null || hasAnnotation(method, BLOCK)) {
transformMethod(config, clazz, method, indexes, blockTypeIds);
}
}
}
}
}
use of soot.SootClass in project robovm by robovm.
the class ObjCBlockPlugin method getBlockTargetMethod.
protected static SootMethod getBlockTargetMethod(SootMethod method, int paramIndex) {
soot.Type type = method.getParameterType(paramIndex);
if (!(type instanceof RefType)) {
throw new CompilerException("@Block annotated parameter " + (paramIndex + 1) + " of method " + method + " must be of interface type");
}
SootClass blockType = ((RefType) type).getSootClass();
if (!blockType.isInterface()) {
throw new CompilerException("@Block annotated parameter " + (paramIndex + 1) + " of method " + method + " must be of interface type");
}
List<SootMethod> allMethods = collectAbstractMethods(blockType);
if (allMethods.isEmpty()) {
throw new CompilerException("No abstract method found in interface " + blockType + " used in @Block annotated parameter " + (paramIndex + 1) + " of method " + method);
}
if (allMethods.size() > 1) {
throw new CompilerException("More than 1 abstract method found in interface " + blockType + " used in @Block annotated parameter " + (paramIndex + 1) + " of method " + method);
}
return allMethods.get(0);
}
Aggregations