/* * @(#) $(JCGO)/jtrsrc/com/ivmaisoft/jcgo/ClassDefinition.java -- * a part of JCGO translator. ** * Project: JCGO (http://www.ivmaisoft.com/jcgo/) * Copyright (C) 2001-2012 Ivan Maidanski <ivmai@mail.ru> * All rights reserved. */ /* * This 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, or (at your option) * any later version. ** * This software 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 (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ package com.ivmaisoft.jcgo; import java.util.Enumeration; /** * Class type definition. */ final class ClassDefinition extends ExpressionType { static final int ARR_STORE_EXC = 0x1; static final int CLASS_CAST_EXC = 0x2; static final int INDEX_OUT_EXC = 0x4; static final int NULL_PTR_EXC = 0x8; static final int MAX_DIMS = (new ConstValue(16)).getIntValue(); private int type = Type.CLASSINTERFACE; private String name; private String cname; private String jniname; private String id; private String shortname; private String signName; private ClassDefinition superClass; private int modifiers; private final ObjVector arrayClasses = new ObjVector(); private ExactClassType exactClassType; private Context context; private OutputContext outputContext; private boolean predefining; private boolean parsed; private boolean isDefined; private boolean used; private boolean forArraysUsed; private boolean vTableUsed; private boolean headerWritten; private boolean addedToHeader; private boolean finished; private boolean hasInstances; private boolean hasExactInstance; private boolean addedToSuper; private boolean insideStaticMethod; private boolean needStaticInitPass; private boolean markIfDefined; private boolean markIfHasInstances; private boolean markIfImplemented; private boolean checkMarkDone; private final ObjQueue subclasses = new ObjQueue(); private ObjQueue implementedBy; private Term extendsTerm; private Term ifaceListTerm; private Term outerMethodDefnTerm; private ClassDefinition outerClass; private VariableDefinition outerThisRef; private LeftBrace outerScope; private ObjVector outerLocals; private ObjHashtable outerFields; private Term constrParamList; private ExpressionType constrSuperType; private final ObjQueue interfaceClasses = new ObjQueue(); private final ObjQueue specifiedInterfaces = new ObjQueue(); private Term classbody; private OrderedMap fieldDictionary; private OrderedMap methodDictionary; private OrderedMap usedMethodSigns; private boolean mayContainClinit; private InitializerPart classInitializers; private InitializerPart instanceInitializers; private boolean leaksDiscoverProcessing; private boolean leaksDiscoverDone; private boolean hasInstanceInitLeaks; private boolean isInitThisStackObjVolatile; private MethodDefinition basicConstructor; private ClassDefinition fromClass; private int dummyEntryCnt; private int literNum; private int scopesNum = 1; private int anonymousNum; private ObjVector methodTableSigns; private ObjQueue arrpool; private ObjQueue strpool; private MethodTraceInfo clinitTraceInfo; private OrderedMap classInitDepend; private ObjHashSet fieldCNames; private ObjHashSet reflectedFieldNames; private ObjHashtable reflectedMethods; private ObjQueue inheritedReflectedSigns; private ObjQueue inheritedReflFieldNames; private ObjQueue mproxypool; private MethodDefinition clinitForStaticField; private ClassDefinition helperClass; private VariableDefinition lastObjectRefField; private OrderedMap inclassCalls; ObjHashtable knownMethodInfos; int nextClinitLabel; int nextInitZLabel; private boolean definePassOneDone; ClassDefinition(String name) { this.name = name; NameMapper nameMapper = Main.dict.nameMapper; cname = nameMapper.classToCName(name); jniname = nameMapper.nameToJniName(name); signName = Type.sig[Type.CLASSINTERFACE] + nameMapper.classToSign(name); shortname = nameMapper.cnameToShort(cname); outputContext = new OutputContext(shortname); fieldCNames = new ObjHashSet(); } ClassDefinition(int arrtype) { name = Type.sig[arrtype]; cname = Type.cName[arrtype]; used = true; hasInstances = true; type = arrtype; vTableUsed = true; } ClassDefinition(int type, Context c) { this.type = type; name = Type.name[type]; cname = Type.cName[type]; signName = Type.sig[type]; used = true; hasInstances = true; vTableUsed = true; definePass0(c, AccModifier.PUBLIC | AccModifier.FINAL, name, Empty.newTerm(), Empty.newTerm(), Empty.newTerm(), false); } ClassDefinition signatureClass() { return this; } int signatureDimensions() { return 0; } int objectSize() { return type; } ExpressionType indirectedType() { return null; } ClassDefinition receiverClass() { return this; } Context passOneContext() { predefineClass(null); Term.assertCond(context != null); return context; } String vTableCName() { Term.assertCond(used && vTableUsed); return cname + "_methods"; } String cNewObjectCode() { return "(" + castName() + ")jcgo_newObject((jvtable)&" + vTableCName() + ")"; } static String arrayVTableCName(int type, int dims) { Term.assertCond((type == Type.VOID && dims >= 0) || (type >= Type.BOOLEAN && type <= Type.DOUBLE && dims == 0)); return Type.cName[Type.CLASSINTERFACE + type] + (dims > 0 ? Integer.toString(dims + 1) : "") + "_methods"; } String routineNameOf(String csign) { Term.assertCond(used); return cname + "__" + csign; } String csign() { Term.assertCond(signName != null); return signName; } String jniClassName() { Term.assertCond(jniname != null); return jniname; } ExpressionType asExprType(int dims) { if (dims == 0) return this; for (int cnt = dims - arrayClasses.size(); cnt > 0; cnt--) { arrayClasses.addElement(null); } ExpressionType exprType = (ExpressionType) arrayClasses .elementAt(dims - 1); if (exprType == null) { exprType = new ClassDefnWithDims(this, dims); arrayClasses.setElementAt(exprType, dims - 1); } return exprType; } ExpressionType asExactClassType() { if (isFinal()) return this; if (exactClassType == null) { exactClassType = new ExactClassType(this); } return exactClassType; } ExpressionType mapToPrimType() { if (name.equals(Names.JAVA_LANG_BOOLEAN)) return Main.dict.classTable[Type.BOOLEAN]; if (name.equals(Names.JAVA_LANG_BYTE)) return Main.dict.classTable[Type.BYTE]; if (name.equals(Names.JAVA_LANG_CHARACTER)) return Main.dict.classTable[Type.CHAR]; if (name.equals(Names.JAVA_LANG_SHORT)) return Main.dict.classTable[Type.SHORT]; if (name.equals(Names.JAVA_LANG_INTEGER)) return Main.dict.classTable[Type.INT]; if (name.equals(Names.JAVA_LANG_LONG)) return Main.dict.classTable[Type.LONG]; if (name.equals(Names.JAVA_LANG_FLOAT)) return Main.dict.classTable[Type.FLOAT]; if (name.equals(Names.JAVA_LANG_DOUBLE)) return Main.dict.classTable[Type.DOUBLE]; return this; } boolean hasInstantatedSubclasses(boolean allowArrays) { define(null); if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if ((cd.hasInstances || (allowArrays && (cd.forArraysUsed || cd.vTableUsed))) && cd.used) return true; } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if ((cd.hasInstances || (allowArrays && (cd.forArraysUsed || cd.vTableUsed))) && cd.used) return true; } return false; } int getSubclassDepth(ClassDefinition aclass, ClassDefinition forClass) { if (aclass != this) { int depth = 0; ClassDefinition cd = this; do { depth++; cd = cd.superClass(forClass); if (cd == null) break; if (cd == aclass) return depth; } while (true); } return 0; } int getImplementedByDepth(ClassDefinition aclass, ClassDefinition forClass) { int depth = 0; while (aclass != null) { depth++; if (aclass.doesImplement(this, forClass)) return depth; aclass = aclass.superClass(); } return 0; } boolean doesImplement(ClassDefinition anInterface, ClassDefinition forClass) { return interfaceClasses(forClass).contains(anInterface); } boolean isAssignableFrom(ClassDefinition cd, int dimsDiff, ClassDefinition forClass) { if (dimsDiff != 0) return dimsDiff < 0 && isObjectOrCloneable(); if (cd == this) return true; if (cd.signName == null) return isObjectOrCloneable(); do { if (cd.doesImplement(this, forClass) || (cd = cd.superClass(forClass)) == this) return true; } while (cd != null); return false; } static boolean isAssignableFrom(ExpressionType exprType1, ExpressionType exprType2, ClassDefinition forClass) { return exprType1 == exprType2 || exprType2.objectSize() == Type.NULLREF || exprType1.signatureClass().isAssignableFrom( exprType2.signatureClass(), exprType1.signatureDimensions() - exprType2.signatureDimensions(), forClass); } static ClassDefinition maxSuperclassOf(ClassDefinition cd1, ClassDefinition cd2, ClassDefinition forClass) { if (cd1 != cd2) { if (cd2.type != Type.CLASSINTERFACE) return cd1; if (cd1.type != Type.CLASSINTERFACE) return cd2; if (cd1.isInterface() && cd2.isInterface()) { if (cd1.doesImplement(cd2, forClass)) return cd2; if (cd2.doesImplement(cd1, forClass)) return cd1; Enumeration en = cd1.specifiedInterfaces.elements(); while (en.hasMoreElements()) { ClassDefinition iface1 = (ClassDefinition) en.nextElement(); Enumeration en2 = cd2.specifiedInterfaces.elements(); while (en2.hasMoreElements()) { ClassDefinition cd = maxSuperclassOf(iface1, (ClassDefinition) en2.nextElement(), forClass); if (cd.superClass(forClass) != null) return cd; } } cd1 = cd1.superClass(null); } else { do { if (cd1.isAssignableFrom(cd2, 0, forClass)) break; if (cd2.isAssignableFrom(cd1, 0, forClass)) { cd1 = cd2; break; } cd1 = cd1.superClass(forClass); cd2 = cd2.superClass(forClass); } while (cd1 != cd2); } } return cd1; } static ExpressionType maxCommonExprOf(ExpressionType exprType1, ExpressionType exprType2, ClassDefinition forClass) { if (exprType1 == exprType2 || exprType2.objectSize() == Type.NULLREF) return exprType1; if (exprType1.objectSize() == Type.NULLREF) return exprType2; int dims1 = exprType1.signatureDimensions(); int dims2 = exprType2.signatureDimensions(); return (dims1 != dims2 ? Main.dict.get(Names.JAVA_LANG_OBJECT) : maxSuperclassOf(exprType1.signatureClass(), exprType2.signatureClass(), forClass)) .asExprType(dims1 < dims2 ? dims1 : dims2); } boolean isStringOrNull() { return type == Type.NULLREF || Names.JAVA_LANG_STRING.equals(name); } boolean isThrowable() { ClassDefinition cd = this; while (cd.superClass() != null) { if (cd.name.equals(Names.JAVA_LANG_THROWABLE)) return true; cd = cd.superClass; } return false; } boolean isUncheckedException(ClassDefinition forClass) { ClassDefinition cd = this; while (cd.superClass(forClass) != null) { if (cd.name.equals(Names.JAVA_LANG_ERROR) || cd.name.equals(Names.JAVA_LANG_RUNTIMEEXCEPTION)) return true; cd = cd.superClass; } return false; } int getVMExcMask() { return name.equals(Names.JAVA_LANG_THROWABLE) || name.equals(Names.JAVA_LANG_EXCEPTION) || name.equals(Names.JAVA_LANG_RUNTIMEEXCEPTION) ? ARR_STORE_EXC | CLASS_CAST_EXC | INDEX_OUT_EXC | NULL_PTR_EXC : name.equals(Names.JAVA_LANG_ARRAYSTOREEXCEPTION) ? ARR_STORE_EXC : name.equals(Names.JAVA_LANG_CLASSCASTEXCEPTION) ? CLASS_CAST_EXC : name.equals(Names.JAVA_LANG_INDEXOUTOFBOUNDSEXCEPTION) || name.equals(Names.JAVA_LANG_ARRAYINDEXOUTOFBOUNDSEXCEPTION) ? INDEX_OUT_EXC : name.equals(Names.JAVA_LANG_NULLPOINTEREXCEPTION) ? NULL_PTR_EXC : 0; } String getJniName() { return type != Type.CLASSINTERFACE ? Type.jniName[type] : name .equals(Names.JAVA_LANG_CLASS) ? "jclass" : name .equals(Names.JAVA_LANG_STRING) ? "jstring" : !isInterface() && isThrowable() ? "jthrowable" : Type.jniName[Type.CLASSINTERFACE]; } boolean isInterface() { predefineClassNoMark(); return implementedBy != null; } boolean isPublic() { predefineClassNoMark(); return (modifiers & AccModifier.PUBLIC) != 0; } boolean isStrictFP() { predefineClassNoMark(); return (modifiers & AccModifier.STRICT) != 0; } boolean isAbstractOrInterface() { predefineClassNoMark(); return (modifiers & (AccModifier.ABSTRACT | AccModifier.INTERFACE)) != 0; } boolean isNotInstantated() { return isAbstractOrInterface() || !hasInstances; } boolean hasInstances() { return hasInstances; } boolean hasRealInstances() { return hasInstances && used; } void setHasInstances() { if (!hasInstances) { if (markIfHasInstances) { markUsed(); } hasInstances = true; checkMethodsMarkedUsed(); if (used) { markFieldInitializers(false); } Enumeration en2 = specifiedInterfaces.elements(); while (en2.hasMoreElements()) { ((ClassDefinition) en2.nextElement()).setHasInstances(); } if (superClass != null) { superClass.setHasInstances(); } setVTableUsed(false); } } boolean hasExactInstance() { return hasExactInstance; } void setHasExactInstance(boolean value) { if (!hasExactInstance && !isAbstractOrInterface()) { hasExactInstance = value; ClassDefinition cd = this; do { cd.checkMethodsMarkedUsed(); } while ((cd = cd.superClass) != null); } } private void checkMethodsMarkedUsed() { Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { getMethodNoInheritance((String) en.nextElement()).checkMarkedUsed(); } } boolean overriddenByAllUsed(MethodDefinition md) { String sigString = md.methodSignature().signatureString(); String pkgName = md.isProtectedOrPublic() ? null : getPackageName(); Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used || cd.hasExactInstance) { MethodDefinition md2 = cd.getMethodNoInheritance(sigString); if (md2 != null ? md2.isClassMethod() || (pkgName != null && !pkgName.equals(cd .getPackageName())) : cd.hasExactInstance || !cd.overriddenByAllUsed(md)) return false; } } return true; } void setVTableUsed(boolean markClassUsed) { if (markClassUsed) { markUsed(); } if (!vTableUsed) { Term.assertCond(!finished); vTableUsed = true; ClassDefinition sc = superClass(); if (sc != null && !sc.vTableUsed && !isInterface()) { do { Term.assertCond(!sc.finished); sc.vTableUsed = true; } while ((sc = sc.superClass(this)) != null && !sc.vTableUsed); } } } boolean isStaticClass() { predefineClassNoMark(); return (modifiers & AccModifier.STATIC) != 0 || outerClass == null || insideStaticMethod; } boolean isFinal() { predefineClassNoMark(); return (modifiers & AccModifier.FINAL) != 0; } ClassDefinition outerClass() { predefineClassNoMark(); return outerClass; } private ClassDefinition topOuterClass() { ClassDefinition cd = this; ClassDefinition aclass; while ((aclass = cd.outerClass()) != null) { cd = aclass; } return cd; } LeftBrace outerScope() { predefineClassNoMark(); return outerScope; } ObjVector outerLocals(ClassDefinition forClass) { predefineClass(forClass); Term.assertCond(outerLocals != null); return outerLocals; } VariableDefinition outerThisRef() { define(null); return outerThisRef; } boolean hasConstrSuperExpr() { return constrSuperType != null; } void setConstrSuperExpr(ExpressionType exprType0, MethodDefinition md, int skipHeadCnt, int skipTailCnt) { constrSuperType = exprType0; constrParamList = md.copyParamList(skipHeadCnt, skipTailCnt); } Term constrMakeArgumentList() { Term.assertCond(constrParamList != null); return constrParamList.makeArgumentList(); } MethodDefinition clinitForStaticField() { if (clinitForStaticField == null) { clinitForStaticField = new MethodDefinition(this); } return clinitForStaticField; } String nextLiteralSuffix() { return Integer.toString(++literNum) + "_" + shortname(); } String nextAnonymousId() { return Integer.toString(++anonymousNum); } String nextLocalClassName(String ident) { ClassDefinition cd = topOuterClass(); String nextName; do { nextName = cd.name + "$" + Integer.toString(cd.scopesNum) + ident; if (!Main.dict.exists(nextName)) break; cd.scopesNum++; } while (true); return nextName; } String resolveInnerClass(String className, boolean checkFields, ClassDefinition forClass) { int i = className.lastIndexOf('.'); ClassDefinition aclass = this; if (i >= 0) { String qualified = resolveInnerClass(className.substring(0, i), checkFields, forClass); if (qualified == null) return null; aclass = Main.dict.get(qualified); } String fieldName = className.substring(i + 1); String innerName = "$" + fieldName; do { String qualified = aclass.name + innerName; aclass.predefineClassNoMark(); if (Main.dict.exists(qualified)) return qualified; if (checkFields) { aclass.define(forClass); if (aclass.fieldDictionary.get(fieldName) != null) return ""; Enumeration en = aclass.interfaceClasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); cd.define(forClass); if (cd.fieldDictionary.get(fieldName) != null) return ""; } } Enumeration en = aclass.interfaceClasses(forClass).elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); qualified = cd.name + innerName; cd.predefineClassNoMark(); if (Main.dict.exists(qualified)) return qualified; } } while ((aclass = aclass.superClass()) != null); return null; } String name() { return name; } String getPackageName() { int i = name.lastIndexOf('.'); return i > 0 ? name.substring(0, i) : "package"; } String id() { return id; } String castName() { ClassDefinition cd = this; do { if (cd.used) return cd.cname; } while ((cd = cd.superClass) != null); return Main.dict.get(Names.JAVA_LANG_OBJECT).cname; } String getClassRefStr(boolean isArray) { Term.assertCond(used); setVTableUsed(false); return type != Type.CLASSINTERFACE ? "JCGO_CORECLASS_FOR(OBJT_" + (isArray ? "jarray+OBJT_" : "") + cname + ")" : "JCGO_CLASSREF_OF(" + cname + "__class)"; } private String clinitCName() { Term.assertCond(used); return cname + "__class__0"; } boolean isObjectOrCloneable() { return name.equals(Names.JAVA_LANG_OBJECT) || name.equals(Names.JAVA_LANG_CLONEABLE) || name.equals(Names.JAVA_IO_SERIALIZABLE); } private void defineObjectStructure(OutputContext oc) { Term.assertCond(used); if (superClass != null && !Names.JAVA_LANG_CLASS.equals(name) && !Names.JAVA_LANG_STRING.equals(name) && !Names.JAVA_LANG_THROWABLE.equals(name)) { oc.hPrint("typedef struct "); oc.hPrint(cname); oc.hPrint("_s *"); oc.hPrint(cname); oc.hPrint(";"); } } String shortname() { Term.assertCond(shortname != null); return shortname; } private int enumerateClass(OutputContext oc, int n, ObjHashSet processed) { if (type == Type.CLASSINTERFACE && processed.add(this)) { if (used) { if (!name.equals(Names.JAVA_LANG_CLASS) && !name.equals(Names.JAVA_LANG_STRING)) { if (superClass == null) { oc.addIncludeCFile(Main.dict .get(Names.JAVA_LANG_STRING).shortname()); oc.addIncludeCFile(Main.dict.get(Names.JAVA_LANG_CLASS) .shortname()); } oc.addIncludeCFile(shortname()); } defineObjectStructure(oc); oc.hPrint("#define OBJT_"); oc.hPrint(cname); oc.hPrint(" "); oc.hPrint(Integer.toString(++n)); oc.hPrint("\010"); if (superClass == null) { n = Main.dict.get(Names.JAVA_LANG_STRING).enumerateClass( oc, Main.dict.get(Names.JAVA_LANG_CLASS) .enumerateClass(oc, 63, processed), processed); } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { n = ((ClassDefinition) en.nextElement()).enumerateClass(oc, n, processed); } if (used) { oc.hPrint("#define MAXT_"); oc.hPrint(cname); oc.hPrint(" "); oc.hPrint(Integer.toString(n)); oc.hPrint("\010"); } } return n; } void produceOutputRecursive(ObjHashSet processed) { if (type == Type.CLASSINTERFACE && processed.add(this)) { if (used && !name.equals(Names.JAVA_LANG_CLASS) && !name.equals(Names.JAVA_LANG_STRING)) { if (superClass == null) { Main.dict.get(Names.JAVA_LANG_STRING).produceOutput(); Main.dict.get(Names.JAVA_LANG_CLASS).produceOutput(); } produceOutput(); } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()) .produceOutputRecursive(processed); } } } private static String[] sortStrings(String[] arr, int size) { String[] sorted = new String[size]; System.arraycopy(arr, 0, sorted, 0, size); mergeSort(arr, sorted, 0, size); return sorted; } static void mergeSort(String[] src, String[] dest, int low, int high) { int len = high - low; if (len < 7) { int i = low; while (++i < high) { for (int j = i; j > low && dest[j - 1].compareTo(dest[j]) > 0; j--) { String s = dest[j]; dest[j] = dest[j - 1]; dest[j - 1] = s; } } } else { int mid = (low + high) >>> 1; mergeSort(dest, src, low, mid); mergeSort(dest, src, mid, high); if (src[mid - 1].compareTo(src[mid]) <= 0) { System.arraycopy(src, low, dest, low, len); } else { int p = low; int q = mid; for (int i = low; i < high; i++) { dest[i] = q < high && (p >= mid || src[p].compareTo(src[q]) > 0) ? src[q++] : src[p++]; } } } } private void createSubclassList(ObjHashSet classnames) { if (type == Type.CLASSINTERFACE) { if (used && !classnames.add(name)) return; Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()) .createSubclassList(classnames); } } } private void addToHeaderFile(OutputContext oc) { if (type == Type.CLASSINTERFACE && !addedToHeader) { addedToHeader = true; if (used && !name.equals(Names.JAVA_LANG_CLASS) && !name.equals(Names.JAVA_LANG_STRING)) { if (superClass == null) { oc.addIncludeHFile(Main.dict.get(Names.JAVA_LANG_STRING) .shortname()); } oc.addIncludeHFile(shortname()); if (superClass == null) { oc.addIncludeHFile(Main.dict.get(Names.JAVA_LANG_CLASS) .shortname()); } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()).addToHeaderFile(oc); } } } void defineProxyClass(ObjVector interfaces, ClassDefinition forClass) { ClassDefinition sc = Main.dict.get(Names.JAVA_LANG_REFLECT_PROXY); sc.define(forClass); int count = interfaces.size(); int i; for (i = 0; i < count; i++) { ClassDefinition cd = (ClassDefinition) interfaces.elementAt(i); cd.define(forClass); cd.reflectMethods(null, false, null, false); if (i > 0) { Enumeration en = cd.methodDictionary().keys(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); ExpressionType minType = cd.getMethodNoInheritance( sigString).exprType(); ExpressionType maxType = minType; for (int j = 0; j < i; j++) { MethodDefinition md = ((ClassDefinition) interfaces .elementAt(j)).getMethod(sigString); if (md != null) { ExpressionType resType = md.exprType(); if (isAssignableFrom(maxType, resType, forClass)) { maxType = resType; } else if (isAssignableFrom(resType, minType, forClass)) { minType = resType; } else if (maxType == minType || !isAssignableFrom(minType, resType, forClass) || !isAssignableFrom(resType, maxType, forClass)) return; } } } } } Term ifaceListTerm = Empty.newTerm(); if (count > 0) { i = count - 1; ifaceListTerm = new ClassOrIfaceType( (ClassDefinition) interfaces.elementAt(i)); while (i-- > 0) { ifaceListTerm = new Seq(new ClassOrIfaceType( (ClassDefinition) interfaces.elementAt(i)), ifaceListTerm); } } definePass0( new Context(), AccModifier.PUBLIC | AccModifier.FINAL, (i = name.lastIndexOf('.')) >= 0 ? name.substring(i + 1) : name, new ClassOrIfaceType(sc), ifaceListTerm, Empty.newTerm(), false); define(forClass); markUsed(); Enumeration en = methodDictionary.keys(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); MethodDefinition md = getMethodNoInheritance(sigString); if (!md.isConstructor()) { MethodDefinition md2 = getOverridenMethod(sigString, md.exprType()); Term.assertCond(md2 != null); if (!md.hasSameThrows(md2)) { reflectMethodInner(md); } } } } MethodDefinition getOverridenMethod(String sigString, ExpressionType resType) { ClassDefinition cd = superClass(); MethodDefinition md; if (cd != null && (md = cd.getMethod(sigString)) != null && md.exprType() == resType) return md; Enumeration en = interfaceClasses(null).elements(); while (en.hasMoreElements()) { md = ((ClassDefinition) en.nextElement()) .getMethodNoInheritance(sigString); if (md != null && md.exprType() == resType) return md; } return null; } void setMayContainClinit() { mayContainClinit = true; } boolean isProxyClass() { return !classbody.notEmpty() && isFinal() && id.startsWith("$Proxy") && superClass == Main.dict.get(Names.JAVA_LANG_REFLECT_PROXY); } boolean defineDynamic(ClassDefinition forClass) { if (!isDefined) { Main.dict.message("Trying dynamic class: " + name); try { predefineClass(forClass); } catch (TranslateException e) { if (isDefined) throw e; Main.dict.message("Bad file ignored for class: " + name); return false; } if (outerMethodDefnTerm != null) { Term.assertCond(outerClass != null); outerClass.define(this); MethodDefinition md = outerMethodDefnTerm.superMethodCall(); Term.assertCond(md != null); md.markUsedThisOnly(); md.producePassOne(null); } define(forClass); } markUsed(); return true; } int define(ClassDefinition forClass) { if (isDefined) return -1; if (forClass == this) { forClass = null; } predefineClass(forClass); processExtends(); if (superClass != null) { superClass.define(this); } Enumeration en = ifaceListTerm.getSignature().elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()).predefineClass(this); } if (isDefined) return 1; processSuperClasses(); if (isDefined) return 1; isDefined = true; ifaceListTerm.addFieldsTo(this); definePass1(forClass); int marked = 0; if (used) { used = false; markUsed(); marked = 1; } if (outerClass != null) { outerClass.predefineClass(this); } return marked; } private boolean checkMarkIfDefined() { boolean marked = false; if (!checkMarkDone) { checkMarkDone = true; if (name.equals(Names.JAVA_LANG_CLASS) || name.equals(Names.JAVA_LANG_STRING)) { markUsed(); setHasInstances(); marked = true; } inheritMarkIfDefined(); String flags = (String) Main.dict.forcedReflectClassOrPkg .remove(name); if (flags != null || (outerMethodDefnTerm == null && (flags = pkgNeedsForcedReflection(name)) != null && !isProxyClass())) { forceReflection(flags); if (used) { marked = true; } } } return marked; } private static String pkgNeedsForcedReflection(String name) { int pos = name.lastIndexOf('.'); ObjHashtable forcedReflectClassOrPkg = Main.dict.forcedReflectClassOrPkg; if (pos < 0) return (String) forcedReflectClassOrPkg.get(""); String pkgName = name.substring(0, pos); String pkgDotStar = pkgName + ".*"; String flags = (String) forcedReflectClassOrPkg.get(pkgDotStar); if (flags == null && (flags = (String) forcedReflectClassOrPkg.remove(pkgName)) != null) { forcedReflectClassOrPkg.put(pkgDotStar, flags); } return flags; } private void forceReflection(String flags) { int reflectCtors = 0; int reflectMethods = 0; int reflectFields = 0; if (flags.length() > 0) { if (flags.equals("p")) { reflectCtors = 1; reflectMethods = 1; reflectFields = 1; } else { int pos; if ((pos = flags.indexOf('c')) < 0) { reflectCtors = -1; } else if (pos > 0 && flags.charAt(pos - 1) == 'p') { reflectCtors = 1; } if ((pos = flags.indexOf('m')) < 0) { reflectMethods = flags.indexOf('g') < 0 ? -1 : 2; } else if (pos > 0 && flags.charAt(pos - 1) == 'p') { reflectMethods = 1; } if ((pos = flags.indexOf('f')) < 0) { reflectFields = -1; } else if (pos > 0 && flags.charAt(pos - 1) == 'p') { reflectFields = 1; } } } if (reflectFields >= 0) { Enumeration en = fieldDictionary().keys(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(en.nextElement()); if (reflectFields == 0 || v.isPublic()) { reflectFieldInner(v); } } } if ((reflectCtors & reflectMethods) >= 0) { Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.isConstructor() ? reflectCtors >= 0 && (reflectCtors == 0 || md.isPublic()) : reflectMethods >= 0 && md.definingClass() == this && (reflectMethods == 0 || (md.isPublic() && (reflectMethods == 1 || md .isGetterSetter())))) reflectMethodInner(md); } } } void predefineClassNoMark() { if (!parsed && type == Type.CLASSINTERFACE) { Main.parseJavaFile(name); if (!parsed) throw new TranslateException( "File bad for class: " + name + (name.indexOf('.', 0) < 0 ? " (unnamed package)" : "")); } } void predefineClass(ClassDefinition forClass) { predefining = true; if (fromClass == null && forClass != this && type == Type.CLASSINTERFACE) { fromClass = forClass; } predefineClassNoMark(); } void definePass0(Context c, int modifiers, String id, Term extendsTerm, Term ifaceListTerm, Term classbody, boolean isInterface) { Term.assertCond(c != null); if (parsed) { classbody.fatalError(c, "Class duplicate or recursive definition: " + name); return; } parsed = true; context = c; if (type == Type.CLASSINTERFACE) { outerMethodDefnTerm = c.passZeroMethodDefnTerm; outerClass = c.currentClass; context = c.cloneForClass(this, this); } else { isDefined = true; if (type >= Type.CLASSINTERFACE) { superClass = Main.dict.get(Names.JAVA_LANG_OBJECT); definePassOneDone = true; } } if (isInterface) { implementedBy = new ObjQueue(); modifiers |= AccModifier.INTERFACE; if (outerClass != null) { modifiers |= AccModifier.STATIC; } } else if (outerClass != null && outerClass.implementedBy != null) { modifiers |= AccModifier.PUBLIC | AccModifier.STATIC; } this.modifiers = modifiers; this.id = id; this.extendsTerm = extendsTerm; this.ifaceListTerm = ifaceListTerm; this.classbody = classbody; fieldDictionary = new OrderedMap(); methodDictionary = new OrderedMap(); usedMethodSigns = new OrderedMap(); constrParamList = Empty.newTerm(); outerLocals = new ObjVector(); classbody.processPass0(context); } void processPass1(Context c) { Term.assertCond(parsed); if (outerScope != null) return; outerScope = c.localScope; if (outerScope != null) { Term.assertCond(outerClass != null); Term.assertCond(c.currentMethod != null); if (isDefined) { classbody.fatalError(c, "Local class is used outside its scope: " + name); return; } if (c.currentMethod.isClassMethod()) { insideStaticMethod = true; if (id.charAt(0) >= '0' && id.charAt(0) <= '9') { modifiers |= AccModifier.STATIC; } } outerScope.addLocalClass(this); Enumeration en = c.currentMethod.getLocalsNames(); while (en.hasMoreElements()) { VariableDefinition v = c.currentMethod.getLocalVar((String) en .nextElement()); Term.assertCond(v != null); if (v.isFinalVariable() && !v.isUnassigned()) { outerLocals.addElement(v); } } } } void changeExtendsTerm(ClassDefinition aclass, boolean hasPrimary) { Term.assertCond(parsed && !isDefined); if (hasPrimary) { extendsTerm = new ClassOrIfaceType(aclass); } if (aclass.isInterface()) { ifaceListTerm = extendsTerm; extendsTerm = Empty.newTerm(); } } private void processExtends() { if (!isDefined) { Term.assertCond(parsed); Context c = context.cloneForClass(outerClass, this); c.localScope = outerScope; if (superClass == null && !name.equals(Names.JAVA_LANG_OBJECT)) { c.typeClassDefinition = Main.dict.get(Names.JAVA_LANG_OBJECT); extendsTerm.processPass1(c); superClass = c.typeClassDefinition; } ifaceListTerm.processPass1(c); } } private void processSuperClasses() { Term.assertCond(parsed); if (superClass != null && !addedToSuper) { if (implementedBy != null && !superClass.name.equals(Names.JAVA_LANG_OBJECT)) { addedToSuper = true; specifiedInterfaces.addLast(superClass); } if (implementedBy == null || !ifaceListTerm.notEmpty()) { addedToSuper = true; if (superClass.implementedBy != null) { classbody.fatalError(context, "A class cannot be extended from an interface: " + superClass.name); } superClass.subclasses.addLast(this); } } } private void addFieldsToInner(ClassDefinition cd) { define(cd); if (superClass != null) { Term.assertCond(implementedBy != null); superClass.addFieldsToInner(cd); if (!cd.interfaceClasses.contains(this)) { cd.interfaceClasses.addLast(this); implementedBy.addLast(cd); Enumeration en = interfaceClasses(cd).elements(); while (en.hasMoreElements()) { ClassDefinition classDefn = (ClassDefinition) en .nextElement(); cd.interfaceClasses.addLast(classDefn); classDefn.implementedBy.addLast(cd); } } } } void addFieldsTo(ClassDefinition cd) { Term.assertCond(cd.isDefined); if (implementedBy == null) { classbody .fatalError(context, "Not an interface is specified after 'implements': " + name); } cd.specifiedInterfaces.addLast(this); if (cd.implementedBy != null && cd.superClass.name.equals(Names.JAVA_LANG_OBJECT)) { if (!cd.addedToSuper) { cd.superClass = this; cd.addedToSuper = true; subclasses.addLast(cd); } } else { addFieldsToInner(cd); } } private void definePass1(ClassDefinition forClass) { Main.dict.message("Analyzing: " + name + (forClass != null ? " (for " + forClass.name + ")" : "")); Term.assertCond(context.currentClass == this); Term.assertCond(context.currentMethod == null); if (!isStaticClass()) { int nesting = 0; for (ClassDefinition cd = outerClass; !cd.isStaticClass(); cd = cd.outerClass) { nesting++; } outerThisRef = new VariableDefinition(this, "this$" + nesting, AccModifier.FINAL | AccModifier.SYNTHETIC, outerClass, Empty.newTerm(), true); addField(outerThisRef); } if (outerScope != null) { outerFields = new ObjHashtable(); Enumeration en = outerLocals.elements(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) en.nextElement(); String varName = v.id(); VariableDefinition field; if (superClass == null || superClass.outerClass() != outerClass || (field = superClass.getOuterField(varName, this)) == null) { addField(field = new VariableDefinition(this, "val$" + varName, AccModifier.FINAL | AccModifier.SYNTHETIC, v.exprType(), Empty.newTerm(), false)); } field.markUsed(true, true); outerFields.put(varName, field); } } boolean oldHasConstructor = context.hasConstructor; context.hasConstructor = false; classbody.processPass1(context); mayContainClinit = false; boolean isProxy = isProxyClass(); if (!context.hasConstructor && implementedBy == null) { Term constr; if (isProxy) { ClassDefinition objectClass = Main.dict .get(Names.JAVA_LANG_OBJECT); Enumeration en = objectClass.methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = objectClass .getMethodNoInheritance((String) en.nextElement()); if (md.isPublic() && !md.isConstructor() && md.allowOverride()) { objectClass.reflectMethodInner(md); addMethod(md.cloneMethodFor(this, true)); } } constr = new TypeDeclaration( new AccModifier(AccModifier.PUBLIC | AccModifier.SYNTHETIC), new ConstrDeclaration( new LexTerm(LexTerm.ID, id), new FormalParameter( new AccModifier(AccModifier.SYNTHETIC), new ClassOrIfaceType( Main.dict .get(Names.JAVA_LANG_REFLECT_INVOCATIONHANDLER)), Empty.newTerm(), new VariableIdentifier(new LexTerm( LexTerm.ID, "handler")), Empty .newTerm()), Empty.newTerm(), new ExprStatement(new ConstructorCall(Empty .newTerm(), new Super(), new Argument( new Expression(new QualifiedName( new LexTerm(LexTerm.ID, "handler")))))))); } else { Term paramList = constrParamList; if (constrSuperType != null) { paramList = FormalParamList.prepend( new FormalParameter(new AccModifier( AccModifier.FINAL | AccModifier.SYNTHETIC), new ClassOrIfaceType(constrSuperType .receiverClass()), Empty.newTerm(), (new VariableIdentifier(new LexTerm( LexTerm.ID, "this$00"))) .setLineInfoFrom(classbody), Empty .newTerm()), paramList); } constr = new TypeDeclaration( new AccModifier((modifiers & (AccModifier.PUBLIC | AccModifier.PRIVATE | AccModifier.PROTECTED)) | ((modifiers & AccModifier.PUBLIC) != 0 ? 0 : AccModifier.SYNTHETIC)), (new ConstrDeclaration(new LexTerm(LexTerm.ID, id), paramList, Empty.newTerm(), Empty.newTerm())) .setLineInfoFrom(classbody)); classbody = (new Seq(classbody, constr)) .setLineInfoFrom(classbody); } constr.processPass1(context); Main.dict.methodsAnalyzed--; } context.hasConstructor = oldHasConstructor; if (classInitializers != null && !classInitializers.isJavaConstant(this)) { modifiers |= AccModifier.NATIVE; } Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (!checkOverridenMethodRetType(md)) { classbody.fatalError(context, "Incompatible return type in: " + name + "." + md.methodSignature().getInfo()); } } if (isInterface()) { ClassDefinition cd = superClass; cd.define(this); if (cd.superClass != null) { Enumeration en2 = cd.methodDictionary().keys(); while (en2.hasMoreElements()) { String sigString = (String) en2.nextElement(); if (getMethod(sigString) == null) { addInheritedMethod(sigString, false); } } } } Enumeration en2 = interfaceClasses(null).elements(); while (en2.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en2.nextElement(); cd.define(this); Term.assertCond(cd.definePassOneDone); Enumeration en3 = cd.methodDictionary().keys(); while (en3.hasMoreElements()) { String sigString = (String) en3.nextElement(); MethodDefinition md = getMethod(sigString); if (md == null) { md = addInheritedMethod(sigString, isProxy); } if (isProxy) { md.intersectThrowsWith(cd.getMethodNoInheritance(sigString)); } } } definePassOneDone = true; } private boolean checkOverridenMethodRetType(MethodDefinition md) { String sigString = md.methodSignature().signatureString(); int retSize = md.exprType().objectSize(); if (retSize >= Type.CLASSINTERFACE) { retSize = Type.CLASSINTERFACE; } ClassDefinition cd = superClass; if (cd != null) { MethodDefinition md2 = cd.getMethodSamePkg(sigString, getPackageName()); if (md2 != null) { int retSize2 = md2.exprType().objectSize(); if (retSize2 >= Type.CLASSINTERFACE) { retSize2 = Type.CLASSINTERFACE; } if (retSize != retSize2) return false; } } Enumeration en = interfaceClasses(null).elements(); while (en.hasMoreElements()) { cd = (ClassDefinition) en.nextElement(); cd.define(this); MethodDefinition md2 = cd.getMethodNoInheritance(sigString); if (md2 != null) { int retSize2 = md2.exprType().objectSize(); if (retSize2 >= Type.CLASSINTERFACE) { retSize2 = Type.CLASSINTERFACE; } if (retSize != retSize2) return false; } } return true; } private MethodDefinition addInheritedMethod(String sigString, boolean isProxy) { MethodDefinition md = null; ExpressionType resType = null; if (isInterface()) { ClassDefinition cd = superClass; if (cd.superClass() != null && (md = cd.getMethodNoInheritance(sigString)) != null) { resType = md.exprType(); } } Enumeration en = interfaceClasses(null).elements(); while (en.hasMoreElements()) { MethodDefinition md2 = ((ClassDefinition) en.nextElement()) .getMethodNoInheritance(sigString); if (md2 != null) { ExpressionType resType2 = md2.exprType(); if (md == null || (resType != resType2 && isAssignableFrom(resType, resType2, this))) { md = md2; resType = resType2; } } } Term.assertCond(md != null); addMethod(md.cloneMethodFor(this, isProxy)); return md; } void setHasAssertStmt() { markUsed(); modifiers |= AccModifier.NATIVE; if (fieldDictionary.get(Names.ASSERTIONSDISABLED) == null) { addField(new VariableDefinition(this, Names.ASSERTIONSDISABLED, AccModifier.STATIC | AccModifier.FINAL | AccModifier.SYNTHETIC, Main.dict.classTable[Type.BOOLEAN], Empty.newTerm(), false)); } } private void addNativeMethodDepend() { MethodDefinition md = getMethodNoInheritance(Names.SIGN_FINALIZE); if (md != null) { if (superClass != null) { Main.dict.get(Names.JAVA_LANG_VMRUNTIME).markUsed(); } else { md.markUsedThisOnly(); } } if (name.equals(Names.JAVA_LANG_STRING)) { markFields(Names.fieldsOrderString, 1); VariableDefinition v = getField(Names.fieldsOrderString[0], null); if (v != null) { Main.dict.setStringValueType(v.exprType()); } } else if (name.equals(Names.JAVA_LANG_STRINGINDEXOUTOFBOUNDSEXCEPTION)) { if (Main.dict.markStrIndexOutInit) { markMethod(Names.SIGN_INIT_INT); if (basicConstructor != null) { basicConstructor.markUsed(this, false); } } } else if (name.equals(Names.JAVA_LANG_CLASS)) { markFields(Names.fieldsOrderClass, 0); } else if (name.equals(Names.JAVA_LANG_VMCLASS)) { markMethod(Names.SIGN_ARRAYCLASSOF0X); } else if (name.equals(Names.JAVA_LANG_VMCLASSLOADER)) { Main.dict.buildClassTable = true; } else if (name.equals(Names.JAVA_LANG_VMRUNTIME)) { markMethod(Names.SIGN_FINALIZEOBJECT0X); } else if (name.equals(Names.JAVA_LANG_VMTHREAD)) { markMethod(Names.SIGN_DESTROYJAVAVM0X); } } int otherInstanceFieldsUnused(String[] names) { Term.assertCond(used); boolean hasOther = false; Enumeration en = fieldDictionary().unorderedElements(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) en.nextElement(); String varName = v.id(); if (v.used() && !v.isClassVariable() && (!v.isFinalVariable() || isReflectedField(varName))) { int i = names.length; while (i-- > 0) { if (varName.equals(names[i])) break; } if (i < 0) { if (v.exprType().objectSize() >= Type.CLASSINTERFACE) return -1; hasOther = true; } } } return hasOther ? 0 : 1; } static void setSpecialVirtual() { MethodDefinition md = Main.dict.get(Names.JAVA_LANG_OBJECT).getMethod( Names.SIGN_FINALIZE); if (md != null && Main.dict.get(Names.JAVA_LANG_VMRUNTIME).used) { md.setVirtual(); } Main.dict.allowConstClass = Main.dict.get(Names.JAVA_LANG_CLASS) .otherInstanceFieldsUnused(Names.fieldsOrderClass); VariableDefinition v = Main.dict.get(Names.JAVA_LANG_STRING).getField( Names.fieldsOrderString[Names.fieldsOrderString.length - 1], null); if (v != null && v.used() && !v.isClassVariable()) { Main.dict.fillStrHash = true; } } private static void markAllBasicCtors() { if (!Main.dict.markBasicCtors) { Main.dict.markBasicCtors = true; Enumeration en = Main.dict.usedClasses(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); MethodDefinition md = cd.basicConstructor; if (md != null && !cd.isInterface() && !md.isPrivate()) { md.markUsed(cd, true); } } } } static void markAllDirectIfaces() { if (!Main.dict.markDirectIfaces) { Main.dict.markDirectIfaces = true; Main.dict.get(Names.JAVA_LANG_CLONEABLE).setVTableUsed(true); Main.dict.get(Names.JAVA_IO_SERIALIZABLE).setVTableUsed(true); Enumeration en = Main.dict.usedClasses(); while (en.hasMoreElements()) { Enumeration en2 = ((ClassDefinition) en.nextElement()).specifiedInterfaces .elements(); while (en2.hasMoreElements()) { ((ClassDefinition) en2.nextElement()).setVTableUsed(true); } } } } void markForInstanceOf(boolean isArray) { if (isObjectOrCloneable()) { markUsed(); } else if (isArray && isInterface()) { if (!markIfImplemented) { markIfImplemented = true; Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { if (((ClassDefinition) en.nextElement()).used) { setVTableUsed(true); break; } } } } else if (hasInstances) { markUsed(); } else { markIfHasInstances = true; } } static void processEnumValueOf() { if (!Main.dict.hasEnumValueOf) { Main.dict.hasEnumValueOf = true; Enumeration en = Main.dict.get(Names.JAVA_LANG_ENUM).subclasses .elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { cd.processEnumClass(); } } } } private void processEnumClass() { Enumeration en = fieldDictionary().keys(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary.get(en .nextElement()); if (isEnumValueField(v)) { reflectFieldInner(v); } } } private boolean isEnumValueField(VariableDefinition v) { ExpressionType resType; return v.isClassVariable() && v.isFinalVariable() && !v.isPrivate() && ((resType = v.exprType()) == this || resType.receiverClass() .superClass() == this); } private void processSerialization() { if (!isProxyClass()) { if (name.equals(Names.JAVA_IO_OBJECTINPUTSTREAM)) { Enumeration en = Main.dict.usedClasses(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()) .markForObjectInputStream(); } } else if (Main.dict.get(Names.JAVA_IO_OBJECTINPUTSTREAM).used) { markForObjectInputStream(); } if (name.equals(Names.JAVA_IO_OBJECTOUTPUTSTREAM)) { Enumeration en = Main.dict.usedClasses(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()) .markForObjectOutputStream(); } } else if (Main.dict.get(Names.JAVA_IO_OBJECTOUTPUTSTREAM).used) { markForObjectOutputStream(); } if (name.equals(Names.JAVA_IO_OBJECTSTREAMCLASS)) { Enumeration en = Main.dict.usedClasses(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()) .markForObjectStreamClass(); } } else if (Main.dict.get(Names.JAVA_IO_OBJECTSTREAMCLASS).used) { markForObjectStreamClass(); } } } private void markForObjectInputStream() { ClassDefinition serializableClass = Main.dict .get(Names.JAVA_IO_SERIALIZABLE); if (!isInterface() && serializableClass.isAssignableFrom(this, 0, this)) { if (!isAbstractOrInterface()) { setHasInstances(); if (!hasExactInstance) { ClassDefinition sc = superClass; while (sc != null && serializableClass.isAssignableFrom(sc, 0, this)) { sc = sc.superClass(); } if (sc != null && sc.basicConstructor != null && !sc.basicConstructor.isPrivate()) { setHasExactInstance(true); } } } MethodDefinition md = getMethodNoInheritance(Names.SIGN_READOBJECT); if (md != null && !md.isAbstract()) { reflectMethodInner(md); } md = getMethodNoInheritance(Names.SIGN_READRESOLVE); if (md != null && !md.isAbstract()) { reflectMethodInner(md); } } } private void markForObjectOutputStream() { if (!isInterface() && Main.dict.get(Names.JAVA_IO_SERIALIZABLE).isAssignableFrom( this, 0, this)) { MethodDefinition md = getMethodNoInheritance(Names.SIGN_WRITEOBJECT); if (md != null && !md.isAbstract()) { reflectMethodInner(md); } md = getMethodNoInheritance(Names.SIGN_WRITEREPLACE); if (md != null && !md.isAbstract()) { reflectMethodInner(md); } } } private void markForObjectStreamClass() { if (Main.dict.get(Names.JAVA_IO_SERIALIZABLE).isAssignableFrom(this, 0, this)) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(Names.SERIALVERSIONUID); if (v == null) { v = new VariableDefinition(this, Names.SERIALVERSIONUID, AccModifier.PRIVATE | AccModifier.STATIC | AccModifier.FINAL | AccModifier.SYNTHETIC, Main.dict.classTable[Type.LONG], new Expression( new IntLiteral(computeSerialVersion())), false); addField(v); } reflectFieldInner(v); if (!Main.dict.get(Names.JAVA_IO_EXTERNALIZABLE).isAssignableFrom( this, 0, this) && !name.equals(Names.JAVA_LANG_CLASS) && !name.equals(Names.JAVA_LANG_STRING)) { v = (VariableDefinition) fieldDictionary .get(Names.SERIALPERSISTENTFIELDS); if (v != null && v.isClassVariable()) { reflectFieldInner(v); } Enumeration en = fieldDictionary().keys(); while (en.hasMoreElements()) { v = (VariableDefinition) fieldDictionary.get(en .nextElement()); if (!v.isClassVariable() && !v.isTransient()) { reflectFieldInner(v); } } } } } String getJavaSignature() { return type == Type.CLASSINTERFACE ? Type.sig[Type.CLASSINTERFACE] + name.replace('.', '/') + ";" : Type.sig[type]; } boolean classInitializerNotCalledYet() { return mayContainClinit || classInitializers != null; } InitializerPart addInitializer(Term term, boolean isClassVariable) { return isClassVariable ? (classInitializers = new InitializerPart( classInitializers, term)) : (instanceInitializers = new InitializerPart( instanceInitializers, term)); } private ConstValue computeSerialVersion() { SecHashAlg sha = new SecHashAlg(); sha.updateUTF(name); int classaccess = modifiers & (AccModifier.PUBLIC | AccModifier.INTERFACE | AccModifier.ABSTRACT); if (isInterface()) { classaccess &= AccModifier.PUBLIC | AccModifier.INTERFACE; Enumeration en = methodDictionary().unorderedElements(); while (en.hasMoreElements()) { MethodDefinition md = (MethodDefinition) en.nextElement(); if (md.definingClass() == this && !md.isCopiedFromIface()) { classaccess |= AccModifier.ABSTRACT; break; } } } else if (isFinal()) { classaccess |= AccModifier.FINAL; } sha.updateInt(classaccess); int size = specifiedInterfaces.countSize(); String[] names; if (size > 0) { names = new String[size]; Enumeration en = specifiedInterfaces.elements(); for (int i = 0; en.hasMoreElements(); i++) { names[i] = ((ClassDefinition) en.nextElement()).name; } names = sortStrings(names, size); for (int i = 0; i < size; i++) { sha.updateUTF(names[i]); } } size = fieldDictionary().size(); if (size > 0) { names = new String[size]; fieldDictionary().copyKeysInto(names); names = sortStrings(names, size); for (int i = 0; i < size; i++) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(names[i]); if (!v.isPrivate() || (!v.isClassVariable() && !v.isTransient())) { sha.updateUTF(names[i]); sha.updateInt(v.getJavaModifiers() & (AccModifier.PUBLIC | AccModifier.PRIVATE | AccModifier.PROTECTED | AccModifier.STATIC | AccModifier.FINAL | AccModifier.VOLATILE | AccModifier.TRANSIENT)); sha.updateUTF(v.exprType().getJavaSignature()); } } } if ((modifiers & AccModifier.NATIVE) != 0) { sha.updateUTF("<clinit>"); sha.updateInt(AccModifier.STATIC); sha.updateUTF("()V"); } names = new String[methodDictionary().size()]; size = 0; Enumeration en = methodDictionary.keys(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); MethodDefinition md = getMethodNoInheritance(sigString); if (md.definingClass() == this && !md.isPrivate() && !md.isCopiedFromIface()) { names[size++] = (md.isConstructor() ? " " : "") + md.id() + " " + md.getJavaSignature() + " " + sigString; } } if (size > 0) { names = sortStrings(names, size); for (int i = 0; i < size; i++) { String s = names[i]; int j = s.indexOf(' ', 1); int k = s.lastIndexOf(' '); sha.updateUTF(s.substring(s.charAt(0) != ' ' ? 0 : 1, j)); sha.updateInt(getMethodNoInheritance(s.substring(k + 1)) .getJavaModifiers() & (AccModifier.PUBLIC | AccModifier.PRIVATE | AccModifier.PROTECTED | AccModifier.STATIC | AccModifier.FINAL | AccModifier.SYNCHRONIZED | AccModifier.NATIVE | AccModifier.ABSTRACT | AccModifier.STRICT)); sha.updateUTF(s.substring(j + 1, k).replace('/', '.')); } } sha.finishUpdate(); byte[] hashvalue = new byte[20]; sha.engineDigestVal(hashvalue); return new ConstValue(((hashvalue[3] & 0xff) << 24) | ((hashvalue[2] & 0xff) << 16) | ((hashvalue[1] & 0xff) << 8) | (hashvalue[0] & 0xff), ((hashvalue[7] & 0xff) << 24) | ((hashvalue[6] & 0xff) << 16) | ((hashvalue[5] & 0xff) << 8) | (hashvalue[4] & 0xff)); } private void processRemoteMethodInvocation() { if (Main.dict.get("java.rmi.server." + "RemoteStub").isAssignableFrom( this, 0, this)) { ObjVector parmSig = new ObjVector(); parmSig.addElement(Main.dict.get("java.rmi.server." + "RemoteRef")); MethodDefinition md = matchConstructor(parmSig, this); if (md != null) { reflectMethodInner(md); } } else { if (Main.dict.get("java.rmi." + "Remote").isAssignableFrom(this, 0, this)) { Main.dict.defineIfExists(name + "_Stub", this); Main.dict.defineIfExists(name + "_Skel", this); ClassDefinition cd = this; do { Enumeration en = cd.methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = cd .getMethodNoInheritance((String) en .nextElement()); if (!md.isConstructor()) { ClassDefinition classDefn = md.definingClass(); if (!md.isPrivate() && !classDefn.name.startsWith(Names.JAVA_0)) { classDefn.reflectMethodInner(md); } } } cd = cd.superClass(); cd.define(this); } while (cd.superClass != null); } } if (Main.dict.get("org.omg.CORBA.portable." + "Streamable") .isAssignableFrom(this, 0, this)) { VariableDefinition v = getField("value", null); if (v != null) { ClassDefinition cd = v.definingClass(); cd.reflectFieldInner(v); cd = v.exprType().receiverClass(); if (cd.objectSize() == Type.CLASSINTERFACE) { cd.reflectAllFields(false); } } } } boolean defined() { return isDefined; } void markUsed() { if (!used) { used = true; if (--Main.dict.failOnClassLimit == 0) throw new TranslateException( "Processed classes limit exceeded!"); if (name.equals(Main.dict.failOnClassName) && Main.dict.failOnMethodId == null && Main.dict.failOnFieldName == null) throw new AssertException("Specified class is required!"); if (!isDefined) { predefineClass(null); return; } Main.dict.classNowUsed(this); addNativeMethodDepend(); ClassDefinition sc = superClass(); if (sc != null) { if (!isInterface()) { sc.markUsed(); } if (Main.dict.markDirectIfaces) { Enumeration en = specifiedInterfaces.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()) .setVTableUsed(true); } } if (sc.used) { Enumeration en = sc.usedMethodSigns.keys(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); String pkgName = (String) sc.usedMethodSigns .get(sigString); if (pkgName.length() == 0) { pkgName = null; } MethodDefinition md = getMethodNoInheritance(sigString); if (md != null && !md.isClassMethod() && (pkgName == null || pkgName .equals(getPackageName()))) { md.markUsed(this, false); } else { markMethodInSubclasses(sigString, pkgName); } } } reflectInheritedFrom(sc); reflectInheritedFieldsFrom(sc); Enumeration en = interfaceClasses(null).elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.markIfImplemented) { cd.setVTableUsed(true); } Enumeration en2 = cd.usedMethodSigns.keys(); while (en2.hasMoreElements()) { String sigString = (String) en2.nextElement(); MethodDefinition md = getMethod(sigString); if (md != null) { md.markUsed(this, false); } if (md == null || md.definingClass() != this) { cd.markMethodInSubclasses(sigString, null); } } reflectInheritedFrom(cd); } if (sc.name.equals(Names.JAVA_UTIL_LISTRESOURCEBUNDLE) || sc.name .equals(Names.COM_IVMAISOFT_JPROPJAV_STRLISTRESOURCEBUNDLE)) { int pos = name.lastIndexOf('_'); if (pos > 0 && name.indexOf('.', pos + 1) < 0) { Main.dict.dynamicDefineClass(name.substring(0, pos), null, this); } } } if (basicConstructor != null && !isInterface() && ((Main.dict.markBasicCtors && !basicConstructor .isPrivate()) || name .equals(Names.JAVA_LANG_THROWABLE))) { basicConstructor.markUsed(this, true); } if (name.equals(Names.JAVA_LANG_REFLECT_VMCONSTRUCTOR)) { markAllBasicCtors(); } if (isObjectOrCloneable() || name.equals(Names.JAVA_LANG_THROWABLE)) { setHasExactInstance(true); setHasInstances(); } else { setHasExactInstance(false); } if (sc != null && Main.dict.hasEnumValueOf && sc.name.equals(Names.JAVA_LANG_ENUM)) { processEnumClass(); } processSerialization(); processRemoteMethodInvocation(); if (name.equals(Names.JAVA_LANG_REFLECT_PROXY)) { reflectConstructors(false, Names.SIGN_INIT_INVOCATIONHANDLER, false); } if (name.equals(Names.JAVA_LANG_CLASSLOADER_STATICDATA)) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(Names.SYSTEMCLASSLOADER); if (v != null) { reflectFieldInner(v); } } if (!name.startsWith(Names.JAVA_LANG_0) && !name.equals(Names.JAVA_IO_VMFILE)) { markFieldInitializers(true); } if (hasInstances) { markFieldInitializers(false); } needStaticInitPass = true; if (outerClass != null) { outerClass.markUsed(); } if (Main.dict.isClassNameUsed(this)) { Main.dict.addStringLiteral(name, this); } } } boolean used() { return used; } void markUsedForArray() { forArraysUsed = true; markUsed(); } void markAllDefinedClasses() { if (!markIfDefined) { markIfDefined = true; markUsed(); if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()) .markAllDefinedClasses(); } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()).markAllDefinedClasses(); } } } private void inheritMarkIfDefined() { if (superClass != null) { if (superClass.markIfDefined) { markAllDefinedClasses(); } else { Enumeration en = specifiedInterfaces.elements(); while (en.hasMoreElements()) { if (((ClassDefinition) en.nextElement()).markIfDefined) { markAllDefinedClasses(); break; } } } } } boolean hasNativeIdCollision(String ident) { boolean found = false; Enumeration en = methodDictionary().unorderedElements(); while (en.hasMoreElements()) { MethodDefinition md = (MethodDefinition) en.nextElement(); if (md.isNative() && ident.equals(md.id())) { if (found) return true; found = true; } } return false; } void markAllPublicStaticMethods() { Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.isPublic() && md.isClassMethod()) { md.markUsedThisOnly(); } } } boolean reflectAllPublicStaticMethods() { boolean reflected = false; MethodDefinition mdMain = getMethodNoInheritance(Names.SIGN_MAIN); Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.isPublic() && md.isClassMethod() && md != mdMain) { reflectMethodInner(md); reflected = true; } } return reflected; } void markAllNatives() { boolean isJavaCore = name.startsWith(Names.JAVA_0) || name.startsWith(Names.GNU_0); Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.isNative() || (isJavaCore && !md.isPrivate())) { md.markUsedThisOnly(); md.markUsed(this, false); } } } private void markFieldInitializers(boolean isStatic) { Enumeration en = fieldDictionary().keys(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary .get((String) en.nextElement()); if (v.isClassVariable() == isStatic) { v.markInitializerOnly(); } } } private void markFields(String[] names, int ignoreLastCnt) { int len = names.length - ignoreLastCnt; VariableDefinition v; for (int i = 0; i < len; i++) { if ((v = getField(names[i], null)) != null) { v.markUsed(); } } } void markMethod(String sigString) { MethodDefinition md = getMethod(sigString); if (md != null) { md.markUsed(null); if (md.isConstructor()) { md.markNew(); } } } int markMethodInSubclasses(String sigString, String pkgName) { if (pkgName == null) { usedMethodSigns.put(sigString, ""); } else { String prevPkgName = (String) usedMethodSigns.get(sigString); if (prevPkgName == null) { usedMethodSigns.put(sigString, pkgName); } else if (prevPkgName.length() > 0 && !pkgName.equals(prevPkgName)) { usedMethodSigns.put(sigString, ""); } } int cnt = 0; if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { MethodDefinition md = cd.getMethod(sigString); cnt += md != null ? md.markUsed(cd, false) : cd .markMethodInSubclasses(sigString, null); } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); MethodDefinition md; cnt += cd.used && (md = cd.getMethodNoInheritance(sigString)) != null && !md.isClassMethod() && (pkgName == null || pkgName.equals(cd.getPackageName())) ? md .markUsed(cd, false) : cd.markMethodInSubclasses(sigString, pkgName); } return cnt; } void setVirtualInSubclasses(String sigString) { if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { MethodDefinition md = cd.getMethod(sigString); if (md != null) { md.setVirtual(); } else { cd.setVirtualInSubclasses(sigString); } } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); MethodDefinition md = null; if (cd.used && (md = cd.getMethodNoInheritance(sigString)) != null) { md.setVirtual(); } if (md == null || md.definingClass() != cd) { cd.setVirtualInSubclasses(sigString); } } } boolean subclassHasMethod(String sigString, String pkgName) { if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { MethodDefinition md = cd.getMethod(sigString); if ((md != null && !md.isAbstract() && !md.isClassMethod()) || cd.subclassHasMethod(sigString, null)) return true; } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); MethodDefinition md; if ((cd.used && (md = cd.getMethodNoInheritance(sigString)) != null && !md.isAbstract() && !md.isClassMethod() && (pkgName == null || pkgName .equals(cd.getPackageName()))) || cd.subclassHasMethod(sigString, pkgName)) return true; } return false; } private void getTwoRealSubclasses(ObjVector classes) { if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.hasInstances && cd.used) { if (cd.isAbstractOrInterface()) { cd.getTwoRealSubclasses(classes); } else if (classes.identityLastIndexOf(cd) < 0) { classes.addElement(cd); } if (classes.size() > 1) return; } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.hasInstances && cd.used) { if (cd.isAbstractOrInterface()) { cd.getTwoRealSubclasses(classes); } else if (classes.identityLastIndexOf(cd) < 0) { classes.addElement(cd); } if (classes.size() > 1) break; } } } ClassDefinition getRealOurClass() { if (isAbstractOrInterface() && !isObjectOrCloneable()) { ObjVector classes = new ObjVector(); getTwoRealSubclasses(classes); if (classes.size() == 1) return (ClassDefinition) classes.elementAt(0); } return this; } MethodDefinition getSingleRealMethodInSubclasses(MethodDefinition md, ClassDefinition[] cdArr) { ObjVector methods = new ObjVector(); getTwoRealMethodsInSubclasses(methods, md.methodSignature() .signatureString(), md.isProtectedOrPublic() ? null : md .definingClass().getPackageName(), cdArr); return methods.size() == 1 ? (MethodDefinition) methods.elementAt(0) : null; } private void getTwoRealMethodsInSubclasses(ObjVector methods, String sigString, String pkgName, ClassDefinition[] cdArr) { if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.hasInstances && cd.used) { MethodDefinition md = cd.getMethod(sigString); if (md != null && md.usedExact() && !md.isAbstract()) { if (methods.identityLastIndexOf(md) < 0) { methods.addElement(md); cdArr[0] = cd; } } else { cd.getTwoRealMethodsInSubclasses(methods, sigString, null, cdArr); } if (methods.size() > 1) return; } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.hasInstances && cd.used) { MethodDefinition md = cd.getMethodNoInheritance(sigString); if (md != null && md.usedExact() && !md.isAbstract() && !md.isClassMethod() && (pkgName == null || pkgName.equals(cd .getPackageName()))) { if (methods.identityLastIndexOf(md) < 0) { methods.addElement(md); cdArr[0] = cd; } } else { cd.getTwoRealMethodsInSubclasses(methods, sigString, pkgName, cdArr); } if (methods.size() > 1) break; } } } boolean copyObjLeaksInSubclasses(String sigString, Term argsList) { ClassDefinition cd; if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { if ((cd = (ClassDefinition) en.nextElement()).hasInstances && cd.used) { MethodDefinition md = cd.getMethod(sigString); if ((md != null && !md.isAbstract() && md .copyObjLeaksTo(argsList)) || cd.copyObjLeaksInSubclasses(sigString, argsList)) return true; } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { if ((cd = (ClassDefinition) en.nextElement()).hasInstances && cd.used) { MethodDefinition md = cd.getMethodNoInheritance(sigString); if ((md != null && !md.isAbstract() && md .copyObjLeaksTo(argsList)) || cd.copyObjLeaksInSubclasses(sigString, argsList)) return true; } } return false; } boolean hasThisObjLeakInSubclasses(String sigString, boolean isReturned) { ClassDefinition cd; if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { if ((cd = (ClassDefinition) en.nextElement()).hasInstances && cd.used) { MethodDefinition md = cd.getMethod(sigString); if ((md != null && !md.isAbstract() && md .hasThisObjLeak(isReturned)) || cd.hasThisObjLeakInSubclasses(sigString, isReturned)) return true; } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { if ((cd = (ClassDefinition) en.nextElement()).hasInstances && cd.used) { MethodDefinition md = cd.getMethodNoInheritance(sigString); if ((md != null && !md.isAbstract() && md .hasThisObjLeak(isReturned)) || cd.hasThisObjLeakInSubclasses(sigString, isReturned)) return true; } } return false; } boolean isThisStackObjVltInSubclasses(String sigString) { ClassDefinition cd; if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { if ((cd = (ClassDefinition) en.nextElement()).hasInstances && cd.used) { MethodDefinition md = cd.getMethod(sigString); if ((md != null && !md.isAbstract() && md .isThisStackObjVolatile()) || cd.isThisStackObjVltInSubclasses(sigString)) return true; } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { if ((cd = (ClassDefinition) en.nextElement()).hasInstances && cd.used) { MethodDefinition md = cd.getMethodNoInheritance(sigString); if ((md != null && !md.isAbstract() && md .isThisStackObjVolatile()) || cd.isThisStackObjVltInSubclasses(sigString)) return true; } } return false; } void setWritableArrayRetInSubclasses(String sigString) { ClassDefinition cd; if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { if ((cd = (ClassDefinition) en.nextElement()).hasInstances && cd.used) { MethodDefinition md = cd.getMethod(sigString); if (md != null && !md.isAbstract()) { md.setWritableArray(); } else { cd.setWritableArrayRetInSubclasses(sigString); } } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { if ((cd = (ClassDefinition) en.nextElement()).hasInstances && cd.used) { MethodDefinition md = cd.getMethodNoInheritance(sigString); if (md != null && !md.isAbstract()) { md.setWritableArray(); } else { cd.setWritableArrayRetInSubclasses(sigString); } } } } Context cloneContextFor(MethodDefinition md) { Term.assertCond(definePassOneDone); Context c = context.cloneForClass(this, this); c.currentMethod = md; return c; } ClassDefinition superClass() { return superClass(null); } ClassDefinition superClass(ClassDefinition forClass) { if (!isDefined && !name.equals(Names.JAVA_LANG_OBJECT)) { predefineClass(forClass); processExtends(); } return superClass; } private ObjQueue interfaceClasses(ClassDefinition forClass) { define(forClass); return interfaceClasses; } VariableDefinition addField(VariableDefinition v) { Term.assertCond(fieldDictionary != null); return (VariableDefinition) fieldDictionary.put(v.id(), v); } MethodDefinition addMethod(MethodDefinition md) { Term.assertCond(isDefined); if (md.isConstructor() && !md.hasParameters()) { basicConstructor = md; } return (MethodDefinition) methodDictionary.put(md.methodSignature() .signatureString(), md); } private OrderedMap methodDictionary() { define(null); return methodDictionary; } private OrderedMap fieldDictionary() { define(null); return fieldDictionary; } VariableDefinition getOuterField(String fieldName, ClassDefinition forClass) { define(forClass); return outerFields != null ? (VariableDefinition) outerFields .get(fieldName) : null; } VariableDefinition getField(String fieldName, ClassDefinition forClass) { ClassDefinition cd = this; do { cd.define(forClass); VariableDefinition v = cd.getOuterField(fieldName, forClass); if ((v != null || (v = (VariableDefinition) cd.fieldDictionary .get(fieldName)) != null) && (cd == this || v.isProtectedOrPublic() || (!v .isPrivate() && cd.getPackageName().equals( getPackageName())))) return v; Enumeration en = cd.specifiedInterfaces.elements(); while (en.hasMoreElements()) { if ((v = ((ClassDefinition) en.nextElement()).getField( fieldName, forClass)) != null) return v; } } while (!isInterface() && (cd = cd.superClass) != null); return null; } int countHiddenFields(String fieldName) { int hiddenCount = 0; ClassDefinition cd = this; while ((cd = cd.superClass()) != null) { VariableDefinition v = (VariableDefinition) cd.fieldDictionary() .get(fieldName); if (v != null && !v.isClassVariable()) { hiddenCount++; } } return hiddenCount; } ClassDefinition getReflectHelperClass() { if (helperClass != null) return helperClass != this ? helperClass : null; String className = topOuterClass().name; int pos = className.lastIndexOf('.') + 1; String baseName = className.substring(0, pos) + "VMReflector"; className = className.substring(pos); helperClass = Main.dict.getInner(baseName, "_" + className); if (helperClass != null) { if (!helperClass.isStaticClass()) { helperClass.classbody.fatalError(helperClass.context, "An inner class of VMReflector cannot be non-static: " + helperClass.name); } return helperClass; } helperClass = Main.dict.getInner(baseName, className); if (helperClass != null) { helperClass.classbody.fatalError(helperClass.context, "VMReflector inner class name shall begin with '_': " + helperClass.name); return helperClass; } helperClass = this; return null; } private void reflectFieldInner(VariableDefinition v) { ClassDefinition cd = v.exprType().signatureClass(); cd.predefineClass(this); v.markUsed(); v.setChangedSpecial(); cd.setVTableUsed(true); if (reflectedFieldNames == null) { reflectedFieldNames = new ObjHashSet(); Main.dict.buildClassTable = true; } String fieldName = v.id(); reflectedFieldNames.add(fieldName); Main.dict.addStringLiteral(fieldName, this); if (v.isClassVariable()) { setVTableUsed(false); Main.dict.get(Names.JAVA_LANG_VMCLASS).markUsed(); } } ClassDefinition reflectField(String fieldName, boolean declaredOnly, boolean isExactType) { VariableDefinition v = getField(fieldName, null); if (v != null) { ClassDefinition classDefn = v.definingClass(); if (declaredOnly ? classDefn == this : !v.isPrivate()) { classDefn.reflectFieldInner(v); if (!v.isClassVariable()) return null; if (!isExactType) { addToInheritedFieldReflected(fieldName); } return classDefn; } } if (!isExactType) { addToInheritedFieldReflected(fieldName); } return null; } private void addToInheritedFieldReflected(String fieldName) { Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { cd.reflectField(fieldName, true, false); } } if (inheritedReflFieldNames == null) { inheritedReflFieldNames = new ObjQueue(); } if (!inheritedReflFieldNames.contains(fieldName)) { inheritedReflFieldNames.addLast(fieldName); } } private void reflectInheritedFieldsFrom(ClassDefinition cd) { if (cd.inheritedReflFieldNames != null) { Enumeration en = cd.inheritedReflFieldNames.elements(); while (en.hasMoreElements()) { reflectField((String) en.nextElement(), true, false); } } } ClassDefinition reflectAllFields(boolean declaredOnly) { ClassDefinition cd = this; ClassDefinition classToTrace = null; do { cd.define(this); Enumeration en = cd.fieldDictionary().keys(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) cd.fieldDictionary .get((String) en.nextElement()); if (declaredOnly || !v.isPrivate()) { v.definingClass().reflectFieldInner(v); if (classToTrace == null && v.isClassVariable()) { classToTrace = cd; } } } if (declaredOnly) break; Enumeration en2 = cd.specifiedInterfaces.elements(); while (en2.hasMoreElements()) { ((ClassDefinition) en2.nextElement()).reflectAllFields(false); } } while ((cd = cd.superClass()) != null); return classToTrace; } boolean addFieldOutputName(String outputName) { Term.assertCond(fieldCNames != null); ClassDefinition aclass = this; do { if (aclass.fieldCNames.contains(outputName)) return false; aclass = aclass.superClass(); } while (aclass != null); Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { if (((ClassDefinition) en.nextElement()).fieldCNames .contains(outputName)) return false; } fieldCNames.add(outputName); return true; } private void reflectMethodInner(MethodDefinition md) { Term.assertCond(md.definingClass() == this); if (md.isCopiedFromIface()) { Enumeration en = interfaceClasses(null).elements(); while (en.hasMoreElements()) { MethodDefinition md2 = ((ClassDefinition) en.nextElement()) .getMethod(md.methodSignature()); if (md2 != null) { md2.definingClass().reflectMethodInner(md2); return; } } } md.markUsedThisOnly(); md.markUsed(this, true); md.markAllTypes(true); if (reflectedMethods == null) { reflectedMethods = new ObjHashtable(); Main.dict.buildClassTable = true; if (basicConstructor != null && basicConstructor != md && !isInterface() && !basicConstructor.isPrivate()) { basicConstructor.markUsed(this, true); basicConstructor.markAllTypes(true); reflectedMethods.put(basicConstructor.methodSignature() .signatureString(), basicConstructor); } } reflectedMethods.put(md.methodSignature().signatureString(), md); if (md.isConstructor()) { setHasExactInstance(true); } else { Main.dict.addStringLiteral(md.id(), this); Main.dict.hasReflectedMethods = true; } } int getReflectedMethodSlot(String sigString) { if (reflectedMethods != null && reflectedMethods.get(sigString) != null) { int slot = 0; Enumeration en = methodDictionary.keys(); while (en.hasMoreElements()) { String sign = (String) en.nextElement(); if (reflectedMethods.get(sign) != null) { if (sigString.equals(sign)) return slot; slot++; } } } return -1; } void reflectConstructors(boolean declaredOnly, String sigString, boolean isExactType) { if (used) { if (sigString != null && !sigString.equals("<init>(*)")) { MethodDefinition md = getMethodNoInheritance(sigString); if (md != null && md.isConstructor()) { reflectMethodInner(md); } } else { Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.isConstructor() && (declaredOnly || !md.isPrivate())) { reflectMethodInner(md); } } } } if (!isExactType && reflectConstructorsInherit(sigString)) { if (used) { addToInheritedReflected(sigString); if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { cd.reflectConstructors(declaredOnly, sigString, false); } } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used || isInterface()) { cd.reflectConstructors(declaredOnly, sigString, false); } } } } private boolean reflectConstructorsInherit(String sigString) { return sigString != null && !isFinal() && superClass != null && (!isInterface() || (!sigString.equals("<init>(*)") && (!sigString .equals("<init>()") || (!name.startsWith(Names.JAVA_0) && !name .startsWith(Names.JAVAX_0))))); } private void addToInheritedReflected(String sigString) { if (inheritedReflectedSigns == null) { inheritedReflectedSigns = new ObjQueue(); } if (!inheritedReflectedSigns.contains(sigString)) { inheritedReflectedSigns.addLast(sigString); } } private void reflectInheritedFrom(ClassDefinition cd) { if (cd.inheritedReflectedSigns != null) { Enumeration en = cd.inheritedReflectedSigns.elements(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); MethodDefinition md; if (sigString.equals("<init>(*)")) { Enumeration en2 = methodDictionary().keys(); while (en2.hasMoreElements()) { md = getMethodNoInheritance((String) en2.nextElement()); if (md.isConstructor() && !md.isPrivate()) { reflectMethodInner(md); } } md = null; } else { md = getMethodNoInheritance(sigString); if (md != null) { if (!md.isPrivate() && md.definingClass() == this) { reflectMethodInner(md); } else { md = null; } } } if (md == null || md.isConstructor() || md.isClassMethod()) { addToInheritedReflected(sigString); } } } } void reflectMethods(String methodId, boolean declaredOnly, ObjVector parmSig, boolean isExactType) { if (methodId != null && parmSig != null) { String sigString = (new MethodSignature(methodId, parmSig)) .signatureString(); MethodDefinition md = getMethod(sigString); if (md != null && !md.isConstructor() && (declaredOnly ? md.definingClass() == this : !md .isPrivate())) { md.definingClass().reflectMethodInner(md); if (!md.isClassMethod()) return; } if (!isExactType) { addToInheritedReflected(sigString); if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { cd.reflectMethods(methodId, declaredOnly, parmSig, false); } } } reflectMethodsInSubclasses(declaredOnly, methodId, parmSig); } } else { ClassDefinition cd = this; do { cd.define(this); Enumeration en = cd.methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = cd.getMethodNoInheritance((String) en .nextElement()); if (!md.isConstructor() && (methodId == null || methodId.equals(md.id())) && (parmSig == null || md.methodSignature() .isSignEqual(parmSig))) { ClassDefinition classDefn = md.definingClass(); if (declaredOnly ? classDefn == this : !md.isPrivate()) { classDefn.reflectMethodInner(md); } } } if (declaredOnly) break; cd = cd.superClass(); } while (cd != null && (!isInterface() || !cd.name .equals(Names.JAVA_LANG_OBJECT))); } } private void reflectMethodsInSubclasses(boolean declaredOnly, String methodId, ObjVector parmSig) { Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { cd.reflectMethods(methodId, declaredOnly, parmSig, false); } else if (isInterface()) { cd.reflectMethodsInSubclasses(declaredOnly, methodId, parmSig); } } } private MethodDefinition getMethodNoInheritance(String sigString) { return (MethodDefinition) methodDictionary().get(sigString); } MethodDefinition getMethodNoInheritance(MethodSignature msig) { return (MethodDefinition) methodDictionary() .get(msig.signatureString()); } MethodDefinition getMethod(MethodSignature msig) { return getMethod(msig.signatureString()); } MethodDefinition getMethod(String sigString) { define(null); MethodDefinition md = (MethodDefinition) methodDictionary .get(sigString); if (md != null) return md; ClassDefinition aclass = isInterface() ? Main.dict .get(Names.JAVA_LANG_OBJECT) : superClass(); if (aclass != null) { String pkgName = getPackageName(); do { aclass.define(this); Term.assertCond(aclass.definePassOneDone); md = aclass.getMethodNoInheritance(sigString); if (md != null && !md.isPrivate() && !md.isConstructor() && (md.isProtectedOrPublic() || aclass.getPackageName() .equals(pkgName))) return md; } while ((aclass = aclass.superClass()) != null); } return null; } private MethodDefinition getMethodSamePkg(String sigString, String pkgName) { ClassDefinition aclass = this; do { MethodDefinition md = aclass.getMethodNoInheritance(sigString); if (md != null && !md.isPrivate() && !md.isClassMethod() && aclass.getPackageName().equals(pkgName)) return aclass != this && md.isProtectedOrPublic() ? getMethod(sigString) : md; aclass = aclass.superClass(); } while (aclass != null); return null; } MethodDefinition getSameMethod(MethodDefinition md) { return md.isProtectedOrPublic() ? getMethod(md.methodSignature()) : getMethodSamePkg(md.methodSignature().signatureString(), md .definingClass().getPackageName()); } int countHiddenMethods(String sigString) { ObjVector pkgNameList = new ObjVector(); ClassDefinition aclass = this; String ourPkgName = getPackageName(); pkgNameList.addElement(ourPkgName); while ((aclass = aclass.superClass()) != null) { MethodDefinition md = aclass.getMethodNoInheritance(sigString); if (md != null && md.used() && md.allowVirtual() && !md.isProtectedOrPublic()) { String pkgName = aclass.getPackageName(); int i = pkgNameList.indexOf(pkgName); if (pkgNameList.size() - 1 > i) { if (i >= 0) { pkgNameList.removeElementAt(i); } pkgNameList.addElement(pkgName); } } } return pkgNameList.size() - pkgNameList.indexOf(ourPkgName) - 1; } MethodDefinition matchMethod(MethodSignature msig, ClassDefinition forClass) { define(forClass); Term.assertCond(definePassOneDone); MethodDefinition bestMethod = getMethod(msig); if (bestMethod == null) { int lowestMatch = -1 >>> 1; ClassDefinition cd = this; do { Enumeration en = cd.methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md2 = getMethod((String) en.nextElement()); if (md2 != null) { int value = md2.methodSignature().match(msig, forClass); if (value < lowestMatch) { lowestMatch = value; bestMethod = md2; } } } cd = cd.superClass(); } while (cd != null); } return bestMethod; } MethodDefinition matchConstructor(ObjVector parmSig, ClassDefinition forClass) { MethodSignature msig = new MethodSignature("<init>", parmSig); define(forClass); MethodDefinition bestMethod = getMethodNoInheritance(msig .signatureString()); if (bestMethod == null || !bestMethod.isConstructor()) { int lowestMatch = -1 >>> 1; bestMethod = null; Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md2 = getMethodNoInheritance((String) en .nextElement()); int value; if (md2.isConstructor() && (value = md2.methodSignature().match(msig, forClass)) < lowestMatch) { lowestMatch = value; bestMethod = md2; } } } return bestMethod; } int producePassOne() { if (type != Type.CLASSINTERFACE) return 0; int count = 0; if (!isDefined) { if (!predefining) return 0; if (define(fromClass) > 0) { count++; } } if (checkMarkIfDefined()) { count++; } if (used) { if (Main.dict.verboseTracing) { Main.dict.message("Processing used class: " + name); } if (needStaticInitPass) { needStaticInitPass = false; if (classbody.staticInitializerPass(null, true) != null) { count++; } if (classbody.staticInitializerPass(null, false) != null) { count++; } } Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.usedExact() && md.producePassOne(null) != null) { count++; } } Enumeration en2 = fieldDictionary.keys(); while (en2.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(en2.nextElement()); if (v.used() || v.isInitializerUsedOnly()) { count += v.producePassOne(); } } } return count; } OutputContext outputContext() { return outputContext; } private void fixClassInitializers() { Term.assertCond(used); if (classInitializers != null) { if (classInitializers.hasSomeCode()) { setVTableUsed(false); if (superClass != null && !name.equals(Names.JAVA_LANG_CLASS)) return; classbody.fatalError(context, "Object and Class cannot have <clinit>()"); } initializerDiscoverObjLeaks(classInitializers); classInitializers = null; } if (!isInterface() && superClass != null) { if (superClass.superClass != null) { superClass.fixClassInitializers(); } if (superClass.classInitializers != null || name.equals(Names.JAVA_LANG_STRING) || name.equals(Names.JAVA_LANG_SYSTEM)) { classInitializers = new InitializerPart(null, Empty.newTerm()); setVTableUsed(false); } } } void prepareMethodsForOutput() { Term.assertCond(used); Main.dict.message("Preparing methods in: " + name); fixClassInitializers(); if (classInitializers != null) { initializerDiscoverObjLeaks(classInitializers); } discoverInstanceObjLeaks(); if (reflectedFieldNames != null) { Enumeration en = fieldDictionary.keys(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary .get((String) en.nextElement()); if (v.isClassVariable() && reflectedFieldNames.contains(v.id()) && v.exprType().objectSize() >= Type.CLASSINTERFACE) { Term.assertCond(v.used()); v.setWritableArray(null); } } } Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.usedExact()) { md.discoverObjLeaks(); } } } void addInclassCall(MethodDefinition md) { if (inclassCalls == null) { inclassCalls = new OrderedMap(); } inclassCalls.put(md, ""); } private void produceOutput() { writeHeaders(); if (reflectedMethods != null) { setVirtualForReflectedMethods(); } produceAllFields(); writeInstanceInitializer(); if (inclassCalls != null) { Enumeration en = inclassCalls.keys(); while (en.hasMoreElements()) { MethodDefinition md = (MethodDefinition) en.nextElement(); if (md.usedExact() && (md.isConstructor() || md.allowInline())) { md.produceOutput(outputContext); } } } Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.usedExact()) { md.produceOutput(outputContext); } } writeClassInitializer(); outputContext.fileClose(); } private void setVirtualForReflectedMethods() { Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); if (reflectedMethods.get(sigString) != null) { MethodDefinition md = getMethodNoInheritance(sigString); if (md.allowOverride()) { md.setVirtual(); } } } } private void produceAllFields() { if (superClass != null) { lastObjectRefField = superClass.lastObjectRefField; } int size = fieldDictionary().size(); if (size > 0) { Enumeration en = fieldDictionary.keys(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(en.nextElement()); if (v.isClassVariable() && v.needsOutputFor()) { v.produceOutput(outputContext); } } Enumeration en2 = fieldDictionary.keys(); VariableDefinition[] fields = new VariableDefinition[size]; size = 0; while (en2.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(en2.nextElement()); if (!v.isClassVariable() && v.needsOutputFor()) { fields[size++] = v; } } VariableDefinition.sortBySize(fields, size); if (name.equals(Names.JAVA_LANG_CLASS)) { VariableDefinition.orderFirstFields(fields, size, Names.fieldsOrderClass); } else if (name.equals(Names.JAVA_LANG_STRING)) { VariableDefinition.orderFirstFields(fields, size, Names.fieldsOrderString); } for (int i = 0; i < size; i++) { VariableDefinition v = fields[i]; v.produceOutput(outputContext); if (v.exprType().objectSize() >= Type.CLASSINTERFACE && v.used()) { lastObjectRefField = v; } } } } boolean hasInstanceInitializers() { return instanceInitializers != null && instanceInitializers.hasSomeCode(); } void writeInstanceInitCall(OutputContext oc) { Term.assertCond(used && hasInstances); if (superClass != null && instanceInitializers != null) { oc.cPrint(";"); oc.cPrint(cname); oc.cPrint("__void("); oc.cPrint(This.CNAME); oc.cPrint(")"); } } private void writeInstanceInitializer() { if (instanceInitializers != null && !isInterface() && superClass != null && hasInstances && used) { outputContext.cAndHPrint("JCGO_NOSEP_INLINE "); outputContext.cAndHPrint(Type.cName[Type.VOID]); outputContext.cAndHPrint(" CFASTCALL\n"); outputContext.cAndHPrint(cname); outputContext.cAndHPrint("__void( "); outputContext.cAndHPrint(cname); outputContext.cAndHPrint(" "); outputContext.cAndHPrint(This.CNAME); outputContext.cAndHPrint(" )"); outputContext.hPrint(";\n\n"); outputContext.cPrint("{"); if (instanceInitializers.hasSomeCode()) { Main.dict.message("Writing instance initializer: " + name); int[] curRcvrs = new int[Type.VOID]; instanceInitializers.allocRcvr(curRcvrs); outputContext.writeRcvrsVar(curRcvrs); outputContext.stackObjCountReset(); instanceInitializers.processOutput(outputContext); } else { instanceInitializers = null; } outputContext.cPrint("}\n\n"); } } private void writeClassInitializer() { if (classInitializers != null) { Main.dict.message("Writing static initializer: " + name); int[] curRcvrs = new int[Type.VOID]; classInitializers.allocRcvr(curRcvrs); outputContext.cPrint("JCGO_NOSEP_STATIC "); outputContext.cPrint(Type.cName[Type.VOID]); outputContext.cPrint(" CFASTCALL\n"); outputContext.cPrint(clinitCName()); outputContext.cPrint("( "); outputContext.cPrint(Type.cName[Type.VOID]); outputContext.cPrint(" ){"); outputContext.writeRcvrsVar(curRcvrs); outputContext.stackObjCountReset(); outputContext.cPrint("JCGO_CLINIT_BEGIN("); outputContext.cPrint(cname); outputContext.cPrint("__class);"); if (!isInterface() && superClass != null) { superClass.writeTrigClinit(outputContext); } classInitializers.processOutput(outputContext); outputContext.cPrint("JCGO_CLINIT_DONE("); outputContext.cPrint(cname); outputContext.cPrint("__class);}\n\n"); } if (Main.dict.buildClassTable) { vTableUsed = true; } } private static void initializerDiscoverObjLeaks(InitializerPart initializers) { ObjQueue oldStackObjRetCalls = Main.dict.stackObjRetCalls; Main.dict.stackObjRetCalls = new ObjQueue(); MethodDefinition oldOurMethod = Main.dict.ourMethod; Main.dict.ourMethod = null; ObjHashtable oldAssignedLocals = Main.dict.assignedLocals; Main.dict.assignedLocals = new ObjHashtable(); initializers.discoverObjLeaks(); Main.dict.assignedLocals = oldAssignedLocals; Term.assertCond(Main.dict.stackObjRetCalls != null); MethodDefinition.setRequiredStackObjRets(Main.dict.stackObjRetCalls); Main.dict.ourMethod = oldOurMethod; Main.dict.stackObjRetCalls = oldStackObjRetCalls; } boolean discoverInstanceObjLeaks() { if (!leaksDiscoverDone) { if (leaksDiscoverProcessing) return false; Term.assertCond(used && !needStaticInitPass); if (instanceInitializers != null) { leaksDiscoverProcessing = true; initializerDiscoverObjLeaks(instanceInitializers); } leaksDiscoverDone = true; leaksDiscoverProcessing = false; } return !hasInstanceInitLeaks; } void setInstanceInitLeaks() { Term.assertCond(leaksDiscoverProcessing); hasInstanceInitLeaks = true; } void setInitThisStackObjVolatile() { Term.assertCond(leaksDiscoverProcessing); isInitThisStackObjVolatile = true; } boolean isInitThisStackObjVolatile() { return isInitThisStackObjVolatile; } private void writeHeaders() { Term.assertCond(isDefined); if (!headerWritten) { headerWritten = true; outputContext.cPrint("#ifdef JCGO_SEPARATED\010"); outputContext.cPrint("#define "); outputContext.cPrint(Main.VER_ABBR); outputContext.cPrint("\010"); outputContext.cPrint("#include \"jcgortl.h\"\010"); outputContext.cPrint("#include \"Main.h\"\010"); outputContext.cPrint("#endif\n\n"); outputContext.cAndHPrint("#ifdef "); outputContext.cAndHPrint(Main.VER_ABBR); outputContext.cAndHPrint("\n\n"); outputContext.cPrint("#ifdef CHKALL_"); outputContext.cPrint(topOuterClass().jniname); outputContext.cPrint("\010"); outputContext.cPrint("#include \"jcgobchk.h\"\010"); outputContext.cPrint("#endif\n\n"); } } void finishClass() { if (!finished && type == Type.CLASSINTERFACE) { if (superClass != null) { superClass.finishClass(); } if (used) { Main.dict.message("Finishing output for class: " + name); if (reflectedFieldNames != null || reflectedMethods != null) { outputReflectionInfo(); } finished = true; startMethodDefinitions(); produceObjectJumpTable(); if (superClass != null) { if (methodTableSigns == null) { ObjVector ifaces = new ObjVector(); gatherChainedIfaces(ifaces, new ObjHashSet()); prepareIfaceJumpTables(ifaces); if (methodTableSigns == null) { methodTableSigns = new ObjVector(); } } if (!isInterface() || methodTableSigns.size() == 0) { prepareClassJumpTable(); } produceJumpTable(); } outputContext.hPrint("};\n\n"); writeClassVariables(); if (superClass == null) { outputCoreClasses(); } outputPool(); outputContext.cPrint("#ifdef CHKALL_"); outputContext.cPrint(topOuterClass().jniname); outputContext.cPrint("\010"); outputContext.cPrint("#include \"jcgochke.h\"\010"); outputContext.cPrint("#endif\n\n"); outputContext.cAndHPrint("#endif\n"); outputContext.close(); } } } private void produceObjectJumpTable() { ClassDefinition objectClass = Main.dict.get(Names.JAVA_LANG_OBJECT); Enumeration en = objectClass.methodDictionary().keys(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); if (objectClass.getMethodNoInheritance(sigString).isVirtualUsed()) { MethodDefinition md = getMethod(sigString); if (md.isVirtualUsed()) { md.produceJumpTableEntry(this, false); } else { writeDummyJumpEntry(); } } } } private void gatherChainedIfaces(ObjVector ifaces, ObjHashSet processed) { if (hasInstances && superClass != null) { if (processed.add(this)) { if (isInterface()) { if (!hasUsedIfaceMethods()) return; if (used) { ifaces.addElement(this); } } else { if (!used) return; superClass.gatherChainedIfaces(ifaces, processed); } if (methodTableSigns == null) { methodTableSigns = new ObjVector(); } Enumeration en = specifiedInterfaces.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()).gatherChainedIfaces( ifaces, processed); } if (used) { Enumeration en2 = subclasses.elements(); while (en2.hasMoreElements()) { ((ClassDefinition) en2.nextElement()) .gatherChainedIfaces(ifaces, processed); } if (implementedBy != null) { Enumeration en3 = implementedBy.elements(); while (en3.hasMoreElements()) { ((ClassDefinition) en3.nextElement()) .gatherChainedIfaces(ifaces, processed); } } } } else { int i; if (isInterface() && (i = ifaces.identityLastIndexOf(this)) >= 0) { ifaces.removeElementAt(i); ifaces.addElement(this); } } } } private boolean hasUsedIfaceMethods() { if (used) { ClassDefinition objectClass = Main.dict.get(Names.JAVA_LANG_OBJECT); Enumeration en = methodDictionary().unorderedElements(); while (en.hasMoreElements()) { MethodDefinition md = (MethodDefinition) en.nextElement(); MethodDefinition md2; if (md.used() && ((md2 = objectClass.getMethodNoInheritance(md .methodSignature())) == null || !md2 .isVirtualUsed())) return true; } Enumeration en2 = specifiedInterfaces.elements(); while (en2.hasMoreElements()) { if (((ClassDefinition) en2.nextElement()).hasUsedIfaceMethods()) return true; } } return false; } private static void prepareIfaceJumpTables(ObjVector ifaces) { ClassDefinition objectClass = Main.dict.get(Names.JAVA_LANG_OBJECT); int i = ifaces.size(); while (i-- > 0) { ClassDefinition cd = (ClassDefinition) ifaces.elementAt(i); Term.assertCond(cd.methodTableSigns != null); Enumeration en = cd.methodDictionary().keys(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); MethodDefinition md2; if (cd.getMethodNoInheritance(sigString).used() && ((md2 = objectClass .getMethodNoInheritance(sigString)) == null || !md2 .isVirtualUsed()) && cd.methodTableSigns.indexOf(sigString) < 0) { fillJumpTableEntryFor( getJumpTableIndexFor(sigString, ifaces, i), sigString, ifaces, i); } } } } private static int getJumpTableIndexFor(String sigString, ObjVector ifaces, int i) { int index = 0; boolean[] changedArr = new boolean[1]; ObjHashSet processed = new ObjHashSet(); do { processed.clear(); changedArr[0] = false; index = ((ClassDefinition) ifaces.elementAt(i)) .guessEmptyJumpTableIndex(index, sigString, changedArr, processed); if (!changedArr[0]) { int j = i; while (j-- > 0) { ClassDefinition cd = (ClassDefinition) ifaces.elementAt(j); MethodDefinition md = cd.getMethodNoInheritance(sigString); if (md != null && md.used()) { index = cd.guessEmptyJumpTableIndex(index, sigString, changedArr, processed); } } } } while (changedArr[0]); return index; } private int guessEmptyJumpTableIndex(int index, String sigString, boolean[] changedArr, ObjHashSet processed) { if (used && processed.add(this)) { if (methodTableSigns == null) { methodTableSigns = new ObjVector(); } for (int size = methodTableSigns.size(); index < size; index++) { if ("".equals(methodTableSigns.elementAt(index))) break; } int oldIndex = index; Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { index = ((ClassDefinition) en.nextElement()) .guessEmptyJumpTableIndex(index, sigString, changedArr, processed); } if (implementedBy != null) { Enumeration en2 = implementedBy.elements(); while (en2.hasMoreElements()) { index = ((ClassDefinition) en2.nextElement()) .guessEmptyJumpTableIndex(index, sigString, changedArr, processed); } } if (!isInterface()) { ClassDefinition sc = superClass; while (sc.superClass != null) { MethodDefinition md = sc.getMethodNoInheritance(sigString); if (md != null && md.isVirtualUsed() && md.isProtectedOrPublic()) { index = sc.guessEmptyJumpTableIndex(index, sigString, changedArr, processed); } sc = sc.superClass; } } if (index > oldIndex) { changedArr[0] = true; } } return index; } private int getClassEmptyJumpTableIndex(int index) { if (used) { if (methodTableSigns == null) { methodTableSigns = new ObjVector(); } int oldIndex; do { for (int size = methodTableSigns.size(); index < size; index++) { if ("".equals(methodTableSigns.elementAt(index))) break; } oldIndex = index; Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { index = ((ClassDefinition) en.nextElement()) .getClassEmptyJumpTableIndex(index); } } while (index > oldIndex); } return index; } private static void fillJumpTableEntryFor(int index, String sigString, ObjVector ifaces, int i) { ((ClassDefinition) ifaces.elementAt(i)).fillJumpTableAt(index, sigString); while (i-- > 0) { ClassDefinition cd = (ClassDefinition) ifaces.elementAt(i); MethodDefinition md = cd.getMethodNoInheritance(sigString); if (md != null && md.used()) { cd.fillJumpTableAt(index, sigString); } } } private void fillJumpTableAt(int index, String sigString) { if (used && fillJumpTableOneEntry(index, sigString)) { Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()).fillJumpTableAt(index, sigString); } if (implementedBy != null) { Enumeration en2 = implementedBy.elements(); while (en2.hasMoreElements()) { ((ClassDefinition) en2.nextElement()).fillJumpTableAt( index, sigString); } } if (!isInterface()) { ClassDefinition sc = superClass; while (sc.superClass != null) { MethodDefinition md = sc.getMethodNoInheritance(sigString); if (md != null && md.isVirtualUsed() && md.isProtectedOrPublic()) { sc.fillJumpTableAt(index, sigString); } sc = sc.superClass; } } } } private boolean fillJumpTableOneEntry(int index, String sigString) { Term.assertCond(methodTableSigns != null); for (int size = methodTableSigns.size(); size <= index; size++) { methodTableSigns.addElement(""); } String str = (String) methodTableSigns.elementAt(index); if (sigString.equals(str)) return false; Term.assertCond(str != null && str.length() == 0); methodTableSigns.setElementAt(sigString, index); return true; } private void fillClassJumpTableAt(int index, String sigString) { if (used) { fillJumpTableOneEntry(index, sigString); Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()).fillClassJumpTableAt( index, sigString); } } } private void prepareClassJumpTable() { ClassDefinition objectClass = Main.dict.get(Names.JAVA_LANG_OBJECT); Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); MethodDefinition md = getMethodNoInheritance(sigString); Term.assertCond(md != null); MethodDefinition md2; if (md.isVirtualUsed() && methodTableSigns.indexOf(sigString) < 0 && ((md2 = objectClass.getMethodNoInheritance(sigString)) == null || !md2 .isVirtualUsed()) && (md.isProtectedOrPublic() || methodTableSigns .indexOf(sigString = getPackageName() + ":" + sigString) < 0)) { fillClassJumpTableAt(getClassEmptyJumpTableIndex(0), sigString); } } } private void produceJumpTable() { Term.assertCond(methodTableSigns != null); int dummyCnt = 0; Enumeration en = methodTableSigns.elements(); while (en.hasMoreElements()) { String sigString = (String) en.nextElement(); int pos = sigString.indexOf(':', 0); MethodDefinition md; if (pos >= 0) { String pkgName = sigString.substring(0, pos); sigString = sigString.substring(pos + 1); md = getMethodSamePkg(sigString, pkgName); } else { md = getMethod(sigString); } if (md != null && md.isVirtualUsed()) { while (dummyCnt-- > 0) { writeDummyJumpEntry(); } md.produceJumpTableEntry(this, pos >= 0 && methodTableSigns.indexOf(sigString) >= 0 && md.isProtectedOrPublic()); } dummyCnt++; } } String nextDummyEntryName() { return "jcgo_dummy" + Integer.toString(++dummyEntryCnt); } private void writeDummyJumpEntry() { Term.assertCond(used); outputContext.hPrint(Type.cName[Type.VOID]); outputContext.hPrint(" (CFASTCALL *"); outputContext.hPrint(nextDummyEntryName()); outputContext.hPrint(")( "); outputContext.hPrint(Type.cName[Type.VOID]); outputContext.hPrint(" );"); if (!isNotInstantated()) { Term.assertCond(vTableUsed); outputContext.cPrint(",\010"); outputContext.cPrint("0"); } } boolean isReflectedField(String fieldName) { return reflectedFieldNames != null && reflectedFieldNames.contains(fieldName); } private boolean hasReflectedStaticFields(boolean isNonPrimOnly) { Term.assertCond(used); if (reflectedFieldNames != null) { Enumeration en = reflectedFieldNames.elements(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(en.nextElement()); Term.assertCond(v != null && v.used()); if (v.isClassVariable() && (!isNonPrimOnly || v.exprType().objectSize() >= Type.CLASSINTERFACE)) return true; } } return false; } private int buildIfacesArrContent(StringBuffer sb) { int ifaceCnt = 0; Enumeration en = specifiedInterfaces.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.vTableUsed) { if (cd.used) { sb.append('(').append(Type.cName[Type.CLASSINTERFACE]) .append(')'); sb.append(cd.getClassRefStr(false)).append(", "); ifaceCnt++; } else { ifaceCnt += cd.buildIfacesArrContent(sb); } } } return ifaceCnt; } private void writeClassVariables() { Term.assertCond(used); ClassDefinition classClassDefn = Main.dict.get(Names.JAVA_LANG_CLASS); if (vTableUsed) { outputContext.cPrint("};\n\n"); boolean isNonGc = false; boolean allowConst = false; if (name.equals(Names.JAVA_LANG_STRING)) { classClassDefn.writeInstanceDefinition(outputContext); outputContext.cPrint("JCGO_NOSEP_GCDATA "); } else if (Main.dict.allowConstClass >= 0 && !hasReflectedStaticFields(true)) { outputContext.cPrint("JCGO_NOSEP_DATA "); isNonGc = true; if (classInitializers == null && Main.dict.allowConstClass > 0 && !hasReflectedStaticFields(false)) { allowConst = true; outputContext.cPrint("JCGO_NOTHR_CONST "); } } else { outputContext.cPrint("JCGO_NOSEP_GCDATA "); } outputContext.cAndHPrint("struct "); outputContext.cAndHPrint(cname); outputContext.cAndHPrint("_class_s"); outputContext.cPrint(" "); outputContext.cPrint(cname); outputContext.cPrint("__class"); outputContext.cPrint(allowConst ? " JCGO_THRD_ATTRNONGC" : isNonGc ? " ATTRIBNONGC" : " ATTRIBGCDATA"); outputContext.cPrint("="); outputContext.cAndHPrint("{"); outputContext.hPrint("struct "); outputContext.hPrint(classClassDefn.cname); outputContext.hPrint("_s jcgo_class;"); outputContext.cPrint("{&"); outputContext.cPrint(classClassDefn.vTableCName()); outputContext.cPrint(",\010"); outputContext.cPrint("JCGO_MON_INIT\010"); outputContext.cPrint("JCGO_OBJREF_OF(*("); outputContext.cPrint(Main.dict.get(Names.JAVA_LANG_OBJECT).cname); outputContext.cPrint(")&"); outputContext.cPrint(vTableCName()); outputContext.cPrint("),\010"); outputContext.cPrint(Main.dict.classNameStringOutput(name, this, false)); outputContext.cPrint(",\010"); outputContext .cPrint(!isInterface() && superClass != null ? superClass .getClassRefStr(false) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); StringBuffer sb = new StringBuffer(); int ifaceCnt = buildIfacesArrContent(sb); outputContext.cPrint(addImmutableArray(classClassDefn, sb.toString(), ifaceCnt)); outputContext.cPrint(",\010"); outputContext.cPrint("0x"); outputContext.cPrint(Integer .toHexString((isAbstractOrInterface() ? modifiers | AccModifier.ABSTRACT : modifiers) | (classInitializers != null ? AccModifier.VOLATILE | AccModifier.TRANSIENT : 0) | (isEnum() ? AccModifier.ENUM : 0))); outputContext.cPrint("}"); if (reflectedFieldNames != null) { VariableDefinition[] fields = new VariableDefinition[reflectedFieldNames .size()]; int size = 0; Enumeration en2 = fieldDictionary.keys(); while (en2.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(en2.nextElement()); if (v.used() && v.isClassVariable() && reflectedFieldNames.contains(v.id())) { fields[size++] = v; } } VariableDefinition.sortBySize(fields, size); for (int i = 0; i < size; i++) { outputContext.cPrint(",\010"); fields[i].outputClassVar(outputContext, true); } } outputContext.cAndHPrint("};\n\n"); outputContext.hPrint("JCGO_SEP_EXTERN CONST struct "); outputContext.hPrint(isNotInstantated() ? "jcgo_methods_s " : vTableCName() + "_s "); outputContext.hPrint(vTableCName()); outputContext.hPrint(";"); outputContext.hPrint(isNonGc ? "JCGO_SEP_EXTERN" : "JCGO_SEP_GCEXTERN"); if (allowConst) { outputContext.hPrint(" JCGO_NOTHR_CONST"); } outputContext.hPrint(" struct "); outputContext.hPrint(cname); outputContext.hPrint("_class_s "); outputContext.hPrint(cname); outputContext.hPrint("__class;\n\n"); if (classInitializers != null) { if (name.equals(Names.JAVA_LANG_STRING)) { outputContext.hPrint("JCGO_SEP_GCEXTERN"); outputContext.cPrint("JCGO_NOSEP_GCDATA"); outputContext.cAndHPrint(" int jcgo_initialized"); outputContext.cPrint(" ATTRIBGCBSS= 0"); outputContext.cAndHPrint(";\n\n"); } outputContext.hPrint("JCGO_NOSEP_STATIC "); outputContext.hPrint(Type.cName[Type.VOID]); outputContext.hPrint(" CFASTCALL\n"); outputContext.hPrint(clinitCName()); outputContext.hPrint("( "); outputContext.hPrint(Type.cName[Type.VOID]); outputContext.hPrint(" );\n\n"); } } int size = fieldDictionary().size(); if (size > 0) { Enumeration en = fieldDictionary.keys(); VariableDefinition[] fields = new VariableDefinition[size]; size = 0; while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) fieldDictionary .get(en.nextElement()); if (v.used() && v.isClassVariable() && !v.isLiteral() && (reflectedFieldNames == null || !reflectedFieldNames .contains(v.id()))) { fields[size++] = v; } } VariableDefinition.sortBySize(fields, size); for (int i = 0; i < size; i++) { fields[i].outputClassVar(outputContext, false); outputContext.cPrint(";\n\n"); } if (size > 0) { outputContext.hPrint("\n\n"); } } if (classClassDefn != this) { writeInstanceDefinition(outputContext); } } private boolean isEnum() { Term.assertCond(used); VariableDefinition v; return superClass != null && superClass.name.equals(Names.JAVA_LANG_ENUM) && (v = (VariableDefinition) fieldDictionary.get("$VALUES")) != null && v.isPrivate() && v.isClassVariable() && v.isFinalVariable(); } private void writeInstanceDefinition(OutputContext oc) { Term.assertCond(used); oc.hPrint("struct "); oc.hPrint(cname); oc.hPrint("_s{"); oc.hPrint("CONST struct "); oc.hPrint(cname); oc.hPrint("_methods_s *JCGO_IMMFLD_CONST jcgo_methods;"); oc.hPrint("JCGO_MON_DEFN\010"); printInstanceDefinition(oc); oc.hPrint("};\n\n"); } private void outputCoreClasses() { ClassDefinition classClassDefn = Main.dict.get(Names.JAVA_LANG_CLASS); ArrayLiteral noIfacesArr = Main.dict.addArrayLiteral(new ArrayLiteral( classClassDefn, "", 0, false), this, false); StringBuffer sb = new StringBuffer(); int cnt = 0; ClassDefinition cd = Main.dict.get(Names.JAVA_LANG_CLONEABLE); if (cd.used) { sb.append('(').append(Type.cName[Type.CLASSINTERFACE]).append(')'); sb.append(cd.getClassRefStr(false)).append(", "); cnt++; } cd = Main.dict.get(Names.JAVA_IO_SERIALIZABLE); if (cd.used) { sb.append('(').append(Type.cName[Type.CLASSINTERFACE]).append(')'); sb.append(cd.getClassRefStr(false)).append(", "); cnt++; } ArrayLiteral arrayIfacesArr = Main.dict.addArrayLiteral( new ArrayLiteral(classClassDefn, sb.toString(), cnt, false), this, false); if (Main.dict.allowConstClass >= 0) { outputContext.hPrint("JCGO_SEP_EXTERN"); outputContext.cPrint("JCGO_NOSEP_DATA"); if (Main.dict.allowConstClass > 0) { outputContext.cAndHPrint(" JCGO_NOTHR_CONST"); } } else { outputContext.hPrint("JCGO_SEP_GCEXTERN"); outputContext.cPrint("JCGO_NOSEP_GCDATA"); } outputContext.cAndHPrint(" struct "); outputContext.cAndHPrint(classClassDefn.cname); outputContext.cAndHPrint("_s jcgo_coreClasses[OBJT_jarray+OBJT_"); outputContext.cAndHPrint(Type.cName[Type.VOID]); outputContext.cAndHPrint("-1]"); outputContext.hPrint(";\n\n"); outputContext .cPrint(Main.dict.allowConstClass > 0 ? " JCGO_THRD_ATTRNONGC" : Main.dict.allowConstClass == 0 ? " ATTRIBNONGC" : " ATTRIBGCDATA"); outputContext.cPrint("={"); boolean next = false; boolean isArray = false; boolean createNames = Main.dict .isClassNameUsed(Main.dict.classTable[Type.CLASSINTERFACE + Type.BOOLEAN]); int type = Type.BOOLEAN; do { do { if (next) { if (isArray && type == Type.VOID) break; outputContext.cPrint(","); } next = true; outputContext.cPrint("{&"); outputContext.cPrint(classClassDefn.vTableCName()); outputContext.cPrint(",\010"); outputContext.cPrint("JCGO_MON_INIT\010"); if (type == Type.NULLREF) { outputContext.cPrint(LexTerm.NULL_STR); outputContext.cPrint(", "); outputContext.cPrint(LexTerm.NULL_STR); outputContext.cPrint(", "); outputContext.cPrint(LexTerm.NULL_STR); outputContext.cPrint(", "); outputContext.cPrint(LexTerm.NULL_STR); outputContext.cPrint(", 0"); } else { outputContext.cPrint("JCGO_OBJREF_OF(*("); outputContext.cPrint(cname); outputContext.cPrint(")&"); outputContext .cPrint(Main.dict.classTable[isArray ? Type.CLASSINTERFACE + type : type].vTableCName()); outputContext.cPrint("),\010"); outputContext.cPrint(Main.dict.classNameStringOutput( isArray ? Type.sig[Type.CLASSINTERFACE + type] : Type.name[type], this, createNames)); outputContext.cPrint(",\010"); outputContext.cPrint(isArray ? Main.dict.classTable[type] .getClassRefStr(false) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint((isArray ? arrayIfacesArr : noIfacesArr).stringOutput()); outputContext.cPrint(",\010"); outputContext.cPrint("0x"); outputContext.cPrint(Integer.toHexString(AccModifier.PUBLIC | AccModifier.FINAL | AccModifier.ABSTRACT)); } outputContext.cPrint("}"); } while (++type <= Type.VOID); if (isArray) break; type = Type.NULLREF; isArray = true; } while (true); outputContext.cPrint("};\n\n"); outputContext.hPrint("JCGO_SEP_EXTERN"); outputContext.cPrint("JCGO_NOSEP_DATA"); outputContext.cAndHPrint(" CONST struct "); outputContext.cAndHPrint(classClassDefn.cname); outputContext.cAndHPrint("_s jcgo_objArrStubClasses["); outputContext.cAndHPrint(Integer.toString(MAX_DIMS)); outputContext.cAndHPrint("]"); outputContext.hPrint(";\n\n"); outputContext.cPrint("={"); for (int dims = 0; dims < MAX_DIMS; dims++) { if (dims > 0) { outputContext.cPrint(","); } outputContext.cPrint("{&"); outputContext.cPrint(classClassDefn.vTableCName()); outputContext.cPrint(",\010"); outputContext.cPrint("JCGO_MON_INIT\010"); outputContext.cPrint("JCGO_OBJREF_OF(*("); outputContext.cPrint(cname); outputContext.cPrint(")&"); outputContext.cPrint(arrayVTableCName(Type.VOID, dims)); outputContext.cPrint("),\010"); outputContext.cPrint(LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint(getClassRefStr(false)); outputContext.cPrint(",\010"); outputContext.cPrint(arrayIfacesArr.stringOutput()); outputContext.cPrint(",\010"); outputContext.cPrint("0x"); outputContext.cPrint(Integer.toHexString(AccModifier.FINAL | AccModifier.ABSTRACT)); outputContext.cPrint("}"); } outputContext.cPrint("};\n\n"); } private void printInstanceDefinition(OutputContext oc) { if (superClass != null) { superClass.printInstanceDefinition(oc); } if (used) { oc.hPrint(outputContext.instanceToString()); } } private void outputReflectionInfo() { Term.assertCond(used); int count = 0; if (reflectedMethods != null && (count = reflectedMethods.size()) > 0) { if (count == 1 && reflectedFieldNames == null && basicConstructor != null && basicConstructor.isPublic() && !isAbstractOrInterface()) { reflectedMethods = null; return; } outputContext .cPrint("JCGO_NOSEP_DATA CONST struct jcgo_methodentry_s "); outputContext.cPrint(cname); outputContext.cPrint("__abstract["); outputContext.cPrint(Integer.toString(count)); outputContext.cPrint("]={"); Enumeration en = methodDictionary().keys(); boolean next = false; while (en.hasMoreElements()) { MethodDefinition md = (MethodDefinition) reflectedMethods .get((String) en.nextElement()); if (md != null) { Term.assertCond(md.used()); Main.dict.message("Reflecting method: " + name + "." + md.methodSignature().getInfo()); if (next) { outputContext.cPrint(",\010"); } outputContext.cPrint("{"); outputContext.cPrint(Main.dict.methodProxyStringOutput(md)); outputContext.cPrint(",\010"); outputContext.cPrint("("); outputContext.cPrint(Type.cName[Type.VOID]); outputContext.cPrint(" (CFASTCALL*)("); outputContext.cPrint(Type.cName[Type.VOID]); outputContext.cPrint("))"); outputContext.cPrint(md.allowOverride() && !md.isConstructor() ? "JCGO_OFFSET_OF(struct " + vTableCName() + "_s, " + md.csign() + ")" : md .routineCName()); outputContext.cPrint("}"); next = true; } } outputContext.cPrint("};\n\n"); } outputContext.cPrint("JCGO_NOSEP_DATA CONST struct jcgo_reflect_s "); outputContext.cPrint(cname); outputContext.cPrint("__transient={"); StringBuffer namesSBuf = null; StringBuffer slotsSBuf = null; StringBuffer typesSBuf = null; StringBuffer dimsSBuf = null; StringBuffer modsSBuf = null; if (reflectedFieldNames != null) { namesSBuf = new StringBuffer(); slotsSBuf = new StringBuffer(); typesSBuf = new StringBuffer(); dimsSBuf = new StringBuffer(); modsSBuf = new StringBuffer(); boolean hasDims = false; boolean hasMods = false; count = 0; StringBuffer infoSBuf = null; Enumeration en = fieldDictionary().keys(); while (en.hasMoreElements()) { String fieldName = (String) en.nextElement(); VariableDefinition v = (VariableDefinition) fieldDictionary .get(fieldName); if (v.used() && reflectedFieldNames.contains(fieldName)) { if (infoSBuf != null) { infoSBuf.append(", "); } else { infoSBuf = new StringBuffer(); infoSBuf.append("Reflected fields for ").append(name) .append(": "); } infoSBuf.append(fieldName); namesSBuf.append('('); namesSBuf.append(Type.cName[Type.CLASSINTERFACE]); namesSBuf.append(')'); namesSBuf.append(Main.dict .addStringLiteral(fieldName, this).stringOutput()); namesSBuf.append(", "); slotsSBuf.append(v.fieldOffsetStr()); slotsSBuf.append(",\010"); typesSBuf.append('('); typesSBuf.append(Type.cName[Type.CLASSINTERFACE]); typesSBuf.append(')'); ClassDefinition signClass = v.exprType().signatureClass(); int dims = v.exprType().signatureDimensions(); if (dims == 1 && signClass.objectSize() < Type.CLASSINTERFACE) { typesSBuf.append(signClass.getClassRefStr(true)); dims--; } else { typesSBuf.append(signClass.getClassRefStr(false)); } typesSBuf.append(",\010"); dimsSBuf.append('('); dimsSBuf.append(Type.cName[Type.BYTE]); dimsSBuf.append(')'); dimsSBuf.append(Integer.toString(dims)); dimsSBuf.append(", "); if (dims > 0) { hasDims = true; } modsSBuf.append('('); modsSBuf.append(Type.cName[Type.SHORT]); int mods = v.getJavaModifiers(); if (superClass != null && superClass.name.equals(Names.JAVA_LANG_ENUM) && isEnumValueField(v)) { mods |= AccModifier.ENUM; } modsSBuf.append(")0x"); modsSBuf.append(Integer.toHexString(mods)); modsSBuf.append(", "); if ((isInterface() ? AccModifier.PUBLIC | AccModifier.STATIC | AccModifier.FINAL : 0) != mods) { hasMods = true; } count++; } } if (infoSBuf != null) { Main.dict.message(infoSBuf.toString()); } if (!hasDims) { dimsSBuf = null; } if (!hasMods) { modsSBuf = null; } } outputContext.cPrint(namesSBuf != null ? addImmutableArray( Main.dict.get(Names.JAVA_LANG_STRING), namesSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint(slotsSBuf != null ? addImmutableArray( Main.dict.classTable[Type.INT], slotsSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint(typesSBuf != null ? addImmutableArray( Main.dict.get(Names.JAVA_LANG_CLASS), typesSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint(dimsSBuf != null ? addImmutableArray( Main.dict.classTable[Type.BYTE], dimsSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint(modsSBuf != null ? addImmutableArray( Main.dict.classTable[Type.SHORT], modsSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); namesSBuf = null; typesSBuf = null; dimsSBuf = null; boolean dimsPresent = false; StringBuffer throwsSBuf = null; boolean throwsPresent = false; modsSBuf = null; if (reflectedMethods != null) { count = 0; namesSBuf = new StringBuffer(); typesSBuf = new StringBuffer(); dimsSBuf = new StringBuffer(); throwsSBuf = new StringBuffer(); modsSBuf = new StringBuffer(); boolean hasNames = false; boolean hasMods = false; Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = (MethodDefinition) reflectedMethods .get((String) en.nextElement()); if (md != null) { Term.assertCond(md.used()); boolean isConstr = md.isConstructor(); if (isConstr) { namesSBuf.append(LexTerm.NULL_STR); } else { namesSBuf.append('('); namesSBuf.append(Type.cName[Type.CLASSINTERFACE]); namesSBuf.append(')'); namesSBuf.append(Main.dict.addStringLiteral(md.id(), this).stringOutput()); hasNames = true; } namesSBuf.append(", "); if ((!isConstr && md.exprType().objectSize() != Type.VOID) || md.hasParameters()) { StringBuffer sb = new StringBuffer(); StringBuffer sb2 = new StringBuffer(); int cnt = 0; boolean hasDims = false; Enumeration en2 = md.methodSignature().elements(); boolean noMore = false; do { ExpressionType exprType; if (en2.hasMoreElements()) { exprType = (ExpressionType) en2.nextElement(); } else { if (isConstr) break; exprType = md.exprType(); noMore = true; } sb.append('('); sb.append(Type.cName[Type.CLASSINTERFACE]); sb.append(')'); ClassDefinition signClass = exprType .signatureClass(); int dims = exprType.signatureDimensions(); if (dims == 1 && signClass.objectSize() < Type.CLASSINTERFACE) { sb.append(signClass.getClassRefStr(true)); dims--; } else { sb.append(signClass.getClassRefStr(false)); } sb.append(",\010"); sb2.append('('); sb2.append(Type.cName[Type.BYTE]); sb2.append(')'); sb2.append(Integer.toString(dims)); sb2.append(", "); cnt++; if (dims > 0) { hasDims = true; } } while (!noMore); typesSBuf.append('('); typesSBuf.append(Type.cName[Type.CLASSINTERFACE]); typesSBuf.append(')'); typesSBuf.append(addImmutableArray( Main.dict.get(Names.JAVA_LANG_CLASS), sb.toString(), cnt)); if (hasDims) { dimsPresent = true; dimsSBuf.append('('); dimsSBuf.append(Type.cName[Type.CLASSINTERFACE]); dimsSBuf.append(')'); dimsSBuf.append(addImmutableArray( Main.dict.classTable[Type.BYTE], sb2.toString(), cnt)); } else { dimsSBuf.append(LexTerm.NULL_STR); } } else { typesSBuf.append(LexTerm.NULL_STR); dimsSBuf.append(LexTerm.NULL_STR); } typesSBuf.append(", "); dimsSBuf.append(", "); Enumeration en2 = md.thrownClassesElements(); if (en2.hasMoreElements()) { StringBuffer sb = new StringBuffer(); int cnt = 0; do { sb.append('('); sb.append(Type.cName[Type.CLASSINTERFACE]); sb.append(')'); sb.append(((ClassDefinition) en2.nextElement()) .getClassRefStr(false)); sb.append(",\010"); cnt++; } while (en2.hasMoreElements()); throwsPresent = true; throwsSBuf.append('('); throwsSBuf.append(Type.cName[Type.CLASSINTERFACE]); throwsSBuf.append(')'); throwsSBuf.append(addImmutableArray( Main.dict.get(Names.JAVA_LANG_CLASS), sb.toString(), cnt)); } else { throwsSBuf.append(LexTerm.NULL_STR); } throwsSBuf.append(",\010"); modsSBuf.append('('); modsSBuf.append(Type.cName[Type.SHORT]); int mods = md.getJavaModifiers(); modsSBuf.append(")0x"); modsSBuf.append(Integer.toHexString(mods)); modsSBuf.append(", "); if ((isInterface() ? AccModifier.PUBLIC | AccModifier.ABSTRACT : AccModifier.PUBLIC) != mods) { hasMods = true; } count++; } } if (!hasNames) { namesSBuf = null; } if (!hasMods) { modsSBuf = null; } } outputContext.cPrint(namesSBuf != null ? addImmutableArray( Main.dict.get(Names.JAVA_LANG_STRING), namesSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint(typesSBuf != null ? addImmutableArray(Main.dict .get(Names.JAVA_LANG_CLASS).asExprType(1), typesSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint(dimsPresent ? addImmutableArray( Main.dict.classTable[Type.BYTE].asExprType(1), dimsSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint(throwsPresent ? addImmutableArray( Main.dict.get(Names.JAVA_LANG_CLASS).asExprType(1), throwsSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); outputContext.cPrint(modsSBuf != null ? addImmutableArray( Main.dict.classTable[Type.SHORT], modsSBuf.toString(), count) : LexTerm.NULL_STR); outputContext.cPrint(",\010"); if (reflectedMethods != null && reflectedMethods.size() > 0) { outputContext.cPrint(cname); outputContext.cPrint("__abstract"); } else { outputContext.cPrint("NULL"); } outputContext.cPrint("};\n\n"); } private boolean hasPrimInstanceFields() { Enumeration en = fieldDictionary().unorderedElements(); while (en.hasMoreElements()) { VariableDefinition v = (VariableDefinition) en.nextElement(); if (v.used() && !v.isClassVariable() && v.exprType().objectSize() < Type.CLASSINTERFACE) return true; } return superClass != null && superClass.hasPrimInstanceFields(); } private void startMethodDefinitions() { Term.assertCond(used); Enumeration en = methodDictionary().unorderedElements(); while (en.hasMoreElements()) { MethodDefinition md = (MethodDefinition) en.nextElement(); if (md.isNative() && md.usedExact()) { outputContext.hPrint("#define JCGO_NATCLASS_"); outputContext.hPrint(jniname); outputContext.hPrint("\n\n"); break; } } outputContext.hPrint("struct "); outputContext.hPrint(cname); outputContext.hPrint("_methods_s{"); outputContext.hPrint(Main.dict.get(Names.JAVA_LANG_CLASS).cname); outputContext.hPrint(" jcgo_class;"); outputContext.hPrint("JCGO_GCJDESCR_DEFN\010"); outputContext .hPrint("JCGO_TYPEID_T jcgo_typeid;JCGO_OBJSIZE_T jcgo_objsize;"); outputContext.hPrint("CONST struct jcgo_reflect_s *jcgo_reflect;"); outputContext.hPrint("JCGO_CLINIT_DEFN\010"); outputContext.hPrint(cname); outputContext.hPrint(" (CFASTCALL *jcgo_thisRtn)( "); outputContext.hPrint(cname); outputContext.hPrint(" This );"); if (vTableUsed) { outputContext.cPrint("JCGO_NOSEP_DATA CONST struct "); outputContext.cPrint(isNotInstantated() ? "jcgo_methods_s " : vTableCName() + "_s "); outputContext.cPrint(vTableCName()); outputContext.cPrint("={"); outputContext.cPrint(getClassRefStr(false)); outputContext.cPrint(",\010"); if (lastObjectRefField != null && !isNotInstantated() && hasPrimInstanceFields()) { outputContext.cPrint("JCGO_GCJDESCR_INIT("); outputContext.cPrint(cname); outputContext.cPrint("_s, "); outputContext.cPrint(lastObjectRefField.outputName()); outputContext.cPrint(")\010"); } else { outputContext.cPrint("JCGO_GCJDESCR_ZEROINIT\010"); } outputContext.cPrint("OBJT_"); outputContext.cPrint(cname); outputContext.cPrint(",\010"); if (isNotInstantated()) { outputContext.cPrint("0"); } else { if (lastObjectRefField == null) { outputContext.cPrint("-"); } outputContext.cPrint("(JCGO_OBJSIZE_T)sizeof(struct "); outputContext.cPrint(cname); outputContext.cPrint("_s)"); } outputContext.cPrint(",\010"); if (reflectedFieldNames != null || reflectedMethods != null) { outputContext.cPrint("&"); outputContext.cPrint(cname); outputContext.cPrint("__transient"); } else { outputContext.cPrint("NULL"); } outputContext.cPrint(",\010"); outputContext.cPrint("JCGO_CLINIT_INIT("); outputContext.cPrint(classInitializers != null ? clinitCName() : "0"); outputContext.cPrint(")\010"); if (basicConstructor != null && reflectedMethods == null && basicConstructor.used() && !basicConstructor.isPrivate()) { if (isNotInstantated()) { outputContext.cPrint("("); outputContext.cPrint(Type.cName[Type.CLASSINTERFACE]); outputContext.cPrint(" (CFASTCALL*)("); outputContext.cPrint(Type.cName[Type.CLASSINTERFACE]); outputContext.cPrint("))"); } outputContext.cPrint(basicConstructor.routineCName()); } else { outputContext.cPrint("0"); } } } boolean writeTrigClinit(OutputContext oc) { Term.assertCond(used); if (classInitializers == null) return false; oc.cPrint("JCGO_CLINIT_TRIG("); oc.cPrint(cname); oc.cPrint("__class);"); return true; } private void coreMethodDefinitions(OutputContext oc, int type, int dims) { oc.hPrint("JCGO_SEP_EXTERN"); oc.cPrint("JCGO_NOSEP_DATA"); oc.cAndHPrint(" CONST struct "); oc.cAndHPrint(vTableCName() + "_s "); oc.cAndHPrint(arrayVTableCName(type, dims)); oc.hPrint(";"); String typeStr = "OBJT_jarray+OBJT_" + Type.cName[type] + (dims > 0 ? "+" + Integer.toString(dims) : ""); oc.cPrint("={"); if (type < Type.VOID) { oc.cPrint("JCGO_CORECLASS_FOR("); oc.cPrint(typeStr); oc.cPrint("),\010"); } else { oc.cPrint("("); oc.cPrint(Main.dict.get(Names.JAVA_LANG_CLASS).cname); oc.cPrint(")JCGO_OBJREF_OF(jcgo_objArrStubClasses["); oc.cPrint(Integer.toString(dims)); oc.cPrint("]),\010"); } oc.cPrint("JCGO_GCJDESCR_ZEROINIT\010"); oc.cPrint(typeStr); oc.cPrint(",\010"); oc.cPrint("0,\010"); oc.cPrint("NULL,\010"); oc.cPrint("JCGO_CLINIT_INIT(0)\010"); oc.cPrint("0"); Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.isVirtualUsed()) { oc.cPrint(",\010"); oc.cPrint(md.isAbstract() ? "0" : md.routineCName()); } } oc.cPrint("};\n\n"); } private void writeClassTableArray(OutputContext oc) { ObjHashSet classnames = new ObjHashSet(); createSubclassList(classnames); String[] names = new String[classnames.size()]; Enumeration en = classnames.elements(); for (int i = 0; en.hasMoreElements(); i++) { names[i] = (String) en.nextElement(); } names = sortStrings(names, names.length); oc.cPrint("JCGO_NOSEP_DATA CONST JCGO_STATIC_OBJARRAY("); oc.cPrint(Integer.toString(names.length)); oc.cPrint(") jcgo_classTable={(jvtable)&"); oc.cPrint(Main.dict.classTable[Type.OBJECTARRAY].vTableCName()); oc.cPrint(",\010"); oc.cPrint("JCGO_MON_INIT\010"); oc.cPrint(Integer.toString(names.length)); oc.cPrint(",\010"); oc.cPrint(Main.dict.get(Names.JAVA_LANG_CLASS).getClassRefStr(false)); oc.cPrint(",\010"); oc.cPrint("{"); for (int i = 0; i < names.length; i++) { if (i > 0) { oc.cPrint(",\010"); } oc.cPrint("("); oc.cPrint(Type.cName[Type.CLASSINTERFACE]); oc.cPrint(")"); oc.cPrint(Main.dict.get(names[i]).getClassRefStr(false)); } oc.cPrint("}};\n\n"); } void buildMain(boolean skipClinitTrace) { OutputContext oc = new OutputContext("Main"); ClassDefinition objectClassDefn = Main.dict.get(Names.JAVA_LANG_OBJECT); oc.cPrint("#define "); oc.cPrint(Main.VER_ABBR); oc.cPrint("\n\n"); oc.cPrint("#include \"jcgortl.h\"\n\n"); oc.cAndHPrint("#ifdef "); oc.cPrint("JCGO_VER"); oc.hPrint(Main.VER_ABBR); oc.cAndHPrint("\n\n"); oc.cPrint("#include \"Main.h\"\n\n"); oc.cPrint("#ifndef JCGO_MAIN_SEP\n\n"); if (Main.dict.buildClassTable) { objectClassDefn.writeClassTableArray(oc); } Main.dict.writeInternedLiterals(oc); oc.cPrint("#endif\n\n"); oc.cPrint("#ifndef JCGO_SEPARATED\n"); objectClassDefn.enumerateClass(oc, Type.VOID, new ObjHashSet()); oc.cPrint("\n#endif"); oc.cAndHPrint("\n\n"); Main.dict.writeArrayTypeDefs(oc); objectClassDefn.addToHeaderFile(oc); oc.hPrint("\n\n"); oc.cPrint("#ifndef JCGO_MAIN_SEP\n\n"); for (int type = Type.BOOLEAN; type <= Type.DOUBLE; type++) { objectClassDefn.coreMethodDefinitions(oc, type, 0); } for (int dims = 0; dims < MAX_DIMS; dims++) { objectClassDefn.coreMethodDefinitions(oc, Type.VOID, dims); } oc.hPrint("\n\n"); oc.hPrint("#endif\n"); oc.cPrint("EXTRASTATIC "); oc.cPrint(Type.cName[Type.OBJECTARRAY]); oc.cPrint(" CFASTCALL jcgo_tpostInit( void **targv );\n\n"); oc.cPrint("EXTRASTATIC "); oc.cPrint(Type.cName[Type.VOID]); oc.cPrint(" CFASTCALL jcgo_destroyJavaVM( "); oc.cPrint(Type.cName[Type.CLASSINTERFACE]); oc.cPrint(" throwable );\n\n"); oc.cPrint("#ifdef JCGO_SEHTRY\n"); oc.cPrint("EXTRASTATIC "); oc.cPrint(Type.cName[Type.CLASSINTERFACE]); oc.cPrint(" CFASTCALL jcgo_tryCatchAll( "); oc.cPrint(Type.cName[Type.VOID]); oc.cPrint(" );"); oc.cPrint("#endif\n\n"); oc.cPrint("EXTRASTATIC "); oc.cPrint(Type.cName[Type.VOID]); oc.cPrint(" jcgo_tmainBody( void **targv ){"); ClassDefinition throwableClassDefn = Main.dict .get(Names.JAVA_LANG_THROWABLE); if (throwableClassDefn.used) { oc.cPrint(Type.cName[Type.CLASSINTERFACE]); oc.cPrint(" throwable;"); oc.cPrint("{JCGO_TRY_BLOCK{"); } MethodDefinition mdMain = getMethod(Names.SIGN_MAIN); if (mdMain != null && mdMain.used()) { oc.cPrint(mdMain.routineCName()); } oc.cPrint("(jcgo_tpostInit(targv));"); if (throwableClassDefn.used) { oc.cPrint("}"); oc.cPrint("JCGO_TRY_LEAVE\010"); oc.cPrint("JCGO_TRY_CATCHALLSTORE(&throwable)\010"); oc.cPrint("}"); } oc.cPrint("jcgo_destroyJavaVM("); oc.cPrint(throwableClassDefn.used ? "throwable" : LexTerm.NULL_STR); oc.cPrint(");}\n\n"); if (mdMain == null || !mdMain.used() || !mdMain.isFirstParamUsed()) { oc.cPrint("#define JCGO_MAINARGS_NOTUSED\n\n"); } oc.hCloseOnly(); oc.cPrint("#ifndef JCGO_STDCLINIT\n\n"); if (skipClinitTrace) { System.out.println("Class init order not evaluated!"); oc.cPrint(" % Class init order not evaluated!"); } else { oc.cPrint("JCGO_NOSEP_INLINE "); oc.cPrint(Type.cName[Type.VOID]); oc.cPrint(" CFASTCALL\n"); oc.cPrint("jcgo_initClasses( "); oc.cPrint(Type.cName[Type.VOID]); oc.cPrint(" ){"); Main.dict.writeClassInitCalls(oc); oc.cPrint("}"); } oc.cPrint("\n\n"); oc.cPrint("#endif\n\n"); oc.cPrint("#include \"jcgortl.c\"\n\n"); oc.cPrint("MAINENTRY\n( int argc, JCGO_MAIN_TCHAR **targv ){"); oc.cPrint("JCGO_MAIN_LAUNCH(argc, targv);"); oc.cPrint("return 0;}\n\n"); oc.cPrint("#endif\n\n"); oc.cPrint("#endif\n"); oc.close(); } private String addImmutableArray(ExpressionType exprType, String data, int count) { return Main.dict.addArrayLiteral( new ArrayLiteral(exprType, data, count, false), this, false) .stringOutput(); } void addArrayLiteral(ArrayLiteral liter) { Term.assertCond(used); if (arrpool == null) { arrpool = new ObjQueue(); } arrpool.addLast(liter); } void addLiteral(LiteralStr liter) { Term.assertCond(used); if (strpool == null) { strpool = new ObjQueue(); } strpool.addLast(liter); } void addMethodProxy(MethodProxy mproxy) { Term.assertCond(used); if (mproxypool == null) { mproxypool = new ObjQueue(); } mproxypool.addLast(mproxy); } private void outputPool() { if (mproxypool != null) { Enumeration en = mproxypool.elements(); while (en.hasMoreElements()) { ((MethodProxy) en.nextElement()).processOutput(outputContext); } mproxypool = null; } if (strpool != null) { Enumeration en = strpool.elements(); while (en.hasMoreElements()) { ((LiteralStr) en.nextElement()).initArrayLiteral(this); } } if (arrpool != null) { Enumeration en = arrpool.elements(); while (en.hasMoreElements()) { ((ArrayLiteral) en.nextElement()).processOutput(outputContext, this); } arrpool = null; } if (strpool != null) { Enumeration en = strpool.elements(); while (en.hasMoreElements()) { ((LiteralStr) en.nextElement()).processOutput(outputContext); } strpool = null; } } void traceReflectedConstructor(boolean declaredOnly, String sigString, boolean isExactType) { if (sigString != null && !sigString.equals("<init>(*)")) { MethodDefinition md = getMethodNoInheritance(sigString); if (md != null && md.isConstructor() && (declaredOnly || !md.isPrivate())) { md.methodTraceClassInit(true, null, null); } } else { Enumeration en = methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = getMethodNoInheritance((String) en .nextElement()); if (md.isConstructor() && (declaredOnly || !md.isPrivate())) { md.methodTraceClassInit(true, null, null); } } } if (!isExactType && reflectConstructorsInherit(sigString)) { if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { cd.traceReflectedConstructor(declaredOnly, sigString, false); } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used || isInterface()) { cd.traceReflectedConstructor(declaredOnly, sigString, false); } } } } void traceReflectedMethod(String methodId, boolean declaredOnly, ObjVector parmSig) { if (methodId != null && parmSig != null) { MethodDefinition md = getMethod(new MethodSignature(methodId, parmSig)); if (md != null) { if (!md.isConstructor() && (declaredOnly ? md.definingClass() == this : !md .isPrivate())) { md.methodTraceClassInit(true, this, null); } } else { if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { cd.traceReflectedMethod(methodId, declaredOnly, parmSig); } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used || isInterface()) { cd.traceReflectedMethod(methodId, declaredOnly, parmSig); } } } } else { ClassDefinition cd = this; do { Enumeration en = cd.methodDictionary().keys(); while (en.hasMoreElements()) { MethodDefinition md = cd.getMethodNoInheritance((String) en .nextElement()); if (!md.isConstructor() && (methodId == null || methodId.equals(md.id())) && (parmSig == null || md.methodSignature() .isSignEqual(parmSig)) && (declaredOnly ? md.definingClass() == this : !md .isPrivate())) { md.methodTraceClassInit(true, this, null); } } } while (!declaredOnly && (cd = cd.superClass()) != null && (!isInterface() || !cd.name .equals(Names.JAVA_LANG_OBJECT))); } } ExpressionType traceClInitInSubclasses(String sigString, String pkgName, boolean isWeak, ObjVector parmTraceSig) { ExpressionType curTraceType = Main.dict.classTable[Type.NULLREF]; if (implementedBy != null) { Enumeration en = implementedBy.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (cd.used) { ExpressionType curType; MethodDefinition md = cd.getMethod(sigString); if (md != null && !md.isAbstract()) { curType = md.methodTraceClassInit(isWeak, cd, parmTraceSig); if (curType == null) { curType = md.exprType(); } } else { curType = cd.traceClInitInSubclasses(sigString, null, isWeak, parmTraceSig); } curTraceType = maxCommonExprOf(curTraceType, curType, null); } } } Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); ExpressionType curType; MethodDefinition md; if (cd.used && (md = cd.getMethodNoInheritance(sigString)) != null && !md.isAbstract() && (pkgName == null || pkgName.equals(cd.getPackageName()))) { curType = md.methodTraceClassInit(isWeak, null, parmTraceSig); if (curType == null) { curType = md.exprType(); } } else { curType = cd.traceClInitInSubclasses(sigString, pkgName, isWeak, parmTraceSig); } curTraceType = maxCommonExprOf(curTraceType, curType, null); } return curTraceType; } void instanceTraceClassInit() { if (hasInstances && used && instanceInitializers != null) { instanceInitializers.traceClassInit(); } } private boolean isBasicConstructorNormal() { return basicConstructor != null && basicConstructor.used() && basicConstructor.isPublic() && !isAbstractOrInterface(); } boolean constructorTraceClassInit(boolean isWeak) { if (basicConstructor == null) return false; basicConstructor.methodTraceClassInit(isWeak, null, null); return true; } void constructorTraceClassInitInSubclasses() { Enumeration en = subclasses.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()) .constructorTraceClassInit(true); } } void classTraceForSupers() { Term.assertCond(used); if (isInterface()) return; ClassDefinition sc = superClass(); while (sc != null) { sc.classTraceClassInit(true); sc = sc.superClass(); } Enumeration en = interfaceClasses(null).elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()).classTraceClassInit(true); } } void classTraceClassInit(boolean isWeak) { if (used && classInitializers != null) { Main.dict.curTraceInfo.addClassInitDepend(isWeak, this); } } boolean noInstanceYetOnTrace() { return !hasInstances || !used || (finished && !Main.dict.instancesCreatedOnTrace .contains(this)); } void instanceCreatedOnTrace() { if (hasInstances && used && finished) { ClassDefinition cd = this; while (Main.dict.instancesCreatedOnTrace.add(cd)) { ObjQueue traceInfos; if (Main.dict.notYetCallableTraceInfos != null && (traceInfos = (ObjQueue) Main.dict.notYetCallableTraceInfos .remove(cd)) != null) Main.dict.pendingTraceInfos.addAllMovedFrom(traceInfos); Enumeration en = cd.specifiedInterfaces.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()) .instanceCreatedOnTrace(); } if (isInterface() || (cd = cd.superClass()) == null || !cd.finished) break; } } } private void buildClassInitTrace() { ObjHashtable processed = new ObjHashtable(); Main.dict.notYetCallableTraceInfos = new ObjHashtable(); Main.dict.dynCallerTraceInfos = new OrderedMap(); int oldDynCount = Main.dict.dynClassesToTrace.size(); recursiveTracing(processed); int dynCount; while ((dynCount = Main.dict.dynClassesToTrace.size()) > oldDynCount) { for (int i = 0; Main.dict.dynCallerTraceInfos.size() > i; i++) { recursiveTracingInner( (MethodTraceInfo) Main.dict.dynCallerTraceInfos .keyAt(i), processed); } oldDynCount = dynCount; } Main.dict.notYetCallableTraceInfos = null; Main.dict.dynCallerTraceInfos = null; } private void createTraceInfo() { if (clinitTraceInfo == null) { Term.assertCond(classInitializers != null); Main.dict.message("Analyzing class initializer: " + name); clinitTraceInfo = MethodTraceInfo.create(null, this, null); Main.dict.curTraceInfo = clinitTraceInfo; classInitializers.traceClassInit(); clinitTraceInfo.doneMethodTracing(Main.dict.classTable[Type.VOID]); } } private void recursiveTracing(ObjHashtable processed) { createTraceInfo(); recursiveTracing(clinitTraceInfo, processed); if (!isInterface() && superClass != null && superClass.classInitializers != null) { superClass.recursiveTracing(processed); } } private static void recursiveTracing(MethodTraceInfo traceInfo, ObjHashtable processed) { if (traceInfo.addToProcessed(processed)) { if (traceInfo.isCallableNow()) { recursiveTracingInner(traceInfo, processed); } else { ExpressionType expr = traceInfo.curThisClass(); Term.assertCond(expr != null); ClassDefinition cd = expr.receiverClass(); ObjQueue traceInfos = (ObjQueue) Main.dict.notYetCallableTraceInfos .get(cd); if (traceInfos == null) { Main.dict.notYetCallableTraceInfos.put(cd, traceInfos = new ObjQueue()); } traceInfos.addLast(traceInfo); } } } private static void recursiveTracingInner(MethodTraceInfo traceInfo, ObjHashtable processed) { traceInfo.setInstanceCreated(); traceInfo.traceMethod(); while (!Main.dict.pendingTraceInfos.isEmpty()) { recursiveTracingInner( (MethodTraceInfo) Main.dict.pendingTraceInfos.removeFirst(), processed); } boolean isWeak = false; do { Enumeration en = traceInfo.getCalledInfosElements(isWeak); while (en.hasMoreElements()) { recursiveTracing((MethodTraceInfo) en.nextElement(), processed); } if (isWeak) break; isWeak = true; } while (true); if (traceInfo.usesDynClasses()) { ClassDefinition[] dynClasses = new ClassDefinition[Main.dict.dynClassesToTrace .size()]; Main.dict.dynClassesToTrace.copyKeysInto(dynClasses); for (int i = 0; i < dynClasses.length; i++) { if (dynClasses[i].isBasicConstructorNormal()) { recursiveTracing(MethodTraceInfo.create( dynClasses[i].basicConstructor, null, null), processed); } } Main.dict.dynCallerTraceInfos.put(traceInfo, traceInfo); } isWeak = false; do { ClassDefinition cd; for (int i = 0; (cd = traceInfo.getClassDependElementAt(isWeak, i)) != null; i++) { cd.recursiveTracing(processed); } if (isWeak) break; isWeak = true; } while (true); ClassDefinition cd = traceInfo.getDefiningClassDepend(); if (cd != null) { cd.recursiveTracing(processed); } } private void collectClassInitDepend(ObjHashtable classToInstancesMap) { ObjHashSet curInstancesCreatedOnTrace = (ObjHashSet) classToInstancesMap .get(this); if (curInstancesCreatedOnTrace == null) { Term.assertCond(clinitTraceInfo != null && classInitializers != null); if (classInitDepend == null) { classInitDepend = new OrderedMap(); if (!isInterface() && superClass != null && superClass.classInitializers != null) { classInitDepend.put(superClass, new ConstValue(-1 >>> 1)); } } curInstancesCreatedOnTrace = new ObjHashSet(); classToInstancesMap.put(this, curInstancesCreatedOnTrace); ObjHashSet oldInstancesCreatedOnTrace = Main.dict.instancesCreatedOnTrace; Main.dict.instancesCreatedOnTrace = curInstancesCreatedOnTrace; int oldInstCount = 0; ObjHashtable processed = new ObjHashtable(); ObjVector traceInfos = new ObjVector(); do { processed.clear(); traceInfos.addElement(clinitTraceInfo); collectClassInitDepend(traceInfos, 0, processed); Term.assertCond(traceInfos.size() == 1); for (int j = 0; classInitDepend.size() > j; j++) { ((ClassDefinition) classInitDepend.keyAt(j)) .collectClassInitDepend(classToInstancesMap); } int instCount = curInstancesCreatedOnTrace.size(); if (instCount == oldInstCount) break; oldInstCount = instCount; traceInfos.removeElementAt(0); } while (true); Main.dict.instancesCreatedOnTrace = oldInstancesCreatedOnTrace; } Enumeration en = curInstancesCreatedOnTrace.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()).instanceCreatedOnTrace(); } } private void collectClassInitDepend(ObjVector traceInfos, int weakness, ObjHashtable processed) { MethodTraceInfo traceInfo = (MethodTraceInfo) traceInfos .elementAt(traceInfos.size() - 1); if (traceInfo.addToProcessed(processed) && traceInfo.isCallableNow()) { traceInfo.setInstanceCreated(); boolean isWeak = false; do { ClassDefinition cd; for (int i = 0; (cd = traceInfo.getClassDependElementAt(isWeak, i)) != null; i++) { if (cd != this) { recordClassInitDepend(cd, weakness, traceInfos); } } if (isWeak) break; weakness++; isWeak = true; } while (true); ClassDefinition cd = traceInfo.getDefiningClassDepend(); if (cd != null && cd != this) { recordClassInitDepend(cd, weakness + 2, traceInfos); } weakness--; isWeak = false; do { Enumeration en = traceInfo.getCalledInfosElements(isWeak); while (en.hasMoreElements()) { traceInfos.addElement(en.nextElement()); collectClassInitDepend(traceInfos, weakness, processed); traceInfos.removeElementAt(traceInfos.size() - 1); } if (isWeak) break; weakness++; isWeak = true; } while (true); if (traceInfo.usesDynClasses()) { Enumeration en = Main.dict.dynClassesToTrace.keys(); while (en.hasMoreElements()) { cd = (ClassDefinition) en.nextElement(); if (cd.isBasicConstructorNormal()) { traceInfos.addElement(MethodTraceInfo.create( cd.basicConstructor, null, null)); collectClassInitDepend(traceInfos, weakness, processed); traceInfos.removeElementAt(traceInfos.size() - 1); } } } } } private void recordClassInitDepend(ClassDefinition cd, int weakness, ObjVector traceInfos) { Term.assertCond(classInitializers != null && cd.classInitializers != null); if (superClass != cd && !isInterface() && superClass != null && superClass.getSubclassDepth(cd, null) > 0) { Term.assertCond(superClass.classInitializers != null); if (superClass.classInitDepend == null) { superClass.classInitDepend = new OrderedMap(); } superClass.recordClassInitDepend(cd, weakness, traceInfos); cd = superClass; } ConstValue constVal = (ConstValue) classInitDepend.get(cd); if (constVal == null || constVal.getIntValue() > weakness) { classInitDepend.put(cd, new ConstValue(weakness)); if (Main.dict.verboseTracing) { Main.dict.message("Clinit dependency: " + name + " -> " + cd.name); int i = traceInfos.size(); while (i-- > 0) { Main.dict.message(" Called from: " + ((MethodTraceInfo) traceInfos.elementAt(i)) .getTraceSig()); } } } } void printClassInitGroup(OutputContext oc) { if (used && classInitializers != null) { Enumeration en = Main.dict.instancesCreatedOnTrace.elements(); while (en.hasMoreElements()) { ((ClassDefinition) en.nextElement()).finished = false; } Main.dict.instancesCreatedOnTrace = new ObjHashSet(); buildClassInitTrace(); Main.dict.message("Grouping initializers for: " + name + " (" + Integer.toString(Main.dict.tracedInfosCount) + " methods traced)"); Main.dict.tracedInfosCount = 0; collectClassInitDepend(new ObjHashtable()); oc.cPrint("{"); ObjHashSet clinitBeginSet = new ObjHashSet(); if (!printClassInitSimpleWithSub(oc, clinitBeginSet)) { ObjVector cdRoots = new ObjVector(); cdRoots.addElement(this); breakClassInitWeakCycles(cdRoots, (-1 >>> 1) - 1); int i = 0; do { if (((ClassDefinition) cdRoots.elementAt(i)) .printClassInitSimpleWithSub(oc, clinitBeginSet)) { cdRoots.removeElementAt(i); } else { i++; } } while (cdRoots.size() > i); if (i > 0) { oc.cPrint(" ;"); breakClassInitWeakCycles(cdRoots, 0); ObjHashSet processed = new ObjHashSet(); i = 0; do { if (((ClassDefinition) cdRoots.elementAt(i)) .printClassInitSimple(oc, processed, null)) { cdRoots.removeElementAt(i); } else { i++; } } while (cdRoots.size() > i); Enumeration en2 = cdRoots.elements(); while (en2.hasMoreElements()) { ((ClassDefinition) en2.nextElement()) .printClassInitCyclic(oc, new ObjHashSet(), null); } } } oc.cPrint("}"); } } private boolean printClassInitSimpleWithSub(OutputContext oc, ObjHashSet clinitBeginSet) { ObjHashSet processed = new ObjHashSet(); do { processed.clear(); if (printClassInitSimple(oc, processed, clinitBeginSet)) return true; processed.clear(); } while (printClassInitForSubclasses(oc, processed, clinitBeginSet)); return false; } private boolean printClassInitForSubclasses(OutputContext oc, ObjHashSet processed, ObjHashSet clinitBeginSet) { if (classInitializers != null && processed.add(this)) { if (!isInterface() && superClass != null) { boolean depend = false; ClassDefinition sc = this; do { Enumeration en = sc.classInitDepend.keys(); ClassDefinition cd; while (en.hasMoreElements()) { if ((cd = (ClassDefinition) en.nextElement()) != sc.superClass && cd.classInitializers != null) { if (cd.getSubclassDepth(sc, null) <= 0) { depend = true; break; } if (sc == this) return cd.printClassInitForSubclasses(oc, processed, clinitBeginSet); if (cd != this && getSubclassDepth(cd, null) <= 0) { depend = true; break; } } } } while (!depend && (sc = sc.superClass) != null && sc.classInitializers != null); if (!depend && superClass.classInitializers != null) { printOneClassInitWithSuper(oc, clinitBeginSet); return true; } } Enumeration en = classInitDepend.keys(); while (en.hasMoreElements()) { if (((ClassDefinition) en.nextElement()) .printClassInitForSubclasses(oc, processed, clinitBeginSet)) return true; } } return false; } private boolean printClassInitSimple(OutputContext oc, ObjHashSet processed, ObjHashSet clinitBeginSet) { Term.assertCond(used); if (classInitializers != null) { if (!processed.add(this)) return false; Term.assertCond(classInitDepend != null); boolean full = true; Enumeration en = classInitDepend.keys(); while (en.hasMoreElements()) { ClassDefinition cd = (ClassDefinition) en.nextElement(); if (!cd.printClassInitSimple(oc, processed, clinitBeginSet) && (clinitBeginSet == null || !clinitBeginSet.contains(cd) || ((ConstValue) classInitDepend .get(cd)).getIntValue() == 0)) { full = false; } } if (!full) return false; printOneClassInit(oc, null, clinitBeginSet); } return true; } private ClassDefinition printClassInitCyclic(OutputContext oc, ObjHashSet commented, ClassDefinition prevCommented) { Term.assertCond(used); if (classInitializers == null) return prevCommented; if (headerWritten) { headerWritten = false; Enumeration en = classInitDepend.keys(); while (en.hasMoreElements()) { prevCommented = ((ClassDefinition) en.nextElement()) .printClassInitCyclic(oc, commented, prevCommented); } headerWritten = true; printOneClassInit(oc, null, null); } else if (this != prevCommented) { printOneClassInit(oc, commented, null); } return this; } private void printOneClassInitWithSuper(OutputContext oc, ObjHashSet clinitBeginSet) { if (!isInterface() && superClass != null && superClass.classInitializers != null) { if (clinitBeginSet.add(this)) { oc.cPrint("JCGO_CLINIT_BEGIN(" + cname + "__class);"); } superClass.printOneClassInitWithSuper(oc, clinitBeginSet); } printOneClassInit(oc, null, null); } private void printOneClassInit(OutputContext oc, ObjHashSet commented, ObjHashSet clinitBeginSet) { Term.assertCond(classInitializers != null); if (commented != null) { if (commented.add(this)) { System.out.println("Warning: cannot detect class init order: " + name); } oc.cPrint("/" + "*"); } else if (clinitBeginSet != null && !isInterface() && superClass != null && superClass.classInitializers != null && clinitBeginSet.add(superClass)) { oc.cPrint("JCGO_CLINIT_BEGIN(" + superClass.cname + "__class);"); } oc.cPrint(clinitCName()); oc.cPrint("()"); if (commented != null) { oc.cPrint("*" + "/"); } oc.cPrint(";"); if (commented == null) { classInitializers = null; } } private static void breakClassInitWeakCycles(ObjVector cdRoots, int nonWeakMax) { int i = 0; do { ((ClassDefinition) cdRoots.elementAt(i)).breakClassInitWeakCycles( cdRoots, nonWeakMax, new ObjVector(), new ObjHashSet()); } while (++i < cdRoots.size()); } private void breakClassInitWeakCycles(ObjVector cdRoots, int nonWeakMax, ObjVector cdStack, ObjHashSet processed) { if (classInitializers != null) { int i = cdStack.identityLastIndexOf(this); if (i >= 0) { int j = cdStack.size(); int k = -1; ClassDefinition cdNext = this; ClassDefinition cd; do { cd = (ClassDefinition) cdStack.elementAt(--j); ConstValue constVal = (ConstValue) cd.classInitDepend .get(cdNext); if (constVal == null) return; int weakness = constVal.getIntValue(); if (nonWeakMax < weakness) { nonWeakMax = weakness; k = j; } } while ((cdNext = cd) != this); if (k >= 0) { if (cdStack.size() - 1 > k) { cdNext = (ClassDefinition) cdStack.elementAt(k + 1); if (i > 0) { cd = (ClassDefinition) cdStack.elementAt(i - 1); ConstValue weaknessVal = (ConstValue) cd.classInitDepend .get(this); if (weaknessVal == null) return; ConstValue constVal = (ConstValue) cd.classInitDepend .get(cdNext); if (constVal == null || constVal.getIntValue() > weaknessVal .getIntValue()) { cd.classInitDepend.put(cdNext, weaknessVal); } } } if (cdRoots.identityLastIndexOf(cdNext) < 0) { cdRoots.addElement(cdNext); } ((ClassDefinition) cdStack.elementAt(k)).classInitDepend .remove(cdNext); } } else if (processed.add(this)) { cdStack.addElement(this); for (int j = 0; classInitDepend.size() > j; j++) { ((ClassDefinition) classInitDepend.keyAt(j)) .breakClassInitWeakCycles(cdRoots, nonWeakMax, cdStack, processed); } cdStack.removeElementAt(cdStack.size() - 1); } } } }