use of org.robovm.compiler.llvm.Unreachable in project robovm by robovm.
the class TrampolineCompiler method checkClassAccessible.
private boolean checkClassAccessible(Function f, Trampoline t) {
Clazz caller = config.getClazzes().load(t.getCallingClass());
String targetClassName = t.getTarget();
if (isArray(targetClassName)) {
if (isPrimitiveBaseType(targetClassName)) {
return true;
}
targetClassName = getBaseType(targetClassName);
}
Clazz target = config.getClazzes().load(targetClassName);
if (Access.checkClassAccessible(target, caller)) {
return true;
}
throwIllegalAccessError(f, ILLEGAL_ACCESS_ERROR_CLASS, target, caller);
f.add(new Unreachable());
return false;
}
use of org.robovm.compiler.llvm.Unreachable in project robovm by robovm.
the class GlobalValueMethodCompiler method doCompile.
protected Function doCompile(ModuleBuilder moduleBuilder, SootMethod method) {
AnnotationTag globalValueAnnotation = getAnnotation(method, GLOBAL_VALUE);
validateGlobalValueMethod(method, globalValueAnnotation);
boolean optional = readBooleanElem(globalValueAnnotation, "optional", false);
boolean dereference = readBooleanElem(globalValueAnnotation, "dereference", true);
Function fn = createMethodFunction(method);
moduleBuilder.addFunction(fn);
Type valueType = getStructMemberType(method);
// Load the address of the resolved @GlobalValue method
Variable valuePtr = fn.newVariable(new PointerType(valueType));
Global valuePtrPtr = new Global(Symbols.globalValuePtrSymbol(method), _private, new NullConstant(I8_PTR));
moduleBuilder.addGlobal(valuePtrPtr);
fn.add(new Load(valuePtr, new ConstantBitcast(valuePtrPtr.ref(), new PointerType(valuePtr.getType()))));
Label nullLabel = new Label();
Label notNullLabel = new Label();
Variable nullCheck = fn.newVariable(I1);
fn.add(new Icmp(nullCheck, Condition.eq, valuePtr.ref(), new NullConstant(valuePtr.getType())));
fn.add(new Br(nullCheck.ref(), fn.newBasicBlockRef(nullLabel), fn.newBasicBlockRef(notNullLabel)));
fn.newBasicBlock(nullLabel);
VariableRef env = fn.getParameterRef(0);
call(fn, BC_THROW_UNSATISIFED_LINK_ERROR, env, moduleBuilder.getString(String.format((optional ? "Optional " : "") + "@GlobalValue method %s.%s%s not bound", className, method.getName(), getDescriptor(method))));
fn.add(new Unreachable());
fn.newBasicBlock(notNullLabel);
if (method.getParameterCount() == 0) {
// Getter
Value result = loadValueForGetter(method, fn, valueType, valuePtr.ref(), env, dereference, MarshalerFlags.CALL_TYPE_GLOBAL_VALUE);
fn.add(new Ret(result));
} else {
// Setter
// 'env' is parameter 0, the value we're interested in is at index 1
Value value = fn.getParameterRef(1);
storeValueForSetter(method, fn, valueType, valuePtr.ref(), env, value, MarshalerFlags.CALL_TYPE_GLOBAL_VALUE);
fn.add(new Ret());
}
return fn;
}
use of org.robovm.compiler.llvm.Unreachable in project robovm by robovm.
the class TrampolineCompiler method compile.
public void compile(ModuleBuilder mb, Clazz currentClass, Trampoline t, Set<String> dependencies, Set<Triple<String, String, String>> methodDependencies) {
this.mb = mb;
addDependencyIfNeeded(dependencies, currentClass, t);
/*
* Check if the target class exists and is accessible. Also check that
* field accesses and method calls are compatible with the target
* field/method and that the field/method is accessible to the caller.
* If any of the tests fail the weak trampoline function created by the
* ClassCompiler will be overridden with a function which throws an
* appropriate exception.
*/
Function errorFn = new FunctionBuilder(t).linkage(external).build();
if (!checkClassExists(errorFn, t) || !checkClassAccessible(errorFn, t)) {
mb.addFunction(errorFn);
return;
}
if (t instanceof New) {
SootClass target = config.getClazzes().load(t.getTarget()).getSootClass();
if (target.isAbstract() || target.isInterface()) {
call(errorFn, BC_THROW_INSTANTIATION_ERROR, errorFn.getParameterRef(0), mb.getString(t.getTarget().replace('/', '.')));
errorFn.add(new Unreachable());
mb.addFunction(errorFn);
return;
}
String fnName = Symbols.clinitWrapperSymbol(Symbols.allocatorSymbol(t.getTarget()));
alias(t, fnName);
} else if (t instanceof Instanceof) {
if (isArray(t.getTarget())) {
FunctionRef fnRef = createInstanceofArray((Instanceof) t);
alias(t, fnRef.getName());
} else {
String fnName = Symbols.instanceofSymbol(t.getTarget());
alias(t, fnName);
}
} else if (t instanceof Checkcast) {
if (isArray(t.getTarget())) {
FunctionRef fnRef = createCheckcastArray((Checkcast) t);
alias(t, fnRef.getName());
} else {
String fnName = Symbols.checkcastSymbol(t.getTarget());
alias(t, fnName);
}
} else if (t instanceof LdcClass) {
if (isArray(t.getTarget())) {
FunctionRef fnRef = createLdcArray((LdcClass) t);
alias(t, fnRef.getName());
} else {
String fnName = Symbols.ldcExternalSymbol(t.getTarget());
alias(t, fnName);
}
} else if (t instanceof Anewarray) {
FunctionRef fnRef = createAnewarray((Anewarray) t);
alias(t, fnRef.getName());
} else if (t instanceof Multianewarray) {
FunctionRef fnRef = createMultianewarray((Multianewarray) t);
alias(t, fnRef.getName());
} else if (t instanceof FieldAccessor) {
SootField field = resolveField(errorFn, (FieldAccessor) t);
if (field != null) {
dependencies.add(getInternalName(field.getDeclaringClass()));
}
if (field == null || !checkMemberAccessible(errorFn, t, field)) {
mb.addFunction(errorFn);
return;
}
Clazz caller = config.getClazzes().load(t.getCallingClass());
Clazz target = config.getClazzes().load(t.getTarget());
if (!((FieldAccessor) t).isGetter() && field.isFinal() && caller != target) {
// Only the class declaring a final field may write to it.
// (Actually only <init>/<clinit> methods may write to it but we
// don't know which method is accessing the field at this point)
throwIllegalAccessError(errorFn, ATTEMPT_TO_WRITE_TO_FINAL_FIELD, target, field.getName(), caller);
mb.addFunction(errorFn);
return;
}
if (!field.isStatic()) {
createInlinedAccessorForInstanceField((FieldAccessor) t, field);
} else {
createTrampolineAliasForField((FieldAccessor) t, field);
}
} else if (t instanceof Invokeinterface) {
SootMethod rm = resolveInterfaceMethod(errorFn, (Invokeinterface) t);
if (rm != null) {
methodDependencies.add(new ImmutableTriple<String, String, String>(getInternalName(rm.getDeclaringClass()), rm.getName(), getDescriptor(rm)));
}
if (rm == null || !checkMemberAccessible(errorFn, t, rm)) {
mb.addFunction(errorFn);
return;
}
createTrampolineAliasForMethod((Invoke) t, rm);
} else if (t instanceof Invoke) {
SootMethod method = resolveMethod(errorFn, (Invoke) t);
if (method != null) {
methodDependencies.add(new ImmutableTriple<String, String, String>(getInternalName(method.getDeclaringClass()), method.getName(), getDescriptor(method)));
}
if (method == null || !checkMemberAccessible(errorFn, t, method)) {
mb.addFunction(errorFn);
return;
}
if (t instanceof Invokespecial && method.isAbstract()) {
call(errorFn, BC_THROW_ABSTRACT_METHOD_ERROR, errorFn.getParameterRef(0), mb.getString(String.format(NO_SUCH_METHOD_ERROR, method.getDeclaringClass(), method.getName(), getDescriptor(method))));
errorFn.add(new Unreachable());
mb.addFunction(errorFn);
return;
}
createTrampolineAliasForMethod((Invoke) t, method);
}
}
use of org.robovm.compiler.llvm.Unreachable in project robovm by robovm.
the class TrampolineCompiler method throwIllegalAccessError.
private void throwIllegalAccessError(Function f, String message, Object... args) {
call(f, BC_THROW_ILLEGAL_ACCESS_ERROR, f.getParameterRef(0), mb.getString(String.format(message, args)));
f.add(new Unreachable());
}
use of org.robovm.compiler.llvm.Unreachable in project robovm by robovm.
the class TrampolineCompiler method throwIncompatibleChangeError.
private void throwIncompatibleChangeError(Function f, String message, Object... args) {
call(f, BC_THROW_INCOMPATIBLE_CLASS_CHANGE_ERROR, f.getParameterRef(0), mb.getString(String.format(message, args)));
f.add(new Unreachable());
}
Aggregations