Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (C) 2012 Trillian 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 <http://www.gnu.org/licenses/gpl-2.0.html>.
  */
 package org.robovm.compiler;
 
 import static org.robovm.compiler.Access.*;
 import static org.robovm.compiler.Functions.*;
 import static org.robovm.compiler.Mangler.*;
 import static org.robovm.compiler.llvm.Linkage.*;
 import static org.robovm.compiler.llvm.Type.*;
 
 import java.io.File;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 
 public class Linker {
     
     private static final TypeInfo[] EMPTY_TYPE_INFOS = new TypeInfo[0];
     
     private static class TypeInfo implements Comparable<TypeInfo> {
         boolean error;
         Clazz clazz;
         List<Clazzchildren = new ArrayList<Clazz>();
         int id;
        
Ordered list of TypeInfos for each superclass of this class and the class itself. Empty if this is an interface.
 
         TypeInfo[] classTypes;
        
Unordered list of TypeInfos for each interface implemented by this class or interface.
 
         TypeInfo[] interfaceTypes;
         
         @Override
         public int hashCode() {
             final int prime = 31;
             int result = 1;
             result = prime * result + ;
             return result;
         }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            TypeInfo other = (TypeInfoobj;
            if ( != other.id)
                return false;
            return true;
        }
        @Override
        public int compareTo(TypeInfo o) {
            return  < o.id ? -1 : ( == o.id ? 0 : 1);
        }
    }
    
    private final Config config;
    public Linker(Config config) {
        this. = config;
    }
    
    public void link(Set<Clazzclassesthrows IOException {
        Set<ClazzlinkClasses = new TreeSet<Clazz>(classes);
        .getLogger().info("Linking %d classes"linkClasses.size());
        ModuleBuilder mb = new ModuleBuilder();
        mb.addInclude(getClass().getClassLoader().getResource(String.format("header-%s-%s.ll".getOs().getFamily(), .getArch())));
        mb.addInclude(getClass().getClassLoader().getResource("header.ll"));
        mb.addGlobal(new Global("_bcDynamicJNI"new IntegerConstant(.isUseDynamicJni() ? (byte) 1 : (byte) 0)));
        ArrayConstantBuilder staticLibs = new ArrayConstantBuilder();
        if (!.isUseDynamicJni()) {
            for (Config.Lib lib : .getLibs()) {
                String p = lib.getValue();
                if (p.endsWith(".a")) {
                    p = new File(p).getName();
                    String libName = p.substring(0, p.length() - 2);
                    if (libName.startsWith("lib")) {
                        libName = libName.substring(3);
                    }
                    staticLibs.add(mb.getString(libName));
                }
            }
        }
        staticLibs.add(new NullConstant(.));
        mb.addGlobal(new Global("_bcStaticLibs"new ConstantGetelementptr(mb.newGlobal(staticLibs.build()).ref(), 0, 0)));
        int classCount = 0;
        Map<ClazzInfoTypeInfotypeInfos = new HashMap<ClazzInfoTypeInfo>();
        for (Clazz clazz : linkClasses) {
            TypeInfo typeInfo = new TypeInfo();
            typeInfo.clazz = clazz;
            typeInfo.id = classCount++;
            typeInfos.put(clazz.getClazzInfo(), typeInfo);
            
            StructureConstant infoErrorStruct = createClassInfoErrorStruct(mbclazz.getClazzInfo());
            Global info = null;
            if (infoErrorStruct == null) {
                info = new Global(mangleClass(clazz.getInternalName()) + "_info_struct"false);
            } else {
                typeInfo.error = true;
                info = new Global(mangleClass(clazz.getInternalName()) + "_info_struct"infoErrorStruct);
            }
            mb.addGlobal(info);
            if (clazz.isInBootClasspath()) {
                bcpHashGen.put(clazz.getInternalName(), new ConstantBitcast(info.ref(), ));
            } else {
                cpHashGen.put(clazz.getInternalName(), new ConstantBitcast(info.ref(), ));
            }
        }
        mb.addGlobal(new Global("_bcBootClassesHash"new ConstantGetelementptr(mb.newGlobal(bcpHashGen.generate(), true).ref(), 0, 0)));
        mb.addGlobal(new Global("_bcClassesHash"new ConstantGetelementptr(mb.newGlobal(cpHashGen.generate(), true).ref(), 0, 0)));
        
        ArrayConstantBuilder bootClasspathValues = new ArrayConstantBuilder();
        ArrayConstantBuilder classpathValues = new ArrayConstantBuilder();
        List<PathallPaths = new ArrayList<Path>();
        allPaths.addAll(.getClazzes().getPaths());
        allPaths.addAll(.getResourcesPaths());
        for (Path path : allPaths) {
            String entryName = null;
            if (.isSkipInstall() && .getTarget().canLaunchInPlace()) {
                entryName = path.getFile().getAbsolutePath();
            } else {
                entryName = .getTarget().getInstallRelativeArchivePath(path);
            }
            if (path.isInBootClasspath()) {
                bootClasspathValues.add(mb.getString(entryName));
            } else {
                classpathValues.add(mb.getString(entryName));
            }
        }
        bootClasspathValues.add(new NullConstant(.));
        classpathValues.add(new NullConstant(.));
        mb.addGlobal(new Global("_bcBootclasspath"new ConstantGetelementptr(mb.newGlobal(bootClasspathValues.build()).ref(), 0, 0)));
        mb.addGlobal(new Global("_bcClasspath"new ConstantGetelementptr(mb.newGlobal(classpathValues.build()).ref(), 0, 0)));
        if (.getMainClass() != null) {
            mb.addGlobal(new Global("_bcMainClass"mb.getString(.getMainClass())));
        }        
        
        buildTypeInfos(typeInfos);
        
        for (Clazz clazz : linkClasses) {
            ClazzInfo ci = clazz.getClazzInfo();
            TypeInfo typeInfo = typeInfos.get(ci);
            if (typeInfo.error) {
                // Add an empty TypeInfo
                mb.addGlobal(new Global(mangleClass(clazz.getInternalName()) + "_typeinfo"
                        new StructureConstantBuilder()
                            .add(new IntegerConstant(typeInfo.id))
                            .add(new IntegerConstant(0))
                            .add(new IntegerConstant(-1))
                            .add(new IntegerConstant(0))
                            .add(new IntegerConstant(0))
                            .build()));
            } else {
                int[] classIds = new int[typeInfo.classTypes.length];
                for (int i = 0; i < typeInfo.classTypes.lengthi++) {
                    classIds[i] = typeInfo.classTypes[i].;
                }
                int[] interfaceIds = new int[typeInfo.interfaceTypes.length];
                for (int i = 0; i < typeInfo.interfaceTypes.lengthi++) {
                    interfaceIds[i] = typeInfo.interfaceTypes[i].;
                }
                mb.addGlobal(new Global(mangleClass(clazz.getInternalName()) + "_typeinfo"
                        new StructureConstantBuilder()
                            .add(new IntegerConstant(typeInfo.id))
                            .add(new IntegerConstant((typeInfo.classTypes.length - 1) * 4 + 5 * 4))
                            .add(new IntegerConstant(-1))
                            .add(new IntegerConstant(typeInfo.classTypes.length))
                            .add(new IntegerConstant(typeInfo.interfaceTypes.length))
                            .add(new ArrayConstantBuilder().add(classIds).build())
                            .add(new ArrayConstantBuilder().add(interfaceIds).build())
                            .build()));
                if (!ci.isInterface() && !ci.isFinal() && typeInfo.children.isEmpty()) {
                    // Non-final class with 0 children. Override every lookup function with one
                    // which doesn't do any lookup.
                    for (MethodInfo mi : ci.getMethods()) {
                        String name = mi.getName();
                        if (!name.equals("<clinit>") && !name.equals("<init>"
                                && !mi.isPrivate() && !mi.isStatic() && !mi.isFinal() && !mi.isAbstract()) {
                            mb.addFunction(createLookup(mbcimi));
                        }
                    }
                }
            }
            
            mb.addFunction(createCheckcast(mbclazztypeInfo));
            mb.addFunction(createInstanceof(mbclazztypeInfo));
        }
        
        Arch arch = .getArch();
        OS os = .getOs();
        
        Context context = new Context();
        Module module = Module.parseIR(contextmb.build().toString(), "linker.ll");
        PassManager passManager = new PassManager();
        passManager.addAlwaysInlinerPass();
        passManager.addPromoteMemoryToRegisterPass();
        passManager.run(module);
        passManager.dispose();
        String triple = arch.getLlvmName() + "-unknown-" + os;
        Target target = Target.lookupTarget(triple);
        TargetMachine targetMachine = target.createTargetMachine(triple);
        targetMachine.setAsmVerbosityDefault(true);
        targetMachine.setFunctionSections(true);
        targetMachine.setDataSections(true);
        targetMachine.getOptions().setNoFramePointerElim(true);
        File linkerO = new File(.getTmpDir(), "linker.o");
        linkerO.getParentFile().mkdirs();
        OutputStream outO = null;
        try {
            outO = new BufferedOutputStream(new FileOutputStream(linkerO));
            targetMachine.emit(moduleoutO.);
        } finally {
            IOUtils.closeQuietly(outO);
        }
        
        module.dispose();
        context.dispose();
        
        List<FileobjectFiles = new ArrayList<File>();
        objectFiles.add(linkerO);
        
        for (Clazz clazz : linkClasses) {
            objectFiles.add(.getOFile(clazz));
        }
        .getTarget().build(objectFiles);
    }
    private TypeInfo buildTypeInfo(TypeInfo typeInfoMap<ClazzInfoTypeInfotypeInfos) {
        if (typeInfo.error || typeInfo.classTypes != null) {
            return typeInfo;
        }
        ClazzInfo ci = typeInfo.clazz.getClazzInfo();
        List<TypeInfoclTypeInfos = new ArrayList<TypeInfo>();
        Set<TypeInfoifTypeInfos = new TreeSet<TypeInfo>();
        
        if (!ci.isInterface()) {
            if (ci.hasSuperclass()) {
                TypeInfo superTypeInfo = buildTypeInfo(typeInfos.get(ci.getSuperclass()), typeInfos);
                if (superTypeInfo.error) {
                    typeInfo.error = true;
                    return typeInfo;
                }
                clTypeInfos.addAll(Arrays.asList(superTypeInfo.classTypes));
                clTypeInfos.add(typeInfo);
                ifTypeInfos.addAll(Arrays.asList(superTypeInfo.interfaceTypes));
                superTypeInfo.children.add(typeInfo.clazz);
            } else {
                clTypeInfos.add(typeInfo);
            }
        }
        
        for (ClazzInfo ifCi : ci.getInterfaces()) {
            TypeInfo ifTypeInfo = buildTypeInfo(typeInfos.get(ifCi), typeInfos);
            if (ifTypeInfo.error) {
                typeInfo.error = true;
                return typeInfo;
            }
            ifTypeInfos.addAll(Arrays.asList(ifTypeInfo.interfaceTypes));
        }
        if (ci.isInterface()) {
            ifTypeInfos.add(typeInfo);
        }
        typeInfo.classTypes = ;
        typeInfo.interfaceTypes = ;
        if (!clTypeInfos.isEmpty()) {
            typeInfo.classTypes = clTypeInfos.toArray(new TypeInfo[clTypeInfos.size()]);
        }
        if (!ifTypeInfos.isEmpty()) {
            typeInfo.interfaceTypes = ifTypeInfos.toArray(new TypeInfo[ifTypeInfos.size()]);
        }
        
        return typeInfo;
    }
    
    private void buildTypeInfos(Map<ClazzInfoTypeInfotypeInfos) {
        for (TypeInfo typeInfo : typeInfos.values()) {
            buildTypeInfo(typeInfotypeInfos);
        }
    }
    
        /*
         * Check that the class can be loaded, i.e. that the superclass 
         * and interfaces of the class exist and are accessible to the
         * class. Also check that any exception the class uses in catch
         * clauses exist and is accessible to the class. If the class
         * cannot be loaded we override the ClassInfoHeader struct
         * produced by the ClassCompiler for the class with one which
         * tells the code in bc.c to throw an appropriate exception
         * whenever the class is accessed.
         */
        int errorType = .;
        String errorMessage = null;
        if (!ci.isInterface() && ci.hasSuperclass()) {
            // Check superclass
            ClazzInfo superclazz = ci.getSuperclass();
            if (superclazz.isPhantom()) {
                errorType = .;
                errorMessage = superclazz.getName();
            } else if (!checkClassAccessible(superclazzci)) {
                errorType = .;
                errorMessage = String.format(superclazzci);
            } else if (superclazz.isInterface()) {
                errorType = .;
                errorMessage = String.format("class %s has interface %s as super class"cisuperclazz);
            }
            // No need to check for ClassCircularityError. Soot doesn't handle 
            // such problems so the compilation will fail earlier.
        }
        
        if (errorType == .) {
            // Check interfaces
            for (ClazzInfo interfaze :  ci.getInterfaces()) {
                if (interfaze.isPhantom()) {
                    errorType = .;
                    errorMessage = interfaze.getName();
                    break;
                } else if (!checkClassAccessible(interfazeci)) {
                    errorType = .;
                    errorMessage = String.format(interfazeci);
                    break;
                } else if (!interfaze.isInterface()) {
                    errorType = .;
                    errorMessage = String.format("class %s tries to implement class %s as interface"
                            ciinterfaze);
                    break;
                }
            }
        }
        
        if (errorType == .) {
            // Check exceptions used in catch clauses. I cannot find any info in
            // the VM spec specifying that this has to be done when the class is loaded.
            // However, this is how it's done in other VMs so we do it too.
            for (ClazzInfo ex : ci.getCatches()) {
                if (ex == null || ex.isPhantom()) {
                    errorType = .;
                    errorMessage = ex.getInternalName();
                    break;
                } else if (!checkClassAccessible(exci)) {
                    errorType = .;
                    errorMessage = String.format(exci);
                    break;
                }
            }
        }
        
        if (errorType == .) {
            return null;
        }
        
        // Create a ClassInfoError struct
        StructureConstantBuilder error = new StructureConstantBuilder();
        error.add(new NullConstant()); // Points to the runtime Class struct
        error.add(new IntegerConstant(.));
        error.add(mb.getString(ci.getInternalName()));
        error.add(new IntegerConstant(errorType));
        error.add(mb.getString(errorMessage));
        return error.build();
    }
    
    private Function createCheckcast(ModuleBuilder mbClazz clazzTypeInfo typeInfo) {
        Function fn = FunctionBuilder.checkcast(clazz);
        Value info = getInfoStruct(mbfnclazz);
        if (typeInfo.error) {
            // This will trigger an exception
            call(fnfn.getParameterRef(0), info);
            fn.add(new Ret(new NullConstant(.)));
        } else if (!clazz.getClazzInfo().isInterface()) {
            Value result = call(fnfn.getParameterRef(0), info
                    fn.getParameterRef(1), 
                    new IntegerConstant((typeInfo.classTypes.length - 1) * 4 + 5 * 4),
                    new IntegerConstant(typeInfo.id));
            fn.add(new Ret(result));
        } else {
            Value result = call(fnfn.getParameterRef(0), info
                    fn.getParameterRef(1), 
                    new IntegerConstant(typeInfo.id));
            fn.add(new Ret(result));
        }
        return fn;
    }
    private Function createInstanceof(ModuleBuilder mbClazz clazzTypeInfo typeInfo) {
        Function fn = FunctionBuilder.instanceOf(clazz);
        Value info = getInfoStruct(mbfnclazz);
        if (typeInfo.error) {
            // This will trigger an exception
            call(fnfn.getParameterRef(0), info);
            fn.add(new Ret(new IntegerConstant(0)));
        } else if (!clazz.getClazzInfo().isInterface()) {
            Value result = call(fnfn.getParameterRef(0), info
                    fn.getParameterRef(1), 
                    new IntegerConstant((typeInfo.classTypes.length - 1) * 4 + 5 * 4),
                    new IntegerConstant(typeInfo.id));
            fn.add(new Ret(result));
        } else {
            Value result = call(fnfn.getParameterRef(0), info
                    fn.getParameterRef(1), 
                    new IntegerConstant(typeInfo.id));
            fn.add(new Ret(result));
        }
        return fn;
    }
    private Function createLookup(ModuleBuilder mbClazzInfo ciMethodInfo mi) {
        Function function = FunctionBuilder.lookup(cimifalse);
        String targetFnName = mangleMethod(ci.getInternalName(), mi.getName(), mi.getDesc());
        if (mi.isSynchronized()) {
            targetFnName += "_synchronized";
        }
        FunctionRef fn = new FunctionRef(targetFnNamefunction.getType());
        if (!mb.hasSymbol(fn.getName())) {
            mb.addFunctionDeclaration(new FunctionDeclaration(fn));
        }
        Value result = tailcall(functionfnfunction.getParameterRefs());
        function.add(new Ret(result));
        return function;
    }
   
    private Value getInfoStruct(ModuleBuilder mbFunction fClazz clazz) {
        return new ConstantBitcast(mb.getGlobalRef(mangleClass(clazz.getInternalName()) + "_info_struct"), );
    }
New to GrepCode? Check out our FAQ X