mirror of
https://github.com/2003scape/deep-c-rsc.git
synced 2024-03-22 05:49:51 -04:00
5608 lines
217 KiB
Java
5608 lines
217 KiB
Java
/*
|
|
* @(#) $(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);
|
|
}
|
|
}
|
|
}
|
|
}
|