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

com.codename1.tools.translator.ByteCodeClass Maven / Gradle / Ivy

There is a newer version: 7.0.164
Show newest version
/*
 * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Codename One designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *  
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 * 
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 * 
 * Please contact Codename One through http://www.codenameone.com/ if you 
 * need additional information or have any questions.
 */

package com.codename1.tools.translator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

/**
 * Parsed class file
 *
 * @author Shai Almog
 */
public class ByteCodeClass {

    /**
     * @param isAnonymous the isAnonymous to set
     */
    public void setIsAnonymous(boolean isAnonymous) {
        this.isAnonymous = isAnonymous;
    }

    /**
     * @param isSynthetic the isSynthetic to set
     */
    public void setIsSynthetic(boolean isSynthetic) {
        this.isSynthetic = isSynthetic;
    }

    /**
     * @param isAnnotation the isAnnotation to set
     */
    public void setIsAnnotation(boolean isAnnotation) {
        this.isAnnotation = isAnnotation;
    }
    private List fullFieldList;
    private List staticFieldList;
    private Set dependsClassesInterfaces = new TreeSet();
    private Set exportsClassesInterfaces = new TreeSet();
    private List methods = new ArrayList();
    private List fields = new ArrayList();
    private String clsName;
    private String originalClassName;
    private String baseClass;
    private List baseInterfaces;
    private boolean isInterface;
    private boolean isAbstract;
    private boolean isSynthetic;
    private boolean isAnnotation;
    private boolean isAnonymous;
    private boolean eliminated;

    private static boolean saveUnitTests;
    private boolean isUnitTest;


    private static Set arrayTypes = new TreeSet();
    
    private ByteCodeClass baseClassObject;
    private List baseInterfacesObject;
    
    List virtualMethodList;
    private String sourceFile;

    private int classOffset;
    
    private boolean marked;
    private static ByteCodeClass mainClass;
    private boolean finalClass;
    private boolean isEnum;
    private static Set writableFields = new HashSet();
    
    /**
     * 
     * @param clsName Class name with mangling.  e.g. java_lang_String
     * @param originalClassName Classname without mangling.  e.g. java/lang/String
     */
    public ByteCodeClass(String clsName, String originalClassName) {
        this.clsName = clsName;
        this.originalClassName = originalClassName;
    }

    /**
     * Checks if this class has been eliminated.
     * @return
     */
    public boolean isEliminated() {
        return eliminated;
    }

    /**
     * Marks class as eliminated.  Will recursively set all class methods
     * as eliminated too.
     * @param eliminated True to set eliminated.
     * @return Number of methods that were newly marked as eliminated by this call.
     */
    public int setEliminated(boolean eliminated) {
        int nfound = 0;
        if (this.eliminated) return nfound;
        this.eliminated = eliminated;
        if (eliminated) {
            for (BytecodeMethod m : methods) {
                if (!m.isEliminated()) {
                    m.setEliminated(true);
                    nfound++;
                }
            }
        }
        return nfound;

    }
    
    /**
     * Class name in original JVM format:  e.g. java/lang/String
     * @return 
     */
    public String getOriginalClassName() {
        return originalClassName;
    }
    static ByteCodeClass getMainClass() {
		return mainClass;
    }
    
    static void setSaveUnitTests(boolean save) {
        saveUnitTests = save;
    }
    
    public void addMethod(BytecodeMethod m) {
        if(m.isMain()) {
            if (mainClass == null) {
                mainClass = this;
            } else {
                throw new RuntimeException("Multiple main classes: "+mainClass.clsName+" and "+this.clsName);
            }
        }
        m.setSourceFile(sourceFile);
        m.setForceVirtual(isInterface);
        methods.add(m);
    }


    public void addField(ByteCodeField m) {
        fields.add(m);
    }
    
    public String generateCSharpCode() {
        return "";
    }
    
    public void addWritableField(String field) {
        writableFields.add(field);
    }

    /**
     * Marks dependencies in this class based on the provided classes in this round of optimization.
     * @param lst The list of classes that are available in this optimization step.
     * @param nativeSources Array of native sources in this round. Used to check if native files reference
     *                      this class or methods.
     */
    public static void markDependencies(List lst, String[] nativeSources) {
        mainClass.markDependent(lst);
        for(ByteCodeClass bc : lst) {
            if (bc.marked) {
                continue;
            }
            if (bc.isEliminated()) {
                continue;
            }
            if(bc.clsName.equals("java_lang_Boolean")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_lang_String")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_lang_Integer")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_lang_Byte")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_lang_Short")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_lang_Character")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_lang_Thread")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_lang_Long")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_lang_Double")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_lang_Float")) {
                bc.markDependent(lst);
                continue;
            }
            if(bc.clsName.equals("java_text_DateFormat")) {
                bc.markDependent(lst);
                continue;
            }
            if (bc.getUsedByNative() == UsedByNativeResult.Unknown) {
                // We don't yet know if this class is used by native
                // calculate it now.
                bc.calcUsedByNative(nativeSources);
            }
            if(bc.getUsedByNative() == UsedByNativeResult.Used){
                bc.markDependent(lst);
                continue;
            }
            if(saveUnitTests && bc.isUnitTest) {
                bc.markDependent(lst);
                continue;
            }
        }
        
        // mark all non-final classes that aren't inherited as final for use in 
        // additional optimizations
        for(ByteCodeClass bc : lst) {
            if(bc.isFinalClass() || bc.isInterface || bc.isIsAbstract()) {
                continue;
            }
            boolean found = false;
            for(ByteCodeClass bk : lst) {
                if(bk.baseClassObject == bc) {
                    found = true;
                    break;
                }
            }
            if(!found) {
                bc.setFinalClass(true);
            }
        }
        
        // we try to disable the "virtual" aspect of methods where possible
        for(ByteCodeClass bc : lst) {
            if(bc.isFinalClass()) {
                for(BytecodeMethod meth : bc.methods) {
                    if(meth.canBeVirtual() && !bc.isMethodFromBaseOrInterface(meth)) {
                        meth.setVirtualOverriden(true);
                    }
                } 
            } 
        }        
    }
    
    
    public boolean isMethodPrivate(String name, String desc) {
        for (BytecodeMethod meth : methods) {
            if (meth.getMethodName().equals(name) && desc.equals(meth.getSignature())) {
                return meth.isPrivate();
            }
        }
        return false;
    }

    public void unmark() {
        marked = false;
    }
    
    private void markDependent(List lst) {
        if(marked) {
            return;
        }

        marked = true;
        
        // make sure the method/classname are in the constant pool so we can later 
        // look them up in case of a stack trace exception
        Parser.addToConstantPool(clsName);
        for(BytecodeMethod bm : methods) {
            if(!bm.isEliminated()) {
                Parser.addToConstantPool(bm.getMethodName());
                bm.addToConstantPool();
            }
        }
        
        for(String s : dependsClassesInterfaces) {
            ByteCodeClass cls = findClass(s, lst);
            
            // annotation can be null
            if(cls != null) {
                cls.markDependent(lst);
            }
        }
    }
    
    public static List clearUnmarked(List lst) {
        List response = new ArrayList();
        for(ByteCodeClass bc : lst) {
            if(bc.marked) {
                response.add(bc);
            }
        }
        return response;
    }
    
    private ByteCodeClass findClass(String s, List lst) {
        for(ByteCodeClass c : lst) {
            if(c.clsName.equals(s)) {
                return c;
            }
        }
        return null;
    }
    
    public void updateAllDependencies() {
        dependsClassesInterfaces.clear();
        exportsClassesInterfaces.clear();
        dependsClassesInterfaces.add("java_lang_NullPointerException");
        setBaseClass(baseClass);
        if (isAnnotation) {
            dependsClassesInterfaces.add("java_lang_annotation_Annotation");
        }
        for(String s : baseInterfaces) {
            s = s.replace('/', '_').replace('$', '_');
            if(!dependsClassesInterfaces.contains(s)) {
                dependsClassesInterfaces.add(s);
            }
            exportsClassesInterfaces.add(s);
        }
        if(virtualMethodList != null) {
            virtualMethodList.clear();
        } else {
            virtualMethodList = new ArrayList();
        }
        fillVirtualMethodTable(virtualMethodList);
        for(BytecodeMethod m : methods) {
            if(m.isEliminated()) {
                continue;
            }

            for(String s : m.getDependentClasses()) {
                if(!dependsClassesInterfaces.contains(s)) {
                    dependsClassesInterfaces.add(s);
                }
            }
            //for (String s : m.getExportedClasses()) {
            //    exportsClassesInterfaces.add(s);
            //}
        }
        for(ByteCodeField m : fields) {
            for(String s : m.getDependentClasses()) {
                if(!dependsClassesInterfaces.contains(s)) {
                    dependsClassesInterfaces.add(s);
                }
            }
            //for (String s : m.getExportedClasses()) {
            //    exportsClassesInterfaces.add(s);
            //}
        }
    }
    
    private boolean isMethodFromBaseOrInterface(BytecodeMethod bm) {
        if(baseInterfacesObject != null) {
            for(ByteCodeClass bi : baseInterfacesObject) {
                if(bi.getMethods().contains(bm)) {
                    return true;
                }
                if(bi.getBaseClassObject() != null) {
                    boolean b = bi.isMethodFromBaseOrInterface(bm);
                    if(b) {
                        return true;
                    }
                }
            }
        }
        if(baseClassObject != null) {
            if(baseClassObject.getMethods().contains(bm)) {
                return true;
            }
            return baseClassObject.isMethodFromBaseOrInterface(bm);
        }
        return false;
    }
    
    private boolean hasDefaultConstructor() {
        for(BytecodeMethod bm : methods) {
            if(bm.isDefaultConstructor()) {
                return true;
            }
        }
        return false;
    }

    private boolean hasFinalizer() {
        for(BytecodeMethod bm : methods) {
            if(bm.isFinalizer()) {
                return true;
            }
        }
        return false;
    }
    
    public static void addArrayType(String type, int dimenstions) {
        String arr = dimenstions + "_" + type;
        if(!arrayTypes.contains(arr)) {
            arrayTypes.add(arr);
        }
    }



    public String generateCCode(List allClasses) {

        StringBuilder b = new StringBuilder();
        b.append("#include \"");
        b.append(clsName);
        
        b.append(".h\"\n");
        
        for(String s : dependsClassesInterfaces) {
            if (exportsClassesInterfaces.contains(s)) {
                continue;
            }
            b.append("#include \"");
            b.append(s);
            b.append(".h\"\n");
        }
        
        b.append("const struct clazz *base_interfaces_for_");
        b.append(clsName);
        b.append("[] = {");
        boolean first = true;
        for(String ints : baseInterfaces) {
            if(!first) {
                b.append(", ");            
            }
            first = false;
            b.append("&class__");
            b.append(ints.replace('/', '_').replace('$', '_'));
        }
        b.append("};\n");
        
        
        // class struct, contains vtable, static fields and meta data (class name), type info etc.
        b.append("struct clazz class__");
        b.append(clsName);
        b.append(" = {\n");
        // object fields so class will be compatible to object
        
        if(clsName.equals("java_lang_Class")) {
            b.append("  DEBUG_GC_INIT 0, 999999, 0, 0, 0, 0, &__FINALIZER_");
        } else {
            b.append("  DEBUG_GC_INIT &class__java_lang_Class, 999999, 0, 0, 0, 0, &__FINALIZER_");
        }
        b.append(clsName);
        b.append(" ,0 , &__GC_MARK_");
        b.append(clsName);
        
        // initialized defaults to false
        b.append(",  0, ");
        
        // the numberic id of the class 
        b.append("cn1_class_id_");
        b.append(clsName);
        b.append(", ");
        
        // name of the class
        b.append("\"");
        b.append(clsName.replace('_', '.'));
        b.append("\", ");
        
        // is array class type
        b.append("0, ");
        
        // array type dimensions
        b.append("0, ");
        
        // array internal type
        b.append("0, ");
        
        // primitive type
        b.append("JAVA_FALSE, ");
        
        // reference to the base class
        if(baseClass != null) {
            b.append("&class__");
            b.append(baseClass.replace('/', '_').replace('$', '_'));
        } else {
            b.append("(const struct clazz*)0");
        }
        b.append(", ");
        
        // references to the base interfaces
        b.append("base_interfaces_for_");
        b.append(clsName);
        b.append(", ");

        // number of base interfaces
        b.append(baseInterfaces.size());
        
        // new instance function pointer
        if(!isInterface && !isAbstract && hasDefaultConstructor()) {
            b.append(", &__NEW_INSTANCE_");
            b.append(clsName);
        } else {
            b.append(", 0");
        }
        
        // vtable 
        b.append(", 0\n");
        
        if (isEnum) {
            b.append(", &__VALUE_OF_");
            b.append(clsName);
        } else {
            b.append(", 0");
        }
        
        /*
        JAVA_BOOLEAN isSynthetic;
    JAVA_BOOLEAN isInterface;
    JAVA_BOOLEAN isAnonymous;
    JAVA_BOOLEAN isAnnotation;
        */
        b
                .append(", ")
                .append(isSynthetic?"JAVA_TRUE":"0")
                .append(", ")
                .append(isInterface?"JAVA_TRUE":"0")
                .append(", ")
                .append(isAnonymous?"JAVA_TRUE":"0")
                .append(", ")
                .append(isAnnotation?"JAVA_TRUE":"0")
                .append(", ")
                .append(getArrayClazz(1));
        
        
        b.append("};\n\n");

        // create class objects for 1 - 3 dimension arrays
        for(int iter = 1 ; iter < 4 ; iter++) {
            if(!(arrayTypes.contains(iter + "_" + clsName) || arrayTypes.contains((iter + 1) + "_" + clsName) || 
                    arrayTypes.contains((iter + 2) + "_" + clsName))) {
                continue;
            }
            b.append("struct clazz class_array");
            b.append(iter);
            b.append("__");
            b.append(clsName);
            if(clsName.equals("java_lang_Class")) {
                b.append(" = {\n DEBUG_GC_INIT 0, 999999, 0, 0, 0, 0, 0, &arrayFinalizerFunction, &gcMarkArrayObject, 0, cn1_array_");
            } else {
                b.append(" = {\n DEBUG_GC_INIT &class__java_lang_Class, 999999, 0, 0, 0, 0, 0, &arrayFinalizerFunction, &gcMarkArrayObject, 0, cn1_array_");
            }
            b.append(iter);
            b.append("_id_");
            b.append(clsName);
            b.append(", \"");
            b.append(clsName.replace('_', '.'));
            for (int arrayDim = 0; arrayDim < iter; arrayDim++) {
                b.append("[]");
            }
            b.append("\", ");

            // array class type, dimension & internal type
            b.append("JAVA_TRUE, ");
            b.append(iter);
            b.append(", &class__");
            b.append(clsName);

            /*
            JAVA_BOOLEAN primitiveType;

            const struct clazz* baseClass;
            const struct clazz** baseInterfaces;
            const int baseInterfaceCount;

            void* newInstanceFp;

            // virtual method table lookup
            void** vtable;

            void* enumValueOfFp;
            JAVA_BOOLEAN isSynthetic;
            JAVA_BOOLEAN isInterface;
            JAVA_BOOLEAN isAnonymous;
            JAVA_BOOLEAN isAnnotation;
            */
            // primitive type is always false here object is always the base class of the array it has no base interfaces
            b.append(", JAVA_FALSE, &class__java_lang_Object, EMPTY_INTERFACES, 0, ");

            // new instance function pointer and vtable 
            b.append("0, 0, 0, 0, 0, 0, 0, "+getArrayClazz(iter+1)+"\n};\n\n");
        }

        staticFieldList = new ArrayList();
        buildStaticFieldList(staticFieldList);
        String enumValuesField = null;
        // static fields for the class
        for(ByteCodeField bf : staticFieldList) {
            if(bf.isStaticField() && bf.getClsName().equals(clsName)) {
                if (isEnum && ("_VALUES".equals(bf.getFieldName().replace('$','_')) || "ENUM_VALUES".equals(bf.getFieldName().replace('$','_')))) {
                    enumValuesField = bf.getFieldName();
                }
                if(bf.isFinal() && bf.getValue() != null && !writableFields.contains(bf.getFieldName())) {
                    // static getter 
                    b.append(bf.getCDefinition());
                    b.append(" get_static_");
                    b.append(clsName);
                    b.append("_");
                    b.append(bf.getFieldName().replace('$', '_'));
                    b.append("(CODENAME_ONE_THREAD_STATE) {\n    return ");
                    if(bf.getValue() instanceof String) {
                        b.append("STRING_FROM_CONSTANT_POOL_OFFSET(");
                        b.append(Parser.addToConstantPool((String)bf.getValue()));
                        b.append(") /* ");
                        b.append(String.valueOf(bf.getValue()).replace("*/", "* /"));
                        b.append(" */");
                    } else {
                        if(bf.getValue() instanceof Number) {
                            if(bf.getValue() instanceof Double) {
                                Double d = ((Double)bf.getValue());
                                if(d.isNaN()) {
                                    b.append("0.0/0.0");                                    
                                } else {
                                    if(d.isInfinite()) {
                                        if(d.doubleValue() > 0) {
                                            b.append("1.0f / 0.0f");
                                        } else {
                                            b.append("-1.0f / 0.0f");
                                        }
                                    } else {
                                        b.append(bf.getValue());
                                    }
                                }
                            } else {
                                if(bf.getValue() instanceof Float) {
                                    Float d = ((Float)bf.getValue());
                                    if(d.isNaN()) {
                                        b.append("0.0/0.0");                                    
                                    } else {
                                        if(d.isInfinite()) {
                                            if(d.floatValue() > 0) {
                                                b.append("1.0f / 0.0f");
                                            } else {
                                                b.append("-1.0f / 0.0f");
                                            }
                                        } else {
                                            b.append(bf.getValue());
                                        }
                                    }
                                } else {
                                    b.append(bf.getValue());
                                }
                            }
                        } else {
                            if(bf.getValue() instanceof Boolean) {
                                if(((Boolean)bf.getValue()).booleanValue()) {
                                    b.append("JAVA_TRUE");
                                } else {
                                    b.append("JAVA_FALSE");
                                }
                            } else {
                                b.append("JAVA_NULL");
                            }
                        }
                    }
                    b.append(";\n}\n\n");                    
                } else {
                    b.append(bf.getCDefinition());
                    b.append(" STATIC_FIELD_");
                    b.append(clsName);
                    b.append("_");
                    b.append(bf.getFieldName());
                    b.append(" = 0;\n");

                    // static getter 
                    b.append(bf.getCDefinition());
                    b.append(" get_static_");
                    b.append(clsName);
                    b.append("_");
                    b.append(bf.getFieldName().replace('$', '_'));
                    b.append("(CODENAME_ONE_THREAD_STATE) {\n    __STATIC_INITIALIZER_");
                    b.append(bf.getClsName());
                    b.append("(threadStateData);\n     return STATIC_FIELD_");
                    b.append(bf.getClsName());
                    b.append("_");
                    b.append(bf.getFieldName());
                    b.append(";\n}\n\n");

                    // static setter 
                    b.append("void set_static_");
                    b.append(clsName);
                    b.append("_");
                    b.append(bf.getFieldName().replace('$', '_'));
                    b.append("(CODENAME_ONE_THREAD_STATE, ");
                    b.append(bf.getCDefinition());
                    b.append(" __cn1StaticVal) {\n    __STATIC_INITIALIZER_");
                    b.append(bf.getClsName());
                    if(bf.isObjectType()) {
                        if(bf.isFinal()) {
                            b.append("(threadStateData);\n    STATIC_FIELD_");                        
                        } else {
                            b.append("(threadStateData);\n    STATIC_FIELD_");
                        }
                    } else {
                        b.append("(threadStateData);\n    STATIC_FIELD_");
                    }
                    b.append(bf.getClsName());
                    b.append("_");
                    b.append(bf.getFieldName());
                    if(bf.shouldRemoveFromHeapCollection()) {
                        if(bf.getType() != null && bf.getType().endsWith("String")) {
                            b.append(" = __cn1StaticVal;\n    removeObjectFromHeapCollection(threadStateData, __cn1StaticVal);\n    if(__cn1StaticVal != 0) {\n        removeObjectFromHeapCollection(threadStateData, ((struct obj__java_lang_String*)__cn1StaticVal)->java_lang_String_value);\n    }\n}\n\n");
                        } else {
                            b.append(" = __cn1StaticVal;\n    removeObjectFromHeapCollection(threadStateData, __cn1StaticVal);\n}\n\n");
                        }
                    } else {
                        b.append(" = __cn1StaticVal;\n}\n\n");
                    }
                }
            }
        }        
        
        if(isInterface) {
            b.append("int **classToInterfaceMap_");
            b.append(clsName);
            b.append(";\n");
        }
        
        fullFieldList = new ArrayList();
        buildInstanceFieldList(fullFieldList);
        
        String nullCheck = "";
        if (System.getProperty("fieldNullChecks", "false").equals("true")) {
            nullCheck = "if(__cn1T == JAVA_NULL){throwException(getThreadLocalData(), __NEW_INSTANCE_java_lang_NullPointerException(getThreadLocalData()));}\n";
        }
        for(ByteCodeField fld : fullFieldList) {
            b.append(fld.getCDefinition());
            b.append(" get_field_");
            b.append(clsName);
            b.append("_");
            b.append(fld.getFieldName());
            b.append("(JAVA_OBJECT __cn1T) {\n ").append(nullCheck).append(" return (*(struct obj__");
            b.append(clsName);
            b.append("*)__cn1T).");            
            b.append(fld.getClsName());
            b.append("_");
            b.append(fld.getFieldName());
            b.append(";\n}\n\n");

            b.append("void set_field_");
            b.append(clsName);
            b.append("_");
            b.append(fld.getFieldName());
            b.append("(CODENAME_ONE_THREAD_STATE, ");
            b.append(fld.getCDefinition());
            if(fld.isObjectType()) {
                b.append(" __cn1Val, JAVA_OBJECT __cn1T) {\n ").append(nullCheck).append("   (*(struct obj__");
            } else {
                b.append(" __cn1Val, JAVA_OBJECT __cn1T) {\n  ").append(nullCheck).append("  (*(struct obj__");
            }
            b.append(clsName);
            b.append("*)__cn1T).");            
            b.append(fld.getClsName());
            b.append("_");
            b.append(fld.getFieldName());
            b.append(" = __cn1Val;\n}\n\n");
        }
                
        
        // finalizer and GC_RELEASE to cleanup variables
        b.append("JAVA_VOID __FINALIZER_");
        b.append(clsName);
        b.append("(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT objToDelete) {\n");
        if(hasFinalizer()) {
            b.append("    ");
            b.append(clsName);
            b.append("_finalize__(threadStateData, objToDelete);\n");
        }
        // invoke the finalize method of the base
        if(baseClass != null) {
            b.append("    __FINALIZER_");
            b.append(baseClass.replace('/', '_').replace('$', '_'));
            b.append("(threadStateData, objToDelete);\n");
        }
        
        b.append("}\n\n");
                
        // mark function for the GC mark cycle to tag the objects that are reachable
        b.append("void __GC_MARK_");
        b.append(clsName);
        b.append("(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT objToMark, JAVA_BOOLEAN force) {\n    struct obj__");
        b.append(clsName);
        b.append("* objInstance = (struct obj__");
        b.append(clsName);
        b.append("*)objToMark;\n");
        for(ByteCodeField fld : fullFieldList) {
            if(!fld.isStaticField() && fld.isObjectType() && fld.getClsName().equals(clsName)) {
                b.append("    gcMarkObject(threadStateData, objInstance->");
                b.append(fld.getClsName());
                b.append("_");
                b.append(fld.getFieldName());
                b.append(", force);\n");
            }
        }
        // invoke the mark method of the base
        if(baseClass != null) {
            b.append("    __GC_MARK_");
            b.append(baseClass.replace('/', '_').replace('$', '_'));
            b.append("(threadStateData, objToMark, force);\n");
        } else {
            // we can do this in Object.java only since all code will reach here eventually
            b.append("    objToMark->__codenameOneGcMark = currentGcMarkValue;\n");
        }
        b.append("}\n\n");

        // initialize object instances

        if(!isInterface && !isAbstract) {
            b.append("JAVA_OBJECT __NEW_");
            b.append(clsName);
            b.append("(CODENAME_ONE_THREAD_STATE) {\n    __STATIC_INITIALIZER_");
            b.append(clsName);
            b.append("(threadStateData);\n    JAVA_OBJECT o = codenameOneGcMalloc(threadStateData, sizeof(struct obj__");
            b.append(clsName);
            b.append("), &class__");
            b.append(clsName);
            b.append(");\n    return o;\n}\n\n");

            if(hasDefaultConstructor()) {
                b.append("JAVA_OBJECT __NEW_INSTANCE_");
                b.append(clsName);
                b.append("(CODENAME_ONE_THREAD_STATE) {\n    __STATIC_INITIALIZER_");
                b.append(clsName);
                b.append("(threadStateData);\n    JAVA_OBJECT o = codenameOneGcMalloc(threadStateData, sizeof(struct obj__");
                b.append(clsName);
                b.append("), &class__");
                b.append(clsName);
                b.append(");\n");
                b.append(clsName);
                b.append("___INIT____(threadStateData, o);\n    return o;\n}\n\n");
            }
        }
                
        if(arrayTypes.contains("1_" + clsName) || arrayTypes.contains("2_" + clsName) || arrayTypes.contains("3_" + clsName)) {
            b.append("JAVA_OBJECT __NEW_ARRAY_");
            b.append(clsName);
            b.append("(CODENAME_ONE_THREAD_STATE, JAVA_INT size) {\n");
            b.append("    JAVA_OBJECT o = allocArray(threadStateData, size, &class_array1__");
            b.append(clsName);
            b.append(", sizeof(JAVA_OBJECT), 1);\n    (*o).__codenameOneParentClsReference = &class_array1__");
            b.append(clsName);
            b.append(";\n    return o;\n}\n\n");
        }

        /*b.append("JAVA_OBJECT __NEW_MULTI_ARRAY_");
        b.append(clsName);
        b.append("(CODENAME_ONE_THREAD_STATE, JAVA_INT dimensions, JAVA_INT* sizes) {\n    JAVA_OBJECT o = JAVA_NULL;\n");
        b.append("    switch(dimensions) {\n        case 2: o = allocMultiArray(sizes, &class_array2__");
        b.append(clsName);
        b.append(", sizeof(JAVA_OBJECT), 2); break;\n");
        b.append("        case 3: o = allocMultiArray(sizes, &class_array3__");
        b.append(clsName);
        b.append(", sizeof(JAVA_OBJECT), 3); break;\n");
        b.append("        case 4: o = allocMultiArray(sizes, &class_array4__");
        b.append(clsName);
        b.append(", sizeof(JAVA_OBJECT), 4); break;\n");
        b.append("        default: return JAVA_NULL;\n    }\n    (*o).__codenameOneParentClsReference = &class__");
        b.append(clsName);
        b.append(";\n    return o;\n}\n\n");*/

        String clInitMethod = null;
        if(isInterface) {
            for(BytecodeMethod m : methods) {
                if(m.getMethodName().equals("__CLINIT__")) {
                    m.appendMethodC(b);
                    clInitMethod = clsName + "_" + m.getMethodName() + "__";
                } else {
                    m.appendInterfaceMethodC(b);
                }
            }
        } else {
            for(BytecodeMethod m : methods) {
                m.appendMethodC(b);
                if(m.getMethodName().indexOf("_CLINIT_") > -1) {
                    clInitMethod = clsName + "_" + m.getMethodName() + "__";
                }
                if(m.isMain()) {
                    b.append("\nint main(int argc, char *argv[]) {\n    initConstantPool();\n");
                    b.append("    ");
                    b.append(clsName);
                    b.append("_main___java_lang_String_1ARRAY(getThreadLocalData(), JAVA_NULL);\n}\n\n");
                }
            }
        }
        if(baseClassObject != null) {
            List bm = new ArrayList(methods);
            appendSuperStub(b, bm, baseClassObject);
        }
        int offset = 0;
        if(clsName.equals("java_lang_Class")) {
            // special case for Class which can't have a vtable since it has no class of its own...
            appendClassVFunctions(b);
        } else {
            if(isInterface) {
                // special case, object virtual calls on interfaces should act
                // as if they are regular virtual calls
                for(BytecodeMethod m : virtualMethodList) {
                    if(m.getClsName().equals("java_lang_Object")) {
                        m.appendVirtualMethodC(clsName, b, "" + offset, true);
                    } else {
                        // we pretend to have a virtual method here but the optimizer says its not really needed
                        if(!m.isVirtualOverriden()) {
                            m.appendVirtualMethodC(clsName, b, "classToInterfaceMap_" + clsName + 
                                    "[__cn1ThisObject->__codenameOneParentClsReference->classId][" + offset + "]", true);
                        }
                        offset++;
                    }
                }
            } else {
                for(BytecodeMethod m : virtualMethodList) {
                    m.appendVirtualMethodC(clsName, b, offset);
                    offset++;
                }
            }
        }
        if(!isInterface) {
            b.append("void __INIT_VTABLE_");
            b.append(clsName);
            b.append("(CODENAME_ONE_THREAD_STATE, void** vtable) {\n    ");
            if(baseClass != null) {
                b.append("    __INIT_VTABLE_");
                b.append(baseClass.replace('/', '_').replace('$', '_'));
                b.append("(threadStateData, vtable);\n");
            }
            for(int iter = 0 ; iter < virtualMethodList.size() ; iter++) {

                BytecodeMethod bm = virtualMethodList.get(iter);

                if(bm.getClsName().equals(clsName) && !bm.isVirtualOverriden()) {
                    b.append("    vtable[");
                    b.append(iter);
                    b.append("] = &");
                    bm.appendFunctionPointer(b);
                    b.append(";\n");
                }
            }
            b.append("}\n\n");
        }
        
        if (isEnum) {
            
            b.append("JAVA_OBJECT __VALUE_OF_").append(clsName).append("(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT value) {\n    ");
            if (enumValuesField != null) {
                b.append("    JAVA_ARRAY values = (JAVA_ARRAY)get_static_").append(clsName).append("_").append(enumValuesField.replace('$', '_')).append("(threadStateData);\n");
                b.append("    JAVA_ARRAY_OBJECT* data = (JAVA_ARRAY_OBJECT*)values->data;\n");
                b.append("    int len = values->length;\n");
                b.append("    for (int i=0; i bm, ByteCodeClass base) {
        // append super stub
        BytecodeMethod.setAcceptStaticOnEquals(true);
        for(BytecodeMethod m : base.methods) {
            if(!m.isPrivate() && !bm.contains(m)) {
                m.appendSuperCall(b, clsName);
                bm.add(m);
            }
        }
        if(base.baseClassObject != null) {
            appendSuperStub(b, bm, base.baseClassObject);
        }
        BytecodeMethod.setAcceptStaticOnEquals(false);
    }
    
    private void appendSuperStubHeader(StringBuilder b, List bm, ByteCodeClass base) {
        BytecodeMethod.setAcceptStaticOnEquals(true);
        // append super stub
        for(BytecodeMethod m : base.methods) {
            if(!m.isPrivate() && !bm.contains(m)) {
                m.appendMethodHeader(b, clsName);
                bm.add(m);
            }
        }
        if(base.baseClassObject != null) {
            appendSuperStubHeader(b, bm, base.baseClassObject);
        }
        BytecodeMethod.setAcceptStaticOnEquals(false);
    }
    
    private void buildInstanceFieldList(List fieldList) {
        buildInstanceFieldList(fieldList, true);
    }
    
    private void buildInstanceFieldList(List fieldList, boolean includePrivateFields) {
        for(ByteCodeField bf : fields) {
            // We don't include private fields from parent classes.
            if (!includePrivateFields && bf.isPrivate()) continue;
            if(!bf.isStaticField() && !fieldList.contains(bf)) {
                fieldList.add(bf);
            } 
        }
        if(baseClassObject != null) {
            baseClassObject.buildInstanceFieldList(fieldList, false);
        }        
    } 

    private List buildStaticFieldList(List fieldList) {
        return buildStaticFieldList(fieldList, true);
    }
    
    private List buildStaticFieldList(List fieldList, boolean includePrivateFields) {
        if (fields != null) {
            for(ByteCodeField bf : fields) {
                // We don't include private fields from parent classes.
                if (!includePrivateFields && bf.isPrivate()) continue;
                if(bf.isStaticField() && !fieldList.contains(bf)) {
                    fieldList.add(bf);
                } 
            }
        }
        if(baseInterfacesObject != null) {
            for(ByteCodeClass baseInterface : baseInterfacesObject) {
                baseInterface.buildStaticFieldList(fieldList, false);
            }
        }
        if(baseClassObject != null) {
            baseClassObject.buildStaticFieldList(fieldList, false);
        }        
        return fieldList;
    } 
    
    private void addFields(StringBuilder b) {
        if(baseClassObject != null) {
            baseClassObject.addFields(b);
        }
        for(ByteCodeField bf : fields) {
            if(!bf.isStaticField()) {
                b.append("    ");
                b.append(bf.getCDefinition());
                b.append(" ");
                b.append(clsName);
                b.append("_");
                b.append(bf.getFieldName());
                b.append(";\n");
            } 
        }
    }
    
    public String generateCHeader() {
        StringBuilder b = new StringBuilder();
        b.append("#ifndef __");
        b.append(clsName.toUpperCase());
        b.append("__\n");
        b.append("#define __");
        b.append(clsName.toUpperCase());
        b.append("__\n\n");

        b.append("#include \"cn1_globals.h\"\n");
        
        for(String s : exportsClassesInterfaces) {
            /*
            if(s.startsWith("java_lang_annotation") || s.startsWith("java_lang_Deprecated") || 
                    s.startsWith("java_lang_Override") || s.startsWith("java_lang_SuppressWarnings")) {
                continue;
            }
            */
            //if (isAnnotation) {
            //    continue;
            //}
            b.append("#include \"");
            b.append(s);
            b.append(".h\"\n");
        }

        b.append("extern struct clazz class__");
        b.append(clsName);
        b.append(";\n");

        if(arrayTypes.contains("1_" + clsName) || arrayTypes.contains("2_" + clsName) || arrayTypes.contains("3_" + clsName)) {
            b.append("extern struct clazz class_array1__");
            b.append(clsName);
            b.append(";\n");
        }

        if(arrayTypes.contains("2_" + clsName) || arrayTypes.contains("3_" + clsName)) {
            b.append("extern struct clazz class_array2__");
            b.append(clsName);
            b.append(";\n");
        }

        if(arrayTypes.contains("3_" + clsName)) {
            b.append("extern struct clazz class_array3__");
            b.append(clsName);
            b.append(";\n");
        }

        if(!isInterface) {
            b.append("extern void __INIT_VTABLE_");
            b.append(clsName);
            b.append("(CODENAME_ONE_THREAD_STATE, void** vtable);\n");
        }

        b.append("extern void __STATIC_INITIALIZER_");
        b.append(clsName);
        b.append("(CODENAME_ONE_THREAD_STATE);\n");
        
        b.append("extern void __FINALIZER_");
        b.append(clsName);
        b.append("(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT objToDelete);\n");

        b.append("extern void __GC_MARK_");
        b.append(clsName);
        b.append("(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT objToMark, JAVA_BOOLEAN force);\n");
        
        if(!isInterface && !isAbstract) {
            b.append("extern JAVA_OBJECT __NEW_");
            b.append(clsName);
            b.append("(CODENAME_ONE_THREAD_STATE);\n");

            if(hasDefaultConstructor()) {
                b.append("extern JAVA_OBJECT __NEW_INSTANCE_");
                b.append(clsName);
                b.append("(CODENAME_ONE_THREAD_STATE);\n");
            }
        }
        
        if (isEnum) {
            b.append("extern JAVA_OBJECT __VALUE_OF_").append(clsName).append("(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT value);\n");
        }
                
        if(arrayTypes.contains("1_" + clsName)) {
            b.append("extern JAVA_OBJECT __NEW_ARRAY_");
            b.append(clsName);
            b.append("(CODENAME_ONE_THREAD_STATE, JAVA_INT size);\n");
        }
        
        appendMethodsToHeader(b);
        
        if(baseClassObject != null) {
            // append super stub
            List bm = new ArrayList(methods);
            appendSuperStubHeader(b, bm, baseClassObject);
        }
        
        for(BytecodeMethod m : virtualMethodList) {
            if(m.isVirtualOverriden()) {
                b.append("#define virtual_");
                b.append(m.getClsName());
                b.append("_");
                b.append(m.getCMethodName());
                b.append("__");
                m.appendArgumentTypes(b);
                b.append(" ");
                b.append(m.getClsName());
                b.append("_");
                b.append(m.getCMethodName());
                b.append("__");
                m.appendArgumentTypes(b);
                b.append("\n");
            } else {
                m.appendVirtualMethodHeader(b, clsName);
            }
        }

        // static fields for the class
        for(ByteCodeField bf : staticFieldList) {
            if(bf.isStaticField()) {
                if(bf.getClsName().equals(clsName)) {
                    b.append("extern ");
                    b.append(bf.getCDefinition());
                    b.append(" get_static_");
                    b.append(clsName);
                    b.append("_");
                    b.append(bf.getFieldName());
                    b.append("();\n");
                    if(!(bf.isFinal() && bf.getValue() != null && !writableFields.contains(bf.getFieldName()))) {
                        b.append("extern ");
                        b.append(bf.getCDefinition());
                        b.append(" STATIC_FIELD_");
                        b.append(clsName);
                        b.append("_");
                        b.append(bf.getFieldName());
                        b.append(";\n");

                        b.append("extern void");
                        b.append(" set_static_");
                        b.append(clsName);
                        b.append("_");
                        b.append(bf.getFieldName());
                        b.append("(CODENAME_ONE_THREAD_STATE, ");
                        b.append(bf.getCDefinition());
                        b.append(" v);\n");
                    }
                } else {
                    b.append("#define get_static_");
                    b.append(clsName);
                    b.append("_");
                    b.append(bf.getFieldName());
                    b.append("(threadStateArgument) get_static_");
                    b.append(bf.getClsName());
                    b.append("_");
                    b.append(bf.getFieldName());
                    b.append("(threadStateArgument)\n");

                    b.append("#define set_static_");
                    b.append(clsName);
                    b.append("_");
                    b.append(bf.getFieldName());
                    b.append("(threadStateArgument, valueArgument) set_static_");
                    b.append(bf.getClsName());
                    b.append("_");
                    b.append(bf.getFieldName());
                    b.append("(threadStateArgument, valueArgument)\n");
                }
            }
        }

        for(ByteCodeField fld : fullFieldList) {
            b.append(fld.getCDefinition());
            b.append(" get_field_");
            b.append(clsName);
            b.append("_");
            b.append(fld.getFieldName());
            b.append("(JAVA_OBJECT t);\n");

            b.append("void set_field_");
            b.append(clsName);
            b.append("_");
            b.append(fld.getFieldName());
            b.append("(CODENAME_ONE_THREAD_STATE, ");
            b.append(fld.getCDefinition());
            b.append(" __cn1Val, JAVA_OBJECT __cn1T);\n");
        }
        
        b.append("\n\n");

        // object struct contains instace field variables
        b.append("struct obj__");
        b.append(clsName);
        b.append(" {\n");
        // reference to the class, reference counter for the arc portion of the GC
        // and a mutex for synchronization code
        b.append("    DEBUG_GC_VARIABLES\n    struct clazz *__codenameOneParentClsReference;\n");
        b.append("    int __codenameOneReferenceCount;\n");
        b.append("    void* __codenameOneThreadData;\n");
        b.append("    int __codenameOneGcMark;\n");
        b.append("    void* __ownerThread;\n");
        b.append("    int __heapPosition;\n");

        
        addFields(b);
        
        b.append("};\n\n");
                     
        
        b.append("\n\n#endif //__");
        b.append(clsName.toUpperCase());
        b.append("__\n");
        return b.toString();
    }

    private void appendMethodsToHeader(StringBuilder b) {        
        for(BytecodeMethod m : methods) {
            m.appendMethodHeader(b);
            
            /*if(!m.isForceVirtual() && m.isVirtualBlockedDueToFinal() && !m.isVirtualOverriden()) {
                b.append("#define virtual_");
                b.append(clsName);
                b.append("_");
                b.append(m.getMethodName());
                b.append("__");
                m.appendArgumentTypes(b);
                b.append(" ");
                b.append(m.getClsName());
                b.append("_");
                b.append(m.getMethodName());
                b.append("__");
                m.appendArgumentTypes(b);
                b.append("\n");
            }*/
        }
        
        /*if(baseClassObject != null) {
            baseClassObject.appendVirtualBlockedMethodsToHeader(b, clsName);
        }*/
    }

    /*private void appendVirtualBlockedMethodsToHeader(StringBuilder b, String clsName) {        
        for(BytecodeMethod m : methods) {
            if(m.isVirtualBlockedDueToFinal() && !m.isVirtualOverriden()) {
                b.append("#define virtual_");
                b.append(clsName);
                b.append("_");
                b.append(m.getMethodName());
                b.append("__");
                m.appendArgumentTypes(b);
                b.append(" ");
                b.append(m.getClsName());
                b.append("_");
                b.append(m.getMethodName());
                b.append("__");
                m.appendArgumentTypes(b);
                b.append("\n");
            }
        }
        if(baseClassObject != null) {
            baseClassObject.appendVirtualBlockedMethodsToHeader(b, clsName);
        }
    }*/

    
    /**
     * @param baseClass the baseClass to set
     */
    public void setBaseClass(String baseClass) {
        this.baseClass = baseClass;
        if(baseClass != null) {
            String b = baseClass.replace('/', '_').replace('$', '_');
            if(!dependsClassesInterfaces.contains(b)) {
                dependsClassesInterfaces.add(b);
            }
            exportsClassesInterfaces.add(b);
        }
    }
    
    public void setBaseInterfaces(String[] interfaces) {
        baseInterfaces = Arrays.asList(interfaces);
        if(baseInterfaces != null) {
            for(String s : interfaces) {
                s = s.replace('/', '_').replace('$', '_');
                if(!dependsClassesInterfaces.contains(s)) {
                    dependsClassesInterfaces.add(s);
                }
                exportsClassesInterfaces.add(s);
            }
        }
    }

    /**
     * @return the clsName
     */
    public String getClsName() {
        return clsName;
    }

    /**
     * @return the baseClassObject
     */
    public ByteCodeClass getBaseClassObject() {
        return baseClassObject;
    }

    /**
     * @param baseClassObject the baseClassObject to set
     */
    public void setBaseClassObject(ByteCodeClass baseClassObject) {
        this.baseClassObject = baseClassObject;
    }

    /**
     * @return the baseInterfacesObject
     */
    public List getBaseInterfacesObject() {
        return baseInterfacesObject;
    }

    /**
     * @param baseInterfacesObject the baseInterfacesObject to set
     */
    public void setBaseInterfacesObject(List baseInterfacesObject) {
        this.baseInterfacesObject = baseInterfacesObject;
    }

    /**
     * @return the baseInterfaces
     */
    public List getBaseInterfaces() {
        return baseInterfaces;
    }
    
    public void fillVirtualMethodTable(List virtualMethods) {
        fillVirtualMethodTable(virtualMethods, true);
    }
    
    private void fillVirtualMethodTable(List virtualMethods, boolean replace) {
        if(baseClassObject != null) {
            baseClassObject.fillVirtualMethodTable(virtualMethods, true);
        }
        if(baseInterfacesObject != null) {
            for(ByteCodeClass bc : baseInterfacesObject) {
                bc.fillVirtualMethodTable(virtualMethods, false);
            }
        }
        for(BytecodeMethod bm : methods) {
            if (bm.isEliminated()) continue;
            if(bm.canBeVirtual()) {
                int offset = virtualMethods.indexOf(bm);
                if(offset < 0) {
                    virtualMethods.add(bm);
                    if(isInterface) {
                        bm.setForceVirtual(true);
                    }
                } else {
                    if(replace) {
                        virtualMethods.set(offset, bm);
                        if(isInterface) {
                            bm.setForceVirtual(true);
                        }
                    }
                }
            } else {
                
            } 
        }
    }
    
    /*private boolean isMethodIn(ByteCodeClass bc, BytecodeMethod bm) {
        if(methods.contains(bm)) {
            return true;
        }
        if(baseInterfacesObject != null) {
            for(ByteCodeClass cc : baseInterfacesObject) {
                if(isMethodIn(cc, bm)) {
                    return true;
                }
            }
        }
        if(baseClassObject != null) {
            return isMethodIn(baseClassObject, bm);
        }
        return false;
    }*/

    /**
     * @return the baseClass
     */
    public String getBaseClass() {
        return baseClass;
    }

    public void setSourceFile(String sourceFile) {
        this.sourceFile = sourceFile;
    } 

    /**
     * @return the classOffset
     */
    public int getClassOffset() {
        return classOffset;
    }

    /**
     * @param classOffset the classOffset to set
     */
    public void setClassOffset(int classOffset) {
        this.classOffset = classOffset;
    }
    
    public int updateMethodOffsets(int initial) {
        for(BytecodeMethod m : methods) {
            m.setMethodOffset(initial);
            initial++;
        }
        return initial;
    }
    
    public int getMethodCountIncludingBase() {
        int size = methods.size();
        if(baseClassObject != null) {
            size += baseClassObject.getMethodCountIncludingBase();
        }
        if(baseInterfacesObject != null) {
            for(ByteCodeClass bo : baseInterfacesObject) {
                size += bo.getMethodCountIncludingBase();
            }
        }
        return size;
    }
    
    public List getMethods() {
        return methods;
    }

    public List getFields() {
        return fields;
    }

    /**
     * @return the isInterface
     */
    public boolean isIsInterface() {
        return isInterface;
    }

    /**
     * @param isInterface the isInterface to set
     */
    public void setIsInterface(boolean isInterface) {
        this.isInterface = isInterface;
    }
    
    public void setIsUnitTest(boolean isUnitTest) {
        this.isUnitTest = isUnitTest;
    }

    /**
     * @return the isAbstract
     */
    public boolean isIsAbstract() {
        return isAbstract;
    }

    /**
     * @param isAbstract the isAbstract to set
     */
    public void setIsAbstract(boolean isAbstract) {
        this.isAbstract = isAbstract;
    }
    
    private void appendClassVFunctions(StringBuilder b) {
        // special case, class has no Class object within it so no real virtual functions
        b.append("JAVA_BOOLEAN virtual_java_lang_Class_equals___java_lang_Object_R_boolean(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject, JAVA_OBJECT __cn1Arg1) {\n" +
            "    return java_lang_Object_equals___java_lang_Object_R_boolean(threadStateData, __cn1ThisObject, __cn1Arg1);\n" +
            "}\n" +
            "\n" +
            "\n" +
            "JAVA_OBJECT virtual_java_lang_Class_getClass___R_java_lang_Class(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject) {\n" +
            "    return java_lang_Object_getClass___R_java_lang_Class(threadStateData, __cn1ThisObject);\n" +
            "}\n" +
            "\n" +
            "\n" +
            "JAVA_INT virtual_java_lang_Class_hashCode___R_int(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject) {\n" +
            "    return java_lang_Object_hashCode___R_int(threadStateData, __cn1ThisObject);\n" +
            "}\n" +
            "\n" +
            "\n" +
            "JAVA_VOID virtual_java_lang_Class_notify__(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject) {\n" +
            "    java_lang_Object_notify__(threadStateData, __cn1ThisObject);\n" +
            "}\n" +
            "\n" +
            "JAVA_VOID virtual_java_lang_Class_notifyAll__(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject) {\n" +
            "    java_lang_Object_notifyAll__(threadStateData, __cn1ThisObject);\n" +
            "}\n" +
            "\n" +
            "\n" +
            "JAVA_OBJECT virtual_java_lang_Class_toString___R_java_lang_String(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject) {\n" +
            "    return java_lang_Object_toString___R_java_lang_String(threadStateData, __cn1ThisObject);\n" +
            "}\n" +
            "\n" +
            "\n" +
            "JAVA_VOID virtual_java_lang_Class_wait__(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject) {\n" +
            "    java_lang_Object_wait__(threadStateData, __cn1ThisObject);\n" +
            "}\n" +
            "\n" +
            "\n" +
            "JAVA_VOID virtual_java_lang_Class_wait___long(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject, JAVA_LONG __cn1Arg1) {\n" +
            "    java_lang_Object_wait___long(threadStateData, __cn1ThisObject, __cn1Arg1);\n" +
            "}\n" +
            "\n" +
            "\n" +
            "JAVA_VOID virtual_java_lang_Class_wait___long_int(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject, JAVA_LONG __cn1Arg1, JAVA_INT __cn1Arg2) {\n" +
            "    java_lang_Object_wait___long_int(threadStateData, __cn1ThisObject, __cn1Arg1, __cn1Arg2);\n" +
            "}\n");
    }

    /**
     * @return the finalClass
     */
    public boolean isFinalClass() {
        return finalClass;
    }

    /**
     * @param finalClass the finalClass to set
     */
    public void setFinalClass(boolean finalClass) {
        this.finalClass = finalClass;
    }
    
    public void appendStaticFieldsExtern(StringBuilder b) {
        for(ByteCodeField bf : fields) {
            if(bf.isStaticField() && bf.isObjectType() && !bf.shouldRemoveFromHeapCollection()) {
                b.append("extern ");
                b.append(bf.getCDefinition());
                b.append(" STATIC_FIELD_");
                b.append(clsName);
                b.append("_");
                b.append(bf.getFieldName());
                b.append(";\n");
            }
        }
    }

    private boolean isTrulyFinal(ByteCodeField bf) {
        if(bf.isFinal()) {
            if(bf.isObjectType()) {
                if(bf.getType() != null) {
                    return bf.getType().endsWith("String");
                }
            } else {
                return true;
            }
        }
        return false;
    }
    
    public void appendStaticFieldsMark(StringBuilder b) {
        for(ByteCodeField bf : fields) {
            if(bf.isStaticField() && bf.isObjectType() && !bf.shouldRemoveFromHeapCollection()) {
                b.append("    gcMarkObject(threadStateData, STATIC_FIELD_");
                b.append(clsName);
                b.append("_");
                b.append(bf.getFieldName());
                b.append(", JAVA_TRUE);\n");
            }
        }
    }

    /**
     * 3-state variable to keep track of whether the class is used by native sources.
     * 3 states, because we need to know if it is unknown.
     */
    private UsedByNativeResult usedByNative = UsedByNativeResult.Unknown;


    /**
     * Sets usedByNative flag in this class.
     * @param usedByNative True if this class is used by native sources.
     */
    public void setUsedByNative(boolean usedByNative) {
        this.usedByNative = usedByNative ? UsedByNativeResult.Used : UsedByNativeResult.Unused;
    }

    /**
     * Enum to track possible values of {@link #usedByNative}.
     */
    public static enum UsedByNativeResult {
        /**
         * The class is used by native sources.
         */
        Used,
        /**
         * The class is not used by native sources.
         */
        Unused,
        /**
         * We don't yet know if this class is used by native sources.
         */
        Unknown;
    }


    /**
     * Check whether this class is used by native sources.
     * @return
     */
    public UsedByNativeResult getUsedByNative() {
       return usedByNative;
    }

    /**
     * Calculates whether this class is used in any of the native sources.
     * @param nativeSources The native sources to check.
     * @see #getUsedByNative() 
     * @see #setUsedByNative(boolean)
     */
    public void calcUsedByNative(String[] nativeSources) {
        for (BytecodeMethod m : methods) {
            if (usedByNative != UsedByNativeResult.Unknown) {
                return;
            }
            m.isMethodUsedByNative(nativeSources, this);
        }
    }

    boolean isUnitTest() {
        return isUnitTest;
    }

    void setIsEnum(boolean b) {
        this.isEnum = b;
    }

    private String getArrayClazz(int dim) {
        if((arrayTypes.contains(dim + "_" + clsName) )) {
            return "&class_array"+dim+"__"+clsName;
        } else {
            return "0";
        }
    }

    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy