Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * Copyright (C) 2012 Trillian Mobile 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.Annotations.*;
  import static org.robovm.compiler.Functions.*;
  import static org.robovm.compiler.Mangler.*;
  import static org.robovm.compiler.Types.*;
  import static org.robovm.compiler.llvm.Type.*;
  
  import java.io.File;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  
  
  import soot.BooleanType;
  import soot.ByteType;
  import soot.CharType;
  import soot.DoubleType;
  import soot.FloatType;
 import soot.IntType;
 import soot.LongType;
 import soot.Modifier;
 import soot.PrimType;
 import soot.VoidType;

Version:
$Id$
 
 public class ClassCompiler {
     private static final int DUMMY_METHOD_SIZE = 0x01abcdef;
     public static final int CI_PUBLIC = 0x1;
     public static final int CI_FINAL = 0x2;
     public static final int CI_INTERFACE = 0x4;
     public static final int CI_ABSTRACT = 0x8;
     public static final int CI_SYNTHETIC = 0x10;
     public static final int CI_ANNOTATION = 0x20;
     public static final int CI_ENUM = 0x40;
     public static final int CI_ATTRIBUTES = 0x80;
     public static final int CI_ERROR = 0x100;
     public static final int CI_INITIALIZED = 0x200;
     public static final int CI_FINALIZABLE = 0x400;
 
     public static final int CI_ERROR_TYPE_NONE = 0x0;
     public static final int CI_ERROR_TYPE_NO_CLASS_DEF_FOUND = 0x1;
     public static final int CI_ERROR_TYPE_ILLEGAL_ACCESS = 0x2;
     public static final int CI_ERROR_TYPE_INCOMPATIBLE_CLASS_CHANGE = 0x3;
     
     public static final int FI_ACCESS_MASK = 0x3;
     public static final int FI_PUBLIC = 0x1;
     public static final int FI_PRIVATE = 0x2;
     public static final int FI_PROTECTED = 0x3;
     public static final int FI_STATIC = 0x4;
     public static final int FI_FINAL = 0x8;
     public static final int FI_VOLATILE = 0x10;
     public static final int FI_TRANSIENT = 0x20;
     public static final int FI_SYNTHETIC = 0x40;
     public static final int FI_ENUM = 0x80;
     public static final int FI_ATTRIBUTES = 0x100;
     
     public static final int MI_ACCESS_MASK = 0x3;
     public static final int MI_PUBLIC = 0x1;
     public static final int MI_PRIVATE = 0x2;
     public static final int MI_PROTECTED = 0x3;
     public static final int MI_STATIC = 0x4;
     public static final int MI_FINAL = 0x8;
     public static final int MI_SYNCHRONIZED = 0x10;
     public static final int MI_BRIDGE = 0x20;
     public static final int MI_VARARGS = 0x40;
     public static final int MI_NATIVE = 0x80;
     public static final int MI_ABSTRACT = 0x100;
     public static final int MI_STRICT = 0x200;
     public static final int MI_SYNTHETIC = 0x400;
     public static final int MI_ATTRIBUTES = 0x800;
     public static final int MI_BRO_BRIDGE = 0x1000;
     public static final int MI_BRO_CALLBACK = 0x2000;
     public static final int MI_COMPACT_DESC = 0x4000;
     
     public static final int DESC_B = 1;
     public static final int DESC_C = 2;
     public static final int DESC_D = 3;
     public static final int DESC_F = 4;
     public static final int DESC_I = 5;
     public static final int DESC_J = 6;
     public static final int DESC_S = 7;
     public static final int DESC_Z = 8;
     public static final int DESC_V = 9;
     
     private SootClass sootClass;
     
     private ModuleBuilder mb;
     private Set<Trampolinetrampolines;
     private Set<Stringcatches;
    
Contains the class fields of the class being compiled.
 
     private List<SootFieldclassFields;
    
Contains the instance fields of the class being compiled.
 
     private List<SootFieldinstanceFields;
     
     private StructureType classType;
     private StructureType instanceType;
     
     private final Config config;
     private final MethodCompiler methodCompiler;
     private final BridgeMethodCompiler bridgeMethodCompiler;
     private final NativeMethodCompiler nativeMethodCompiler;
     private final AttributesEncoder attributesEncoder;
     private final TrampolineCompiler trampolineResolver;
     
     private final ByteArrayOutputStream output = new ByteArrayOutputStream(256 * 1024);
     
     public ClassCompiler(Config config) {
         this. = config;
         this. = new MethodCompiler(config);
         this. = new BridgeMethodCompiler(config);
         this. = new CallbackMethodCompiler(config);
         this. = new NativeMethodCompiler(config);
         this. = new StructMemberMethodCompiler(config);
         this. = new GlobalValueMethodCompiler(config);
         this. = new AttributesEncoder();
         this. = new TrampolineCompiler(config);
     }
     
     public boolean mustCompile(Clazz clazz) {
         File oFile = .getOFile(clazz);
         if (!oFile.exists() || oFile.lastModified() < clazz.lastModified()) {
             return true;
         }
         
         ClazzInfo ci = clazz.getClazzInfo();
         if (ci == null) {
             return true;
         }
         
         Set<Dependencydependencies = ci.getDependencies();
         for (Dependency dep : dependencies) {
             Clazz depClazz = .getClazzes().load(dep.getClassName());
             if (depClazz == null) {
                 if (dep.getPath() != null) {
                     // depClazz was available the last time clazz was compiled but is now gone
                     return true;
                 }
             } else {
                 if (dep.getPath() == null) {
                     // depClazz was not available the last time clazz was compiled but is now available
                     return true;
                 }
                 if (!dep.getPath().equals(depClazz.getPath().getFile().getAbsolutePath())) {
                     // depClazz was located in another place the last time clazz was built
                     return true;
                 }
                 if (depClazz.isInBootClasspath() != dep.isInBootClasspath()) {
                     // depClazz has moved to/from the bootclasspath since the last time clazz was built
                     return true;
                 }
                 if (depClazz.lastModified() > oFile.lastModified()) {
                     // depClazz has been changed since the last time clazz was built 
                     return true;
                 }
             }
         }
         
         // No class or interface has zero dependencies (we always add java.lang.Object as a dependency)
         // If dependencies is empty it probably means that an error occurred while reading the
         // serialized dependencies. By returning true here in that case the class will be recompiled
         // and the dependencies regenerated.
         return dependencies.isEmpty();
     }
     
     public void compile(Clazz clazzthrows IOException {
         reset();        
         
 //        File llFile = config.getLlFile(clazz);
 //        File bcFile = config.getBcFile(clazz);
 //        File sFile = config.getSFile(clazz);
         File oFile = .getOFile(clazz);
 //        llFile.getParentFile().mkdirs();
 //        bcFile.getParentFile().mkdirs();
 //        sFile.getParentFile().mkdirs();
         oFile.getParentFile().mkdirs();
 
         Arch arch = .getArch();
         OS os = .getOs();
 
         try {
             .getLogger().debug("Compiling %s (%s %s)"clazzosarch);
             .reset();
             compile(clazz);
         } catch (Throwable t) {
 //            FileUtils.deleteQuietly(llFile);
             if (t instanceof IOException) {
                 throw (IOExceptiont;
             }
             if (t instanceof RuntimeException) {
                 throw (RuntimeExceptiont;
             }
             throw new RuntimeException(t);
         }
 
         Context context = new Context();
         Module module = Module.parseIR(context.toByteArray(), clazz.getClassName());
         PassManager passManager = createPassManager();
         passManager.run(module);
         passManager.dispose();
 
         String triple = .getTriple();
         Target target = Target.lookupTarget(triple);
         TargetMachine targetMachine = target.createTargetMachine(triple);
         targetMachine.setAsmVerbosityDefault(true);
         targetMachine.setFunctionSections(true);
         targetMachine.setDataSections(true);
         targetMachine.getOptions().setNoFramePointerElim(true);
         .reset();
         targetMachine.emit(module.);
         
         module.dispose();
         context.dispose();
         
         byte[] asm = .toByteArray();
         .reset();
         patchAsmWithFunctionSizes(clazznew ByteArrayInputStream(asm), );
         asm = .toByteArray();
 
         BufferedOutputStream oOut = new BufferedOutputStream(new FileOutputStream(oFile));
         targetMachine.assemble(asmclazz.getClassName(), oOut);
         oOut.close();
         
         targetMachine.dispose();
     }
 
     private PassManager createPassManager() {
         // Sets up the passes we would get with PassManagerBuilder (see PassManagerBuilder.cpp) at 
         // O2 level except the TailCallEliminationPass which promotes all calls to tail calls which
         // we don't want since it messes up stack traces.
         
         PassManager passManager = new PassManager();
         passManager.addAlwaysInlinerPass();
         passManager.addPromoteMemoryToRegisterPass();
 
         passManager.addTypeBasedAliasAnalysisPass();
         passManager.addBasicAliasAnalysisPass();
         passManager.addGlobalOptimizerPass();
         passManager.addIPSCCPPass();
         passManager.addDeadArgEliminationPass();
         passManager.addInstructionCombiningPass();
         passManager.addCFGSimplificationPass();
         passManager.addPruneEHPass();
         passManager.addFunctionInliningPass();
         passManager.addFunctionAttrsPass();
 //        if (optLevel > 2) {
 //            passManager.addArgumentPromotionPass();
 //        }
         passManager.addScalarReplAggregatesPass();
         
         passManager.addEarlyCSEPass();
         passManager.addSimplifyLibCallsPass();
         passManager.addJumpThreadingPass();
         passManager.addCorrelatedValuePropagationPass();
         passManager.addCFGSimplificationPass();
         passManager.addInstructionCombiningPass();
         
         //passManager.addTailCallEliminationPass();
         passManager.addCFGSimplificationPass();
         passManager.addReassociatePass();
         passManager.addCFGSimplificationPass();
         passManager.addReassociatePass();
         passManager.addLoopRotatePass();
         passManager.addLICMPass();
         passManager.addLoopUnswitchPass();
         passManager.addInstructionCombiningPass();
         passManager.addIndVarSimplifyPass();
         passManager.addLoopIdiomPass();
         passManager.addLoopDeletionPass();
         
         passManager.addLoopVectorizePass();
         
         passManager.addLoopUnrollPass();
         
         passManager.addGVNPass();
         passManager.addMemCpyOptPass();
         passManager.addSCCPPass();
         
         passManager.addInstructionCombiningPass();
         passManager.addJumpThreadingPass();
         passManager.addCorrelatedValuePropagationPass();
         passManager.addDeadStoreEliminationPass();
 
         passManager.addSLPVectorizePass();
         
         passManager.addAggressiveDCEPass();
         passManager.addCFGSimplificationPass();
         passManager.addInstructionCombiningPass();
 
         passManager.addStripDeadPrototypesPass();
 
         passManager.addGlobalDCEPass();
         passManager.addConstantMergePass();
         return passManager;
     }
     
     private void patchAsmWithFunctionSizes(Clazz clazzInputStream inStreamOutputStream outStreamthrows IOException {
         Set<StringfunctionNames = new HashSet<String>();
         for (SootMethod method : clazz.getSootClass().getMethods()) {
             if (!method.isAbstract()) {
                 String name = mangleMethod(method);
                 if (.getOs().getFamily() == ..) {
                     name = "_" + name;
                 }                
                 functionNames.add(name);
             }
         }
         
         String localLabelPrefix = ".L";
         String prefix = mangleClass(clazz.getInternalName());
         if (.getOs().getFamily() == ..) {
             localLabelPrefix = "L";
             prefix = "_" + prefix;
         }
         String infoStructLabel = prefix + "_info_struct";
         Pattern methodImplPattern = Pattern.compile("\\s*\\.(?:quad|long)\\s+(" + Pattern.quote(prefix) + "[^\\s]+).*");
         
         BufferedReader in = null;
         BufferedWriter out = null;
         try {
             in = new BufferedReader(new InputStreamReader(inStream"UTF-8"));
             out = new BufferedWriter(new OutputStreamWriter(outStream"UTF-8"));
             String line = null;
             String currentFunction = null;
             while ((line = in.readLine()) != null) {
                 if (currentFunction == null) {
                     out.write(line);
                     out.write('\n');
                     if (line.startsWith(prefix)) {
                         int colon = line.indexOf(':');
                         if (colon == -1) {
                             continue;
                         }
                         String label = line.substring(0, colon);
                         if (functionNames.contains(label)) {
                             currentFunction = label;
                         } else if (label.equals(infoStructLabel)) {
                             break;
                         }
                     }
                 } else if (line.trim().equals(".cfi_endproc") || line.trim().startsWith(".section") || line.trim().startsWith(".globl")) {
                     out.write(localLabelPrefix);
                     out.write(currentFunction);
                     out.write("_end:\n\n");
                     currentFunction = null;
                     out.write(line);
                     out.write('\n');
                 } else {
                     out.write(line);
                     out.write('\n');
                 }
             }
             
             while ((line = in.readLine()) != null) {
                 out.write(line);
                 out.write('\n');
                 if (line.contains(prefix)) {
                     Matcher matcher = methodImplPattern.matcher(line);
                     if (matcher.matches()) {
                         String functionName = matcher.group(1);
                         if (functionNames.contains(functionName)) {
                             line = in.readLine();
                             if (line.contains(String.valueOf())) {
                                 out.write("\t.long\t");
                                 out.write(localLabelPrefix + functionName + "_end - " + functionName);
                                 out.write('\n');
                             } else {
                                 out.write(line);
                                 out.write('\n');                                
                             }
                         }
                     }
                 }
             }
         } finally {
             IOUtils.closeQuietly(in);
             IOUtils.closeQuietly(out);
         }
     }
     
     private void reset() {
         .reset();
          = null;
          = null;
          = null;
          = null;
          = null;
          = null;
          = null;
          = null;
     }
     
     private void compile(Clazz clazzOutputStream outthrows IOException {
         .reset(clazz);
         .reset(clazz);
         .reset(clazz);
         .reset(clazz);
         .reset(clazz);
         .reset(clazz);
         
         ClazzInfo ci = clazz.resetClazzInfo();
 
         for (CompilerPlugin compilerPlugin : .getCompilerPlugins()) {
             compilerPlugin.beforeClass(clazz);
         }
         
          = clazz.getSootClass();
          = new ModuleBuilder();
          = new HashSet<Trampoline>();
          = new HashSet<String>();
         
         .encode();
         
         // Add a <clinit> method if the class has ConstantValueTags but no <clinit>.
         // This has to be done before createInfoStruct() is called otherwise the
         // ClassInfoHeader->initializer value will become NULL and constant static fields
         // will never be initialized.
         if (!.declaresMethodByName("<clinit>") && hasConstantValueTags()) {
             SootMethod clinit = new SootMethod("<clinit>"., VoidType.v(), .);
             JimpleBody body = Jimple.v().newBody(clinit);
             clinit.setActiveBody(body);
             body.getUnits().add(new JReturnVoidStmt());
             this..addMethod(clinit);
         }
 
         if (isStruct()) {
             SootMethod _sizeOf = new SootMethod("_sizeOf"., IntType.v(), .);
             .addMethod(_sizeOf);
             SootMethod sizeOf = new SootMethod("sizeOf"., IntType.v(), . | .);
             .addMethod(sizeOf);
         }
         
         .addInclude(getClass().getClassLoader().getResource(String.format("header-%s-%s.ll".getOs().getFamily(), .getArch())));
         .addInclude(getClass().getClassLoader().getResource("header.ll"));
 
         .addFunction(createLdcClass());
         Function allocator = createAllocator();
         .addFunction(allocator);
         .addFunction(createClassInitWrapperFunction(allocator.ref()));
         
         for (SootField f : .getFields()) {
             Function getter = createFieldGetter(f);
             Function setter = createFieldSetter(f);
             .addFunction(getter);
             .addFunction(setter);
             if (f.isStatic() && !f.isPrivate()) {
                 .addFunction(createClassInitWrapperFunction(getter.ref()));
                 if (!f.isFinal()) {
                     .addFunction(createClassInitWrapperFunction(setter.ref()));
                 }
             }
         }
         
         for (SootMethod method : .getMethods()) {
             
             for (CompilerPlugin compilerPlugin : .getCompilerPlugins()) {
                 compilerPlugin.beforeMethod(clazzmethod);
             }
             
             String name = method.getName();
             if (hasBridgeAnnotation(method)) {
                 bridgeMethod(method);
             } else if (hasGlobalValueAnnotation(method)) {
                 globalValueMethod(method);
             } else if (isStruct() && ("_sizeOf".equals(name
                         || "sizeOf".equals(name) || hasStructMemberAnnotation(method))) {
                 structMember(method);
             } else if (method.isNative()) {
                 nativeMethod(method);
             } else if (!method.isAbstract()) {
                 method(method);
             }
             if (hasCallbackAnnotation(method)) {
                 callbackMethod(method);
             }
             if (!name.equals("<clinit>") && !name.equals("<init>"
                     && !method.isPrivate() && !method.isStatic() 
                     && !Modifier.isFinal(method.getModifiers()) 
                     && !Modifier.isFinal(.getModifiers())) {
                 
                 createLookupFunction(method);
             }
             if (method.isStatic()) {
                 String fnName = mangleMethod(method);
                 if (method.isSynchronized()) {
                     fnName += "_synchronized";
                 }
                 FunctionRef fn = new FunctionRef(fnNamegetFunctionType(method));
                 .addFunction(createClassInitWrapperFunction(fn));
             }
         }
         
         Set<StringtrampolineDependencies = new HashSet<String>();
         for (Trampoline trampoline : ) {
             .compile(trampoline);
             trampolineDependencies.addAll(.getDependencies());
         }
 
         Global classInfoStruct = null;
         try {
             if (!.isInterface()) {
                 .getVTableCache().get();
             }
             classInfoStruct = new Global(mangleClass() + "_info_struct".createClassInfoStruct());
         } catch (IllegalArgumentException e) {
             // VTable throws this if any of the superclasses of the class is actually an interface.
             // Shouldn't happen frequently but the DRLVM test suite has some tests for this.
             // The Linker will take care of making sure the class cannot be loaded at runtime.
             classInfoStruct = new Global(mangleClass() + "_info_struct"true);
         }
         .addGlobal(classInfoStruct);
         
         Function infoFn = FunctionBuilder.infoStruct();
         infoFn.add(new Ret(new ConstantBitcast(classInfoStruct.ref(), )));
         .addFunction(infoFn);
         
         out.write(.build().toString().getBytes("UTF-8"));
         
         ci.setCatchNames();
         ci.setTrampolines();
         
         ci.addDependency("java/lang/Object"); // Make sure no class or interface has zero dependencies
         if (.hasSuperclass() && !.isInterface()) {
             ci.addDependency(getInternalName(.getSuperclass()));
         }
         for (SootClass iface : .getInterfaces()) {
             ci.addDependency(getInternalName(iface));
         }
         for (SootField f : .getFields()) {
             addDependencyIfNeeded(clazzf.getType());
         }
         for (SootMethod m : .getMethods()) {
             addDependencyIfNeeded(clazzm.getReturnType());
             @SuppressWarnings("unchecked")
             List<soot.TypeparamTypes = (List<soot.Type>) m.getParameterTypes();
             for (soot.Type type : paramTypes) {
                 addDependencyIfNeeded(clazztype);
             }
         }
         ci.addDependencies(trampolineDependencies);
         ci.addDependencies();
         
         for (Trampoline t : ) {
             if (!(t instanceof LdcString)) {
                 String desc = t.getTarget();
                 if (desc.charAt(0) == 'L' || desc.charAt(0) == '[') {
                     // Target is a descriptor
                     addDependencyIfNeeded(clazzdesc);
                 } else {
                     ci.addDependency(t.getTarget());
                 }
             }
             if (t instanceof FieldAccessor) {
                 addDependencyIfNeeded(clazz, ((FieldAccessort).getFieldDesc());
             } else if (t instanceof Invoke) {
                 String methodDesc = ((Invoket).getMethodDesc();
                 addDependencyIfNeeded(clazzgetReturnTypeDescriptor(methodDesc));
                 for (String desc : getParameterDescriptors(methodDesc)) {
                     addDependencyIfNeeded(clazzdesc);
                 }
             }
         }
         clazz.saveClazzInfo();
     }
 
     private static void addDependencyIfNeeded(Clazz clazzsoot.Type type) {
         if (type instanceof RefLikeType) {
             addDependencyIfNeeded(clazzgetDescriptor(type));
         }
     }
 
     private static void addDependencyIfNeeded(Clazz clazzString desc) {
         if (!isPrimitive(desc) && (!isArray(desc) || !isPrimitiveBaseType(desc))) {
             String internalName = isArray(desc) ? getBaseType(desc) : getInternalNameFromDescriptor(desc);
             if (!clazz.getInternalName().equals(internalName)) {
                 clazz.getClazzInfo().addDependency(internalName);
             }
         }
     }
     
     private void createLookupFunction(SootMethod m) {
         // TODO: This should use a virtual method table or interface method table.
         Function function = FunctionBuilder.lookup(mtrue);
         .addFunction(function);
 
         Variable reserved0 = function.newVariable();
         function.add(new Getelementptr(reserved0function.getParameterRef(0), 0, 4));
         Variable reserved1 = function.newVariable();
         function.add(new Getelementptr(reserved1function.getParameterRef(0), 0, 5));
         function.add(new Store(getString(m.getName()), reserved0.ref()));
         function.add(new Store(getString(getDescriptor(m)), reserved1.ref()));
         
         if (!.isInterface()) {
             int vtableIndex = 0;
             try {
                 VTable vtable = .getVTableCache().get();
                 vtableIndex = vtable.getEntry(m).getIndex();
             } catch (IllegalArgumentException e) {
                 // VTable throws this if any of the superclasses of the class is actually an interface.
                 // Shouldn't happen frequently but the DRLVM test suite has some tests for this.
                 // Use 0 as vtableIndex since this lookup function will never be called anyway.
             }
             Value classPtr = call(functionfunction.getParameterRef(1));
             Value vtablePtr = call(functionclassPtr);
             Variable funcPtrPtr = function.newVariable();
             function.add(new Getelementptr(funcPtrPtrvtablePtr, 0, 1, vtableIndex));
             Variable funcPtr = function.newVariable();
             function.add(new Load(funcPtrfuncPtrPtr.ref()));
             Variable f = function.newVariable(function.getType());
             function.add(new Bitcast(ffuncPtr.ref(), f.getType()));
             Value result = tailcall(functionf.ref(), function.getParameterRefs());
             function.add(new Ret(result));
         } else {
             ITable itable = .getITableCache().get();
             ITable.Entry entry = itable.getEntry(m);
             List<Valueargs = new ArrayList<Value>();
             args.add(function.getParameterRef(0));
             args.add(getInfoStruct(function));
             args.add(function.getParameterRef(1));
             args.add(new IntegerConstant(entry.getIndex()));
             Value fptr = call(functionargs);
             Variable f = function.newVariable(function.getType());
             function.add(new Bitcast(ffptrf.getType()));
             Value result = tailcall(functionf.ref(), function.getParameterRefs());
             function.add(new Ret(result));
         }
     }
     
     private Constant createVTableStruct() {
         VTable vtable = .getVTableCache().get();
         String name = mangleClass() + "_vtable";
         for (VTable.Entry entry : vtable.getEntries()) {
             FunctionRef fref = entry.getFunctionRef();
             if (fref != null && !.hasSymbol(fref.getName())) {
                 .addFunctionDeclaration(new FunctionDeclaration(fref));
             }
         }
         Global vtableStruct = new Global(name.vtable.getStruct(), true);
         .addGlobal(vtableStruct);
         return new ConstantBitcast(vtableStruct.ref(), );
     }
     
     private Constant createITableStruct() {
         ITable itable = .getITableCache().get();
         String name = mangleClass() + "_itable";
         Global itableStruct = new Global(name.itable.getStruct(), true);
         .addGlobal(itableStruct);
         return new ConstantBitcast(itableStruct.ref(), );
     }
     
     private Constant createITablesStruct() {
         if (!.isInterface()) {
             HashSet<SootClassinterfaces = new HashSet<SootClass>();
             collectInterfaces(interfaces);
             List<Constanttables = new ArrayList<Constant>();
             int i = 0;
             for (SootClass ifs : interfaces) {
                 ITable itable = .getITableCache().get(ifs);
                 if (itable.size() > 0) {
                     String name = mangleClass() + "_itable" + (i++);
                     String typeInfoName = mangleClass(ifs) + "_typeinfo";
                     if (!.hasSymbol(typeInfoName)) {
                         .addGlobal(new Global(typeInfoName.true));
                     }
                     Global itableStruct = new Global(name.,
                             new StructureConstantBuilder()
                                 .add(.getGlobalRef(typeInfoName))
                                 .add(itable.getStruct()).build(), true);
                     .addGlobal(itableStruct);
                     tables.add(new ConstantBitcast(itableStruct.ref(), ));
                 }
             }
             
             if (tables.isEmpty()) {
                 return new NullConstant();
             } else {
                 Global itablesStruct = new Global(mangleClass() + "_itables".,
                         new StructureConstantBuilder()
                             .add(new IntegerConstant((shorttables.size()))
                             .add(tables.get(0)) // cache value must never be null
                             .add(new ArrayConstantBuilder().add(tables).build())
                             .build());
                 .addGlobal(itablesStruct);
                 return new ConstantBitcast(itablesStruct.ref(), );
             }
             
         } else {
             return new NullConstant();
         }
     }
     
         int flags = 0;
         
         if (Modifier.isPublic(.getModifiers())) {
             flags |= ;
         }
         if (Modifier.isFinal(.getModifiers())) {
             flags |= ;
         }
         if (Modifier.isInterface(.getModifiers())) {
             flags |= ;
         }
         if (Modifier.isAbstract(.getModifiers())) {
             flags |= ;
         }
         if ((.getModifiers() & 0x1000) > 0) {
             flags |= ;
         }
         if (Modifier.isAnnotation(.getModifiers())) {
             flags |= ;
         }
         if (Modifier.isEnum(.getModifiers())) {
             flags |= ;
         }
         if (.classHasAttributes()) {
             flags |= ;
         }
         if (hasFinalizer()) {
             flags |= ;
         }
         
         // Create the ClassInfoHeader structure.
         StructureConstantBuilder header = new StructureConstantBuilder();
         header.add(new NullConstant()); // Points to the runtime Class struct
         header.add(new IntegerConstant(flags));
         header.add(getString(getInternalName()));
         if (.declaresMethod("<clinit>", Collections.emptyList(), VoidType.v())) {
             SootMethod method = .getMethod("<clinit>", Collections.emptyList(), VoidType.v());
             header.add(new FunctionRef(mangleMethod(method), getFunctionType(method)));            
         } else {
             header.add(new NullConstant());
         }
         .addGlobal(new Global(mangleClass() + "_typeinfo".true));
         header.add(new GlobalRef(mangleClass() + "_typeinfo")); // TypeInfo* generated by Linker
 
         if (!.isInterface()) {
             header.add(createVTableStruct());
         } else {
             header.add(createITableStruct());
         }
         header.add(createITablesStruct());
         
         header.add(sizeof());
         header.add(sizeof());
         if (!.isEmpty()) {
             header.add(offsetof(, 1, 1));
         } else {
             header.add(sizeof());
         }
         header.add(new IntegerConstant((shortcountReferences()));
         header.add(new IntegerConstant((shortcountReferences()));
 
         body.add(new IntegerConstant((short.getInterfaceCount()));
         body.add(new IntegerConstant((short.getFieldCount()));
         body.add(new IntegerConstant((short.getMethodCount()));
         
         if (!.isInterface()) {
             body.add(getStringOrNull(.hasSuperclass() ? getInternalName(.getSuperclass()) : null));
         }
 
         if (.classHasAttributes()) {
             body.add(new ConstantBitcast(.getClassAttributes().ref(), ));
         }
         
         for (SootClass s : .getInterfaces()) {
             body.add(getString(getInternalName(s)));
         }
         
         for (SootField f : .getFields()) {
             flags = 0;
             soot.Type t = f.getType();
             if (t instanceof PrimType) {
                 if (t.equals(BooleanType.v())) {
                     flags |= ;
                 } else if (t.equals(ByteType.v())) {
                     flags |= ;
                 } else if (t.equals(ShortType.v())) {
                     flags |= ;
                 } else if (t.equals(CharType.v())) {
                     flags |= ;
                 } else if (t.equals(IntType.v())) {
                     flags |= ;
                 } else if (t.equals(LongType.v())) {
                     flags |= ;
                 } else if (t.equals(FloatType.v())) {
                     flags |= ;
                 } else if (t.equals(DoubleType.v())) {
                     flags |= ;
                 }
                 flags <<= 12;
             }
             if (Modifier.isPublic(f.getModifiers())) {
                 flags |= ;
             } else if (Modifier.isPrivate(f.getModifiers())) {
                 flags |= ;
             } else if (Modifier.isProtected(f.getModifiers())) {
                 flags |= ;
             }
             if (Modifier.isStatic(f.getModifiers())) {
                 flags |= ;
             }
             if (Modifier.isFinal(f.getModifiers())) {
                 flags |= ;
             }
             if (Modifier.isVolatile(f.getModifiers())) {
                 flags |= ;
             }
             if (Modifier.isTransient(f.getModifiers())) {
                 flags |= ;
             }
             if ((f.getModifiers() & 0x1000) > 0) {
                 flags |= ;
             }
             if (Modifier.isEnum(f.getModifiers())) {
                 flags |= ;
             }
             if (.fieldHasAttributes(f)) {
                 flags |= ;
             }
             body.add(new IntegerConstant((shortflags));
             body.add(getString(f.getName()));
             if (!(t instanceof PrimType)) {
                 body.add(getString(getDescriptor(f)));
             }
             if (f.isStatic()) {
                 int index = .indexOf(f);
                 body.add(offsetof(, 1, index, 1));
             } else {
                 int index = .indexOf(f);
                 body.add(offsetof(, 1, 1 + index, 1));
             }
             if (.fieldHasAttributes(f)) {
                 body.add(new ConstantBitcast(.getFieldAttributes(f).ref(), ));
             }
         }
         
         VTable vtable = !.isInterface() ? .getVTableCache().get() : null;
         ITable itable = .isInterface() ? .getITableCache().get() : null;;
 
         for (SootMethod m : .getMethods()) {
             soot.Type t = m.getReturnType();