use of org.robovm.compiler.llvm.IntegerConstant in project robovm by robovm.
the class AttributesEncoder method encodeAttributes.
private Constant encodeAttributes(Host host) {
List<Value> attributes = new ArrayList<Value>();
for (Tag tag : host.getTags()) {
if (tag instanceof SourceFileTag) {
// Skip. We don't need this at this time.
Value sourceFile = getString(((SourceFileTag) tag).getSourceFile());
attributes.add(new PackedStructureConstant(new PackedStructureType(I8, I8_PTR), new IntegerConstant(SOURCE_FILE), sourceFile));
} else if (tag instanceof EnclosingMethodTag) {
EnclosingMethodTag emt = (EnclosingMethodTag) tag;
Value eClass = getString(emt.getEnclosingClass());
Value eMethod = getStringOrNull(emt.getEnclosingMethod());
Value eDesc = getStringOrNull(emt.getEnclosingMethodSig());
attributes.add(new PackedStructureConstant(new PackedStructureType(I8, I8_PTR, I8_PTR, I8_PTR), new IntegerConstant(ENCLOSING_METHOD), eClass, eMethod, eDesc));
} else if (tag instanceof SignatureTag) {
Value signature = getString(((SignatureTag) tag).getSignature());
attributes.add(new PackedStructureConstant(new PackedStructureType(I8, I8_PTR), new IntegerConstant(SIGNATURE), signature));
} else if (tag instanceof InnerClassTag) {
InnerClassTag ict = (InnerClassTag) tag;
Value innerClass = getStringOrNull(ict.getInnerClass());
Value outerClass = getStringOrNull(ict.getOuterClass());
Value innerName = getStringOrNull(ict.getShortName());
Value innerClassAccess = new IntegerConstant(ict.getAccessFlags());
attributes.add(new PackedStructureConstant(new PackedStructureType(I8, I8_PTR, I8_PTR, I8_PTR, I32), new IntegerConstant(INNER_CLASS), innerClass, outerClass, innerName, innerClassAccess));
} else if (tag instanceof AnnotationDefaultTag) {
StructureConstant value = encodeAnnotationElementValue(((AnnotationDefaultTag) tag).getDefaultVal());
attributes.add(new PackedStructureConstant(new PackedStructureType(I8, value.getType()), new IntegerConstant(ANNOTATION_DEFAULT), value));
} else if (tag instanceof VisibilityAnnotationTag) {
VisibilityAnnotationTag vat = (VisibilityAnnotationTag) tag;
if (vat.getVisibility() == AnnotationConstants.RUNTIME_VISIBLE) {
Type[] types = new Type[vat.getAnnotations().size()];
Value[] values = new Value[vat.getAnnotations().size()];
int i = 0;
for (AnnotationTag at : vat.getAnnotations()) {
values[i] = encodeAnnotationTagValue(at);
types[i] = values[i].getType();
i++;
}
attributes.add(new PackedStructureConstant(new PackedStructureType(I8, I32, new PackedStructureType(types)), new IntegerConstant(RUNTIME_VISIBLE_ANNOTATIONS), new IntegerConstant(vat.getAnnotations().size()), new PackedStructureConstant(new PackedStructureType(types), values)));
}
} else if (tag instanceof VisibilityParameterAnnotationTag) {
VisibilityParameterAnnotationTag vpat = (VisibilityParameterAnnotationTag) tag;
List<Type> typesList = new ArrayList<Type>();
List<Value> valuesList = new ArrayList<Value>();
boolean hasRuntimeVisible = false;
for (VisibilityAnnotationTag vat : vpat.getVisibilityAnnotations()) {
typesList.add(I32);
if (vat.getVisibility() == AnnotationConstants.RUNTIME_VISIBLE && vat.getAnnotations() != null && !vat.getAnnotations().isEmpty()) {
hasRuntimeVisible = true;
valuesList.add(new IntegerConstant(vat.getAnnotations().size()));
for (AnnotationTag at : vat.getAnnotations()) {
valuesList.add(encodeAnnotationTagValue(at));
typesList.add(valuesList.get(valuesList.size() - 1).getType());
}
} else {
valuesList.add(new IntegerConstant(0));
}
}
if (hasRuntimeVisible) {
Type[] types = typesList.toArray(new Type[typesList.size()]);
Value[] values = valuesList.toArray(new Value[valuesList.size()]);
attributes.add(new PackedStructureConstant(new PackedStructureType(I8, I32, new PackedStructureType(types)), new IntegerConstant(RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS), new IntegerConstant(vpat.getVisibilityAnnotations().size()), new PackedStructureConstant(new PackedStructureType(types), values)));
}
}
}
if (host instanceof SootMethod) {
List<SootClass> exceptions = ((SootMethod) host).getExceptions();
if (!exceptions.isEmpty()) {
Value[] values = new Value[exceptions.size()];
for (int i = 0; i < exceptions.size(); i++) {
String exName = getInternalName(exceptions.get(i));
values[i] = getString(exName);
addDependency(exName);
}
attributes.add(new PackedStructureConstant(new PackedStructureType(I8, I32, new ArrayType(exceptions.size(), I8_PTR)), new IntegerConstant(EXCEPTIONS), new IntegerConstant(exceptions.size()), new ArrayConstant(new ArrayType(exceptions.size(), I8_PTR), values)));
}
}
if (attributes.isEmpty()) {
return null;
}
attributes.add(0, new IntegerConstant(attributes.size()));
Type[] types = new Type[attributes.size()];
for (int i = 0; i < types.length; i++) {
types[i] = attributes.get(i).getType();
}
return new PackedStructureConstant(new PackedStructureType(types), attributes.toArray(new Value[0]));
}
use of org.robovm.compiler.llvm.IntegerConstant in project robovm by robovm.
the class BridgeMethodCompiler method doCompile.
protected Function doCompile(ModuleBuilder moduleBuilder, SootMethod method) {
validateBridgeMethod(method);
AnnotationTag bridgeAnnotation = getAnnotation(method, BRIDGE);
boolean dynamic = readBooleanElem(bridgeAnnotation, "dynamic", false);
boolean optional = readBooleanElem(bridgeAnnotation, "optional", false);
boolean useCWrapper = requiresCWrapper(method);
Function fn = createMethodFunction(method);
moduleBuilder.addFunction(fn);
Type[] parameterTypes = fn.getType().getParameterTypes();
String[] parameterNames = fn.getParameterNames();
ArrayList<Argument> args = new ArrayList<Argument>();
for (int i = 0; i < parameterTypes.length; i++) {
args.add(new Argument(new VariableRef(parameterNames[i], parameterTypes[i])));
}
VariableRef env = fn.getParameterRef(0);
// Load the address of the resolved @Bridge method
Variable targetFn = fn.newVariable(I8_PTR);
if (!dynamic) {
Global targetFnPtr = new Global(Symbols.bridgePtrSymbol(method), _private, new NullConstant(I8_PTR));
moduleBuilder.addGlobal(targetFnPtr);
fn.add(new Load(targetFn, targetFnPtr.ref()));
Label nullLabel = new Label();
Label notNullLabel = new Label();
Variable nullCheck = fn.newVariable(I1);
fn.add(new Icmp(nullCheck, Condition.eq, targetFn.ref(), new NullConstant(I8_PTR)));
fn.add(new Br(nullCheck.ref(), fn.newBasicBlockRef(nullLabel), fn.newBasicBlockRef(notNullLabel)));
fn.newBasicBlock(nullLabel);
call(fn, optional ? BC_THROW_UNSATISIFED_LINK_ERROR_OPTIONAL_BRIDGE_NOT_BOUND : BC_THROW_UNSATISIFED_LINK_ERROR_BRIDGE_NOT_BOUND, env, moduleBuilder.getString(className), moduleBuilder.getString(method.getName()), moduleBuilder.getString(getDescriptor(method)));
fn.add(new Unreachable());
fn.newBasicBlock(notNullLabel);
} else {
// Dynamic @Bridge methods pass the target function pointer as a
// long in the first parameter.
fn.add(new Inttoptr(targetFn, fn.getParameterRef(1), targetFn.getType()));
args.remove(1);
}
// Marshal args
// Remove Env* from args
args.remove(0);
// Save the Object->handle mapping for each marshaled object. We need it
// after the native call to call updateObject() on the marshaler for
// each value. Since the LLVM variables that store these values are used
// after the native call we get the nice side effect that neither the
// Java objects nor the handles can be garbage collected while we're in
// native code.
List<MarshaledArg> marshaledArgs = new ArrayList<MarshaledArg>();
FunctionType targetFnType = getBridgeFunctionType(method, dynamic, false);
Type[] targetParameterTypes = targetFnType.getParameterTypes();
if (!method.isStatic()) {
MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method, MarshalSite.RECEIVER));
MarshaledArg marshaledArg = new MarshaledArg();
marshaledArg.paramIndex = MarshalSite.RECEIVER;
marshaledArgs.add(marshaledArg);
Type nativeType = targetParameterTypes[0];
Value nativeValue = marshalObjectToNative(fn, marshalerMethod, marshaledArg, useCWrapper ? I8_PTR : nativeType, env, args.get(0).getValue(), MarshalerFlags.CALL_TYPE_BRIDGE);
args.set(0, new Argument(nativeValue));
}
for (int i = 0, argIdx = 0; i < method.getParameterCount(); i++) {
if (dynamic && i == 0) {
// Skip the target function pointer for dynamic bridge methods.
continue;
}
if (!method.isStatic() && argIdx == 0) {
// Skip the receiver in args. It doesn't correspond to a parameter.
argIdx++;
}
soot.Type type = method.getParameterType(i);
if (needsMarshaler(type)) {
MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method, i));
// The return type of the marshaler's toNative() method is derived from the target function type.
Type nativeType = targetParameterTypes[argIdx];
if (nativeType instanceof PrimitiveType) {
Value nativeValue = marshalValueObjectToNative(fn, marshalerMethod, nativeType, env, args.get(argIdx).getValue(), MarshalerFlags.CALL_TYPE_BRIDGE);
args.set(argIdx, new Argument(nativeValue));
} else {
ParameterAttribute[] parameterAttributes = new ParameterAttribute[0];
if (isPassByValue(method, i) || isStructRet(method, i)) {
// The parameter must not be null. We assume that Structs
// never have a NULL handle so we just check that the Java
// Object isn't null.
call(fn, CHECK_NULL, env, args.get(argIdx).getValue());
}
MarshaledArg marshaledArg = new MarshaledArg();
marshaledArg.paramIndex = i;
marshaledArgs.add(marshaledArg);
Value nativeValue = marshalObjectToNative(fn, marshalerMethod, marshaledArg, useCWrapper ? I8_PTR : nativeType, env, args.get(argIdx).getValue(), MarshalerFlags.CALL_TYPE_BRIDGE);
args.set(argIdx, new Argument(nativeValue, parameterAttributes));
}
} else {
args.set(argIdx, new Argument(marshalPrimitiveToNative(fn, method, i, args.get(argIdx).getValue())));
}
argIdx++;
}
Variable structResult = null;
Value targetFnRef = null;
if (useCWrapper) {
args.add(0, new Argument(targetFn.ref()));
if (targetFnType.getReturnType() instanceof StructureType) {
// Allocate space on the stack big enough to hold the returned struct
Variable tmp = fn.newVariable(new PointerType(targetFnType.getReturnType()));
fn.add(new Alloca(tmp, targetFnType.getReturnType()));
structResult = fn.newVariable(I8_PTR);
fn.add(new Bitcast(structResult, tmp.ref(), I8_PTR));
args.add(1, new Argument(structResult.ref()));
}
String wrapperName = Symbols.bridgeCSymbol(method);
FunctionType wrapperFnType = getBridgeFunctionType(method, dynamic, true);
getCWrapperFunctions().add(createBridgeCWrapper(targetFnType.getReturnType(), targetFnType.getParameterTypes(), wrapperFnType.getParameterTypes(), wrapperName));
FunctionRef wrapperFnRef = getBridgeCWrapperRef(targetFnType, wrapperName);
moduleBuilder.addFunctionDeclaration(new FunctionDeclaration(wrapperFnRef));
targetFnRef = wrapperFnRef;
} else {
Variable tmp = fn.newVariable(targetFnType);
fn.add(new Bitcast(tmp, targetFn.ref(), targetFnType));
targetFnRef = tmp.ref();
}
// Execute the call to native code
BasicBlockRef bbSuccess = fn.newBasicBlockRef(new Label("success"));
BasicBlockRef bbFailure = fn.newBasicBlockRef(new Label("failure"));
pushNativeFrame(fn);
trycatchAllEnter(fn, env, bbSuccess, bbFailure);
fn.newBasicBlock(bbSuccess.getLabel());
Value result = callWithArguments(fn, targetFnRef, args);
trycatchLeave(fn, env);
popNativeFrame(fn);
updateObject(method, fn, env, MarshalerFlags.CALL_TYPE_BRIDGE, marshaledArgs);
// Marshal the return value
if (needsMarshaler(method.getReturnType())) {
MarshalerMethod marshalerMethod = config.getMarshalerLookup().findMarshalerMethod(new MarshalSite(method));
String targetClassName = getInternalName(method.getReturnType());
if (structResult != null) {
// Copy to the heap.
DataLayout dataLayout = config.getDataLayout();
Value heapCopy = call(fn, BC_COPY_STRUCT, env, structResult.ref(), new IntegerConstant(dataLayout.getAllocSize(targetFnType.getReturnType())));
result = marshalNativeToObject(fn, marshalerMethod, null, env, targetClassName, heapCopy, MarshalerFlags.CALL_TYPE_BRIDGE);
} else if (targetFnType.getReturnType() instanceof PrimitiveType) {
result = marshalNativeToValueObject(fn, marshalerMethod, env, targetClassName, result, MarshalerFlags.CALL_TYPE_BRIDGE);
} else {
result = marshalNativeToObject(fn, marshalerMethod, null, env, targetClassName, result, MarshalerFlags.CALL_TYPE_BRIDGE);
}
} else {
result = marshalNativeToPrimitive(fn, method, result);
}
fn.add(new Ret(result));
fn.newBasicBlock(bbFailure.getLabel());
trycatchLeave(fn, env);
popNativeFrame(fn);
Value ex = call(fn, BC_EXCEPTION_CLEAR, env);
// Call Marshaler.updateObject() for each object that was marshaled before
// the call.
updateObject(method, fn, env, MarshalerFlags.CALL_TYPE_BRIDGE, marshaledArgs);
call(fn, BC_THROW, env, ex);
fn.add(new Unreachable());
return fn;
}
use of org.robovm.compiler.llvm.IntegerConstant in project robovm by robovm.
the class MethodCompiler method nop.
private void nop(NopStmt stmt) {
/*
* We need to preserve NOPs as they may be needed by compiler plugins to
* work properly. There's no NOP bitcode instruction. Instead we use an
* ADD instruction which has no side-effects. LLVM should be able to
* optimize it out later on.
*/
Variable v = function.newVariable(I32);
function.add(new Add(v, new IntegerConstant(0), new IntegerConstant(0))).attach(stmt);
}
use of org.robovm.compiler.llvm.IntegerConstant in project robovm by robovm.
the class MethodCompiler method ldcString.
private FunctionRef ldcString(String s) {
byte[] modUtf8 = stringToModifiedUtf8Z(s);
FunctionRef fref = new FunctionRef(Symbols.ldcStringSymbol(modUtf8), new FunctionType(OBJECT_PTR, ENV_PTR));
if (moduleBuilder.hasSymbol(fref.getName())) {
return fref;
}
Global g = new Global(Symbols.ldcStringPtrSymbol(modUtf8), weak, new NullConstant(OBJECT_PTR));
moduleBuilder.addGlobal(g);
Function f = new FunctionBuilder(fref).linkage(weak).build();
moduleBuilder.addFunction(f);
Value result = Functions.call(f, BC_LDC_STRING, f.getParameterRef(0), g.ref(), moduleBuilder.getString(s), new IntegerConstant(s.length()));
f.add(new Ret(result));
return fref;
}
use of org.robovm.compiler.llvm.IntegerConstant 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());
}
}
}
Aggregations