org.robovm.compiler.GlobalValueMethodCompiler Maven / Gradle / Ivy
/*
* Copyright (C) 2012 RoboVM AB
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.robovm.compiler;
import static org.robovm.compiler.Annotations.*;
import static org.robovm.compiler.Functions.*;
import static org.robovm.compiler.Types.*;
import static org.robovm.compiler.llvm.Linkage.*;
import static org.robovm.compiler.llvm.Type.*;
import org.robovm.compiler.Bro.MarshalerFlags;
import org.robovm.compiler.config.Config;
import org.robovm.compiler.llvm.Br;
import org.robovm.compiler.llvm.ConstantBitcast;
import org.robovm.compiler.llvm.Function;
import org.robovm.compiler.llvm.Global;
import org.robovm.compiler.llvm.Icmp;
import org.robovm.compiler.llvm.Icmp.Condition;
import org.robovm.compiler.llvm.Label;
import org.robovm.compiler.llvm.Load;
import org.robovm.compiler.llvm.NullConstant;
import org.robovm.compiler.llvm.PointerType;
import org.robovm.compiler.llvm.Ret;
import org.robovm.compiler.llvm.Type;
import org.robovm.compiler.llvm.Unreachable;
import org.robovm.compiler.llvm.Value;
import org.robovm.compiler.llvm.Variable;
import org.robovm.compiler.llvm.VariableRef;
import soot.SootMethod;
import soot.VoidType;
import soot.tagkit.AnnotationTag;
/**
* @author niklas
*
*/
public class GlobalValueMethodCompiler extends BroMethodCompiler {
public GlobalValueMethodCompiler(Config config) {
super(config);
}
private void validateGlobalValueMethod(SootMethod method, AnnotationTag globalValueAnnotation) {
if (!method.isStatic()) {
throw new IllegalArgumentException("@GlobalValue annotated method "
+ method + " must be static");
}
if (!method.isNative()) {
throw new IllegalArgumentException("@GlobalValue annotated method "
+ method + " must be native");
}
if (!(method.getReturnType() != VoidType.v() && method.getParameterCount() == 0
|| method.getReturnType() == VoidType.v() && method.getParameterCount() == 1)) {
throw new IllegalArgumentException("Invalid signature for "
+ "@GlobalValue annotated method " + method
+ ". It should either take 0 arguments and return a non-void "
+ "type or take 1 argument and return void");
}
// dereference can only be false for getters
if (method.getReturnType() == VoidType.v()) {
// Setter
boolean dereference = readBooleanElem(globalValueAnnotation, "dereference", true);
if (!dereference) {
throw new IllegalArgumentException("Only @GlobalValue getter methods "
+ "are allowed to have dereference=false");
}
}
}
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
Value value = fn.getParameterRef(1); // 'env' is parameter 0, the value we're interested in is at index 1
storeValueForSetter(method, fn, valueType, valuePtr.ref(), env,
value, MarshalerFlags.CALL_TYPE_GLOBAL_VALUE);
fn.add(new Ret());
}
return fn;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy