use of soot.RefLikeType in project robovm by robovm.
the class MethodCompiler method assign.
private void assign(DefinitionStmt stmt) {
/*
* leftOp is either a Local, an ArrayRef or a FieldRef
* rightOp is either a Local, a Ref, or an Expr
*/
soot.Value rightOp = stmt.getRightOp();
Value result;
if (rightOp instanceof Immediate) {
Immediate immediate = (Immediate) rightOp;
result = immediate(stmt, immediate);
} else if (rightOp instanceof ThisRef) {
result = function.getParameterRef(1);
} else if (rightOp instanceof ParameterRef) {
ParameterRef ref = (ParameterRef) rightOp;
int index = (sootMethod.isStatic() ? 1 : 2) + ref.getIndex();
Value p = new VariableRef("p" + index, getType(ref.getType()));
result = widenToI32Value(stmt, p, isUnsigned(ref.getType()));
} else if (rightOp instanceof CaughtExceptionRef) {
result = call(stmt, BC_EXCEPTION_CLEAR, env);
} else if (rightOp instanceof ArrayRef) {
ArrayRef ref = (ArrayRef) rightOp;
VariableRef base = (VariableRef) immediate(stmt, (Immediate) ref.getBase());
if (ref.getType() instanceof NullType) {
// The base value is always null. Do a null check which will
// always throw NPE.
checkNull(stmt, base);
return;
} else {
Value index = immediate(stmt, (Immediate) ref.getIndex());
checkNull(stmt, base);
checkBounds(stmt, base, index);
result = call(stmt, getArrayLoad(ref.getType()), base, index);
result = widenToI32Value(stmt, result, isUnsigned(ref.getType()));
}
} else if (rightOp instanceof InstanceFieldRef) {
InstanceFieldRef ref = (InstanceFieldRef) rightOp;
Value base = immediate(stmt, (Immediate) ref.getBase());
checkNull(stmt, base);
FunctionRef fn = null;
if (canAccessDirectly(ref)) {
fn = new FunctionRef(Symbols.getterSymbol(ref.getFieldRef()), new FunctionType(getType(ref.getType()), ENV_PTR, OBJECT_PTR));
} else {
soot.Type runtimeType = ref.getBase().getType();
String targetClassName = getInternalName(ref.getFieldRef().declaringClass());
String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
Trampoline trampoline = new GetField(this.className, targetClassName, ref.getFieldRef().name(), getDescriptor(ref.getFieldRef().type()), runtimeClassName);
trampolines.add(trampoline);
fn = trampoline.getFunctionRef();
}
result = call(stmt, fn, env, base);
result = widenToI32Value(stmt, result, isUnsigned(ref.getType()));
} else if (rightOp instanceof StaticFieldRef) {
StaticFieldRef ref = (StaticFieldRef) rightOp;
FunctionRef fn = config.isDebug() ? null : Intrinsics.getIntrinsic(sootMethod, stmt);
if (fn == null) {
if (canAccessDirectly(ref)) {
fn = new FunctionRef(Symbols.getterSymbol(ref.getFieldRef()), new FunctionType(getType(ref.getType()), ENV_PTR));
} else {
String targetClassName = getInternalName(ref.getFieldRef().declaringClass());
Trampoline trampoline = new GetStatic(this.className, targetClassName, ref.getFieldRef().name(), getDescriptor(ref.getFieldRef().type()));
trampolines.add(trampoline);
fn = trampoline.getFunctionRef();
}
}
result = call(stmt, fn, env);
result = widenToI32Value(stmt, result, isUnsigned(ref.getType()));
} else if (rightOp instanceof Expr) {
if (rightOp instanceof BinopExpr) {
BinopExpr expr = (BinopExpr) rightOp;
Type rightType = getLocalType(expr.getType());
Variable resultVar = function.newVariable(rightType);
result = resultVar.ref();
Value op1 = immediate(stmt, (Immediate) expr.getOp1());
Value op2 = immediate(stmt, (Immediate) expr.getOp2());
if (rightOp instanceof AddExpr) {
if (rightType instanceof IntegerType) {
function.add(new Add(resultVar, op1, op2)).attach(stmt);
} else {
function.add(new Fadd(resultVar, op1, op2)).attach(stmt);
}
} else if (rightOp instanceof AndExpr) {
function.add(new And(resultVar, op1, op2)).attach(stmt);
} else if (rightOp instanceof CmpExpr) {
Variable t1 = function.newVariable(I1);
Variable t2 = function.newVariable(I1);
Variable t3 = function.newVariable(resultVar.getType());
Variable t4 = function.newVariable(resultVar.getType());
function.add(new Icmp(t1, Condition.slt, op1, op2)).attach(stmt);
function.add(new Icmp(t2, Condition.sgt, op1, op2)).attach(stmt);
function.add(new Zext(t3, new VariableRef(t1), resultVar.getType())).attach(stmt);
function.add(new Zext(t4, new VariableRef(t2), resultVar.getType())).attach(stmt);
function.add(new Sub(resultVar, new VariableRef(t4), new VariableRef(t3))).attach(stmt);
} else if (rightOp instanceof DivExpr) {
if (rightType instanceof IntegerType) {
FunctionRef f = rightType == I64 ? LDIV : IDIV;
result = call(stmt, f, env, op1, op2);
} else {
// float or double
function.add(new Fdiv(resultVar, op1, op2)).attach(stmt);
}
} else if (rightOp instanceof MulExpr) {
if (rightType instanceof IntegerType) {
function.add(new Mul(resultVar, op1, op2)).attach(stmt);
} else {
function.add(new Fmul(resultVar, op1, op2)).attach(stmt);
}
} else if (rightOp instanceof OrExpr) {
function.add(new Or(resultVar, op1, op2)).attach(stmt);
} else if (rightOp instanceof RemExpr) {
if (rightType instanceof IntegerType) {
FunctionRef f = rightType == I64 ? LREM : IREM;
result = call(stmt, f, env, op1, op2);
} else {
FunctionRef f = rightType == DOUBLE ? DREM : FREM;
result = call(stmt, f, env, op1, op2);
}
} else if (rightOp instanceof ShlExpr || rightOp instanceof ShrExpr || rightOp instanceof UshrExpr) {
IntegerType type = (IntegerType) op1.getType();
int bits = type.getBits();
Variable t = function.newVariable(op2.getType());
function.add(new And(t, op2, new IntegerConstant(bits - 1, (IntegerType) op2.getType()))).attach(stmt);
Value shift = t.ref();
if (((IntegerType) shift.getType()).getBits() < bits) {
Variable tmp = function.newVariable(type);
function.add(new Zext(tmp, shift, type)).attach(stmt);
shift = tmp.ref();
}
if (rightOp instanceof ShlExpr) {
function.add(new Shl(resultVar, op1, shift)).attach(stmt);
} else if (rightOp instanceof ShrExpr) {
function.add(new Ashr(resultVar, op1, shift)).attach(stmt);
} else {
function.add(new Lshr(resultVar, op1, shift)).attach(stmt);
}
} else if (rightOp instanceof SubExpr) {
if (rightType instanceof IntegerType) {
function.add(new Sub(resultVar, op1, op2)).attach(stmt);
} else {
function.add(new Fsub(resultVar, op1, op2)).attach(stmt);
}
} else if (rightOp instanceof XorExpr) {
function.add(new Xor(resultVar, op1, op2)).attach(stmt);
} else if (rightOp instanceof XorExpr) {
function.add(new Xor(resultVar, op1, op2)).attach(stmt);
} else if (rightOp instanceof CmplExpr) {
FunctionRef f = op1.getType() == FLOAT ? FCMPL : DCMPL;
function.add(new Call(resultVar, f, op1, op2)).attach(stmt);
} else if (rightOp instanceof CmpgExpr) {
FunctionRef f = op1.getType() == FLOAT ? FCMPG : DCMPG;
function.add(new Call(resultVar, f, op1, op2)).attach(stmt);
} else {
throw new IllegalArgumentException("Unknown type for rightOp: " + rightOp.getClass());
}
} else if (rightOp instanceof CastExpr) {
Value op = immediate(stmt, (Immediate) ((CastExpr) rightOp).getOp());
soot.Type sootTargetType = ((CastExpr) rightOp).getCastType();
soot.Type sootSourceType = ((CastExpr) rightOp).getOp().getType();
if (sootTargetType instanceof PrimType) {
Type targetType = getType(sootTargetType);
Type sourceType = getType(sootSourceType);
if (targetType instanceof IntegerType && sourceType instanceof IntegerType) {
// op is at least I32 and has already been widened if source type had fewer bits then I32
IntegerType toType = (IntegerType) targetType;
IntegerType fromType = (IntegerType) op.getType();
Variable v = function.newVariable(toType);
if (fromType.getBits() < toType.getBits()) {
// Widening
if (isUnsigned(sootSourceType)) {
function.add(new Zext(v, op, toType)).attach(stmt);
} else {
function.add(new Sext(v, op, toType)).attach(stmt);
}
} else if (fromType.getBits() == toType.getBits()) {
function.add(new Bitcast(v, op, toType)).attach(stmt);
} else {
// Narrow
function.add(new Trunc(v, op, toType)).attach(stmt);
}
result = widenToI32Value(stmt, v.ref(), isUnsigned(sootTargetType));
} else if (targetType instanceof FloatingPointType && sourceType instanceof IntegerType) {
// we always to a signed conversion since if op is char it has already been zero extended to I32
Variable v = function.newVariable(targetType);
function.add(new Sitofp(v, op, targetType)).attach(stmt);
result = v.ref();
} else if (targetType instanceof FloatingPointType && sourceType instanceof FloatingPointType) {
Variable v = function.newVariable(targetType);
if (targetType == FLOAT && sourceType == DOUBLE) {
function.add(new Fptrunc(v, op, targetType)).attach(stmt);
} else if (targetType == DOUBLE && sourceType == FLOAT) {
function.add(new Fpext(v, op, targetType)).attach(stmt);
} else {
function.add(new Bitcast(v, op, targetType)).attach(stmt);
}
result = v.ref();
} else {
// F2I, F2L, D2I, D2L
FunctionRef f = null;
if (targetType == I32 && sourceType == FLOAT) {
f = F2I;
} else if (targetType == I64 && sourceType == FLOAT) {
f = F2L;
} else if (targetType == I32 && sourceType == DOUBLE) {
f = D2I;
} else if (targetType == I64 && sourceType == DOUBLE) {
f = D2L;
} else {
throw new IllegalArgumentException();
}
Variable v = function.newVariable(targetType);
function.add(new Call(v, f, op)).attach(stmt);
result = v.ref();
}
} else {
if (sootTargetType instanceof soot.ArrayType && ((soot.ArrayType) sootTargetType).getElementType() instanceof PrimType) {
soot.Type primType = ((soot.ArrayType) sootTargetType).getElementType();
GlobalRef arrayClassPtr = new GlobalRef("array_" + getDescriptor(primType), CLASS_PTR);
Variable arrayClass = function.newVariable(CLASS_PTR);
function.add(new Load(arrayClass, arrayClassPtr)).attach(stmt);
result = call(stmt, CHECKCAST_PRIM_ARRAY, env, arrayClass.ref(), op);
} else {
String targetClassName = getInternalName(sootTargetType);
Trampoline trampoline = new Checkcast(this.className, targetClassName);
trampolines.add(trampoline);
result = call(stmt, trampoline.getFunctionRef(), env, op);
}
}
} else if (rightOp instanceof InstanceOfExpr) {
Value op = immediate(stmt, (Immediate) ((InstanceOfExpr) rightOp).getOp());
soot.Type checkType = ((InstanceOfExpr) rightOp).getCheckType();
if (checkType instanceof soot.ArrayType && ((soot.ArrayType) checkType).getElementType() instanceof PrimType) {
soot.Type primType = ((soot.ArrayType) checkType).getElementType();
GlobalRef arrayClassPtr = new GlobalRef("array_" + getDescriptor(primType), CLASS_PTR);
Variable arrayClass = function.newVariable(CLASS_PTR);
function.add(new Load(arrayClass, arrayClassPtr)).attach(stmt);
result = call(stmt, INSTANCEOF_PRIM_ARRAY, env, arrayClass.ref(), op);
} else {
String targetClassName = getInternalName(checkType);
Trampoline trampoline = new Instanceof(this.className, targetClassName);
trampolines.add(trampoline);
result = call(stmt, trampoline.getFunctionRef(), env, op);
}
} else if (rightOp instanceof NewExpr) {
String targetClassName = getInternalName(((NewExpr) rightOp).getBaseType());
FunctionRef fn = null;
if (targetClassName.equals(this.className)) {
fn = FunctionBuilder.allocator(sootMethod.getDeclaringClass()).ref();
} else {
Trampoline trampoline = new New(this.className, targetClassName);
trampolines.add(trampoline);
fn = trampoline.getFunctionRef();
}
result = call(stmt, fn, env);
} else if (rightOp instanceof NewArrayExpr) {
NewArrayExpr expr = (NewArrayExpr) rightOp;
Value size = immediate(stmt, (Immediate) expr.getSize());
if (expr.getBaseType() instanceof PrimType) {
result = call(stmt, getNewArray(expr.getBaseType()), env, size);
} else {
String targetClassName = getInternalName(expr.getType());
Trampoline trampoline = new Anewarray(this.className, targetClassName);
trampolines.add(trampoline);
result = call(stmt, trampoline.getFunctionRef(), env, size);
}
} else if (rightOp instanceof NewMultiArrayExpr) {
NewMultiArrayExpr expr = (NewMultiArrayExpr) rightOp;
if (expr.getBaseType().numDimensions == 1 && expr.getBaseType().getElementType() instanceof PrimType) {
Value size = immediate(stmt, (Immediate) expr.getSize(0));
result = call(stmt, getNewArray(expr.getBaseType().getElementType()), env, size);
} else {
for (int i = 0; i < expr.getSizeCount(); i++) {
Value size = immediate(stmt, (Immediate) expr.getSize(i));
Variable ptr = function.newVariable(new PointerType(I32));
function.add(new Getelementptr(ptr, dims.ref(), 0, i)).attach(stmt);
function.add(new Store(size, ptr.ref())).attach(stmt);
}
Variable dimsI32 = function.newVariable(new PointerType(I32));
function.add(new Bitcast(dimsI32, dims.ref(), dimsI32.getType())).attach(stmt);
String targetClassName = getInternalName(expr.getType());
Trampoline trampoline = new Multianewarray(this.className, targetClassName);
trampolines.add(trampoline);
result = call(stmt, trampoline.getFunctionRef(), env, new IntegerConstant(expr.getSizeCount()), dimsI32.ref());
}
} else if (rightOp instanceof InvokeExpr) {
result = invokeExpr(stmt, (InvokeExpr) rightOp);
} else if (rightOp instanceof LengthExpr) {
Value op = immediate(stmt, (Immediate) ((LengthExpr) rightOp).getOp());
checkNull(stmt, op);
Variable v = function.newVariable(I32);
function.add(new Call(v, ARRAY_LENGTH, op)).attach(stmt);
result = v.ref();
} else if (rightOp instanceof NegExpr) {
NegExpr expr = (NegExpr) rightOp;
Value op = immediate(stmt, (Immediate) expr.getOp());
Type rightType = op.getType();
Variable v = function.newVariable(op.getType());
if (rightType instanceof IntegerType) {
function.add(new Sub(v, new IntegerConstant(0, (IntegerType) rightType), op)).attach(stmt);
} else {
function.add(new Fmul(v, new FloatingPointConstant(-1.0, (FloatingPointType) rightType), op)).attach(stmt);
}
result = v.ref();
} else {
throw new IllegalArgumentException("Unknown type for rightOp: " + rightOp.getClass());
}
} else {
throw new IllegalArgumentException("Unknown type for rightOp: " + rightOp.getClass());
}
soot.Value leftOp = stmt.getLeftOp();
if (leftOp instanceof Local) {
Local local = (Local) leftOp;
VariableRef v = new VariableRef(local.getName(), new PointerType(getLocalType(leftOp.getType())));
function.add(new Store(result, v, !sootMethod.getActiveBody().getTraps().isEmpty())).attach(stmt);
} else {
Type leftType = getType(leftOp.getType());
Value narrowedResult = narrowFromI32Value(stmt, leftType, result);
if (leftOp instanceof ArrayRef) {
ArrayRef ref = (ArrayRef) leftOp;
VariableRef base = (VariableRef) immediate(stmt, (Immediate) ref.getBase());
Value index = immediate(stmt, (Immediate) ref.getIndex());
checkNull(stmt, base);
checkBounds(stmt, base, index);
if (leftOp.getType() instanceof RefLikeType) {
call(stmt, BC_SET_OBJECT_ARRAY_ELEMENT, env, base, index, narrowedResult);
} else {
call(stmt, getArrayStore(leftOp.getType()), base, index, narrowedResult);
}
} else if (leftOp instanceof InstanceFieldRef) {
InstanceFieldRef ref = (InstanceFieldRef) leftOp;
Value base = immediate(stmt, (Immediate) ref.getBase());
checkNull(stmt, base);
FunctionRef fn = null;
if (canAccessDirectly(ref)) {
fn = new FunctionRef(Symbols.setterSymbol(ref.getFieldRef()), new FunctionType(VOID, ENV_PTR, OBJECT_PTR, getType(ref.getType())));
} else {
soot.Type runtimeType = ref.getBase().getType();
String targetClassName = getInternalName(ref.getFieldRef().declaringClass());
String runtimeClassName = runtimeType == NullType.v() ? targetClassName : getInternalName(runtimeType);
Trampoline trampoline = new PutField(this.className, targetClassName, ref.getFieldRef().name(), getDescriptor(ref.getFieldRef().type()), runtimeClassName);
trampolines.add(trampoline);
fn = trampoline.getFunctionRef();
}
call(stmt, fn, env, base, narrowedResult);
} else if (leftOp instanceof StaticFieldRef) {
StaticFieldRef ref = (StaticFieldRef) leftOp;
FunctionRef fn = null;
if (canAccessDirectly(ref)) {
fn = new FunctionRef(Symbols.setterSymbol(ref.getFieldRef()), new FunctionType(VOID, ENV_PTR, getType(ref.getType())));
} else {
String targetClassName = getInternalName(ref.getFieldRef().declaringClass());
Trampoline trampoline = new PutStatic(this.className, targetClassName, ref.getFieldRef().name(), getDescriptor(ref.getFieldRef().type()));
trampolines.add(trampoline);
fn = trampoline.getFunctionRef();
}
call(stmt, fn, env, narrowedResult);
} else {
throw new IllegalArgumentException("Unknown type for leftOp: " + leftOp.getClass());
}
}
}
use of soot.RefLikeType in project robovm by robovm.
the class Types method getFields.
public static List<SootField> getFields(final OS os, final Arch arch, SootClass clazz, boolean ztatic) {
List<SootField> l = new ArrayList<SootField>();
for (SootField f : clazz.getFields()) {
if (ztatic == f.isStatic()) {
l.add(f);
}
}
// Sort the fields. references, volatile long, double, long, float, int, char, short, boolean, byte.
// Fields of same type are sorted by name.
Collections.sort(l, new Comparator<SootField>() {
@Override
public int compare(SootField o1, SootField o2) {
soot.Type t1 = o1.getType();
soot.Type t2 = o2.getType();
if (t1 instanceof RefLikeType) {
if (!(t2 instanceof RefLikeType)) {
return -1;
}
}
if (t2 instanceof RefLikeType) {
if (!(t1 instanceof RefLikeType)) {
return 1;
}
}
// Compare alignment. Higher first.
int align1 = getFieldAlignment(os, arch, o1);
int align2 = getFieldAlignment(os, arch, o2);
int c = new Integer(align2).compareTo(align1);
if (c == 0) {
// Compare size. Larger first.
int size1 = getFieldSize(arch, o1);
int size2 = getFieldSize(arch, o2);
c = new Integer(size2).compareTo(size1);
if (c == 0) {
// Compare type name.
c = t1.getClass().getSimpleName().compareTo(t2.getClass().getSimpleName());
if (c == 0) {
// Compare name.
c = o1.getName().compareTo(o2.getName());
}
}
}
return c;
}
});
return l;
}
use of soot.RefLikeType in project robovm by robovm.
the class ObjCMemberPlugin method createBridge.
private void createBridge(SootClass sootClass, SootMethod method, String selectorName, boolean strongRefSetter, boolean extensions) {
Jimple j = Jimple.v();
boolean usingGenericInstanceMethod = false;
SootMethod msgSendMethod = getMsgSendMethod(selectorName, method, extensions);
/*
* Add the method even if we might remove it later to make marshaler
* lookup on the method work as expected.
*/
sootClass.addMethod(msgSendMethod);
addBridgeAnnotation(msgSendMethod);
SootMethodRef msgSendMethodRef = getGenericMsgSendReplacementMethod(msgSendMethod);
if (!msgSendMethodRef.declaringClass().getType().equals(msgSendMethod.getDeclaringClass().getType())) {
/*
* There's a generic objc_msgSend method we can use. Remove
* msgSendMethod from the class.
*/
sootClass.removeMethod(msgSendMethod);
/*
* Can we use a generic <name>_instance method from $M? If we can we
* won't have to make a call to objc_msgSendSuper.
*/
if (!method.isStatic()) {
// Yes!
msgSendMethodRef = Scene.v().makeMethodRef(msgSendMethodRef.declaringClass(), msgSendMethodRef.name() + "_instance", msgSendMethodRef.parameterTypes(), msgSendMethodRef.returnType(), true);
usingGenericInstanceMethod = true;
}
}
SootMethodRef msgSendSuperMethodRef = null;
if (!usingGenericInstanceMethod && !extensions && !method.isStatic()) {
SootMethod msgSendSuperMethod = getMsgSendSuperMethod(selectorName, method);
/*
* Add the method even if we might remove it later to make marshaler
* lookup on the method work as expected.
*/
sootClass.addMethod(msgSendSuperMethod);
addBridgeAnnotation(msgSendSuperMethod);
msgSendSuperMethodRef = getGenericMsgSendSuperReplacementMethod(msgSendSuperMethod);
if (!msgSendSuperMethodRef.declaringClass().getType().equals(msgSendSuperMethod.getDeclaringClass().getType())) {
/*
* There's a generic objc_msgSendSuper method we can use. Remove
* msgSendSuperMethod from the class.
*/
sootClass.removeMethod(msgSendSuperMethod);
}
}
method.setModifiers(method.getModifiers() & ~NATIVE);
Body body = j.newBody(method);
method.setActiveBody(body);
PatchingChain<Unit> units = body.getUnits();
Local thiz = null;
if (extensions) {
thiz = j.newLocal("$this", method.getParameterType(0));
body.getLocals().add(thiz);
units.add(j.newIdentityStmt(thiz, j.newParameterRef(method.getParameterType(0), 0)));
} else if (!method.isStatic()) {
thiz = j.newLocal("$this", sootClass.getType());
body.getLocals().add(thiz);
units.add(j.newIdentityStmt(thiz, j.newThisRef(sootClass.getType())));
}
LinkedList<Value> args = new LinkedList<>();
for (int i = extensions ? 1 : 0; i < method.getParameterCount(); i++) {
Type t = method.getParameterType(i);
Local p = j.newLocal("$p" + i, t);
body.getLocals().add(p);
units.add(j.newIdentityStmt(p, j.newParameterRef(t, i)));
args.add(p);
}
Local objCClass = null;
if (!extensions && method.isStatic()) {
objCClass = j.newLocal("$objCClass", org_robovm_objc_ObjCClass.getType());
body.getLocals().add(objCClass);
units.add(j.newAssignStmt(objCClass, j.newStaticFieldRef(Scene.v().makeFieldRef(sootClass, "$objCClass", org_robovm_objc_ObjCClass.getType(), true))));
}
if (strongRefSetter) {
Type propType = method.getParameterType(extensions ? 1 : 0);
if (propType instanceof RefLikeType) {
SootMethodRef getter = findStrongRefGetter(sootClass, method, extensions).makeRef();
Local before = j.newLocal("$before", propType);
body.getLocals().add(before);
units.add(j.newAssignStmt(before, extensions ? j.newStaticInvokeExpr(getter, thiz) : (objCClass != null ? j.newStaticInvokeExpr(getter) : j.newVirtualInvokeExpr(thiz, getter))));
Value after = args.get(0);
if (extensions) {
units.add(j.newInvokeStmt(j.newStaticInvokeExpr(org_robovm_objc_ObjCExtensions_updateStrongRef, Arrays.asList(thiz, before, after))));
} else {
units.add(j.newInvokeStmt(j.newVirtualInvokeExpr(objCClass != null ? objCClass : thiz, org_robovm_objc_ObjCObject_updateStrongRef, before, after)));
}
}
}
Local sel = j.newLocal("$sel", org_robovm_objc_Selector.getType());
body.getLocals().add(sel);
// $sel = <selector>
units.add(j.newAssignStmt(sel, j.newStaticFieldRef(Scene.v().makeFieldRef(sootClass, getSelectorFieldName(selectorName), org_robovm_objc_Selector.getType(), true))));
args.addFirst(sel);
Local customClass = null;
if (!usingGenericInstanceMethod && !extensions && !Modifier.isFinal(sootClass.getModifiers()) && !method.isStatic()) {
customClass = j.newLocal("$customClass", BooleanType.v());
body.getLocals().add(customClass);
units.add(j.newAssignStmt(customClass, j.newInstanceFieldRef(thiz, org_robovm_objc_ObjCObject_customClass)));
}
Local ret = null;
if (method.getReturnType() != VoidType.v()) {
ret = j.newLocal("$ret", msgSendMethodRef.returnType());
body.getLocals().add(ret);
}
Local castRet = null;
if (!msgSendMethodRef.returnType().equals(method.getReturnType())) {
/*
* We're calling a generic method in $M which returns an NSObject.
* We need to cast that to the return type declared by the method
* being generated.
*/
castRet = j.newLocal("$castRet", method.getReturnType());
body.getLocals().add(castRet);
}
StaticInvokeExpr invokeMsgSendExpr = j.newStaticInvokeExpr(msgSendMethodRef, l(thiz != null ? thiz : objCClass, args));
Stmt invokeMsgSendStmt = ret == null ? j.newInvokeStmt(invokeMsgSendExpr) : j.newAssignStmt(ret, invokeMsgSendExpr);
if (customClass != null) {
// if $customClass == 0 goto <invokeMsgSendStmt>
units.add(j.newIfStmt(j.newEqExpr(customClass, IntConstant.v(0)), invokeMsgSendStmt));
// $super = this.getSuper()
Local zuper = j.newLocal("$super", org_robovm_objc_ObjCSuper.getType());
body.getLocals().add(zuper);
units.add(j.newAssignStmt(zuper, j.newVirtualInvokeExpr(body.getThisLocal(), org_robovm_objc_ObjCObject_getSuper)));
StaticInvokeExpr invokeMsgSendSuperExpr = j.newStaticInvokeExpr(msgSendSuperMethodRef, l(zuper, args));
units.add(ret == null ? j.newInvokeStmt(invokeMsgSendSuperExpr) : j.newAssignStmt(ret, invokeMsgSendSuperExpr));
if (ret != null) {
if (castRet != null) {
units.add(j.newAssignStmt(castRet, j.newCastExpr(ret, castRet.getType())));
units.add(j.newReturnStmt(castRet));
} else {
units.add(j.newReturnStmt(ret));
}
} else {
units.add(j.newReturnVoidStmt());
}
}
units.add(invokeMsgSendStmt);
if (ret != null) {
if (castRet != null) {
units.add(j.newAssignStmt(castRet, j.newCastExpr(ret, castRet.getType())));
units.add(j.newReturnStmt(castRet));
} else {
units.add(j.newReturnStmt(ret));
}
} else {
units.add(j.newReturnVoidStmt());
}
}
Aggregations