All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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