use of soot.tagkit.AnnotationTag in project robovm by robovm.
the class ObjCMemberPlugin method addTypeEncodingAnnotation.
static void addTypeEncodingAnnotation(SootMethod method, String encoding) {
AnnotationTag annotationTag = new AnnotationTag(TYPE_ENCODING, 1);
annotationTag.addElem(new AnnotationStringElem(encoding, 's', "value"));
addRuntimeVisibleAnnotation(method, annotationTag);
}
use of soot.tagkit.AnnotationTag 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 soot.tagkit.AnnotationTag 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 soot.tagkit.AnnotationTag in project robovm by robovm.
the class Bro method getArrayDimensions.
public static int[] getArrayDimensions(SootMethod method, int paramIndex) {
AnnotationTag annotation = paramIndex == -1 ? getArrayAnnotation(method) : getArrayAnnotation(method, paramIndex);
if (annotation == null) {
return null;
}
ArrayList<AnnotationElem> values = ((AnnotationArrayElem) annotation.getElemAt(0)).getValues();
int[] dims = new int[values.size()];
for (int i = 0; i < dims.length; i++) {
dims[i] = ((AnnotationIntElem) values.get(i)).getValue();
}
return dims;
}
use of soot.tagkit.AnnotationTag in project robovm by robovm.
the class MarshalerLookup method findMarshalerMethod.
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));
}
Aggregations