deep-c-rsc/JCGO/jtrsrc/com/ivmaisoft/jcgo/MethodInvocation.java
2021-07-16 17:12:20 -05:00

1081 lines
44 KiB
Java

/*
* @(#) $(JCGO)/jtrsrc/com/ivmaisoft/jcgo/MethodInvocation.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;
/**
* Grammar production for normal and primary method calls.
**
* Formats: QualifiedName LPAREN [ArgumentList] RPAREN Primary DOT ID LPAREN
* [ArgumentList] RPAREN Super DOT ID LPAREN [ArgumentList] RPAREN
*/
final class MethodInvocation extends LexNode {
private ClassDefinition resultClass;
private ClassDefinition actualClass;
private boolean isExact;
private MethodDefinition md;
private MethodDefinition actualMethod;
private String resultString;
private ExpressionType classLiteralValue;
private int rcvr;
private ExpressionType reflectedClass;
private boolean reflectInSuper;
private String reflectedMethodId;
private ObjVector reflectedParmSig;
private boolean forceCheck;
private LeftBrace noLeaksScope;
private boolean noStackObjRet;
private boolean isConditional;
private String stackObjCode;
private boolean needsLocalVolatile;
private boolean isVoidExpr;
MethodInvocation(Term a, Term c) {
super(a, Empty.newTerm(), c);
}
MethodInvocation(Term a, Term c, Term e) {
super(a, c, e);
}
MethodInvocation(Context c, ClassDefinition resultClass, String id,
Term exprTerm) {
super(Empty.newTerm(), Empty.newTerm(), (new Argument(exprTerm, true))
.setLineInfoFrom(exprTerm));
assertCond(c.currentClass != null);
setLineInfoFrom(exprTerm);
this.resultClass = resultClass;
processPassOneInner(c, null, resultClass, 0, id);
if (md != null && !md.isClassMethod()) {
undefinedMethod(resultClass, md.methodSignature(), c);
}
}
MethodInvocation(Context c, Term t, String id) {
super(t, Empty.newTerm(), Empty.newTerm());
assertCond(c.currentClass != null);
setLineInfoFrom(t);
resultClass = t.exprType().receiverClass();
processPassOneInner(c, null, t.actualExprType(), 0, id);
if (md != null && md.exprType().objectSize() != Type.CLASSINTERFACE) {
undefinedMethod(resultClass, md.methodSignature(), c);
}
}
void processPass1(Context c) {
if (resultClass == null) {
assertCond(c.currentClass != null);
if ((c.forceVmExc & ClassDefinition.NULL_PTR_EXC) != 0) {
forceCheck = true;
}
ClassDefinition aclass;
int vecSize;
String id;
BranchContext oldBranch = c.saveBranch();
if (terms[1].notEmpty()) {
terms[0].processPass1(c);
resultClass = terms[0].exprType().receiverClass();
aclass = null;
vecSize = 0;
id = terms[1].dottedName();
} else {
ObjVector vec = new ObjVector();
terms[0].storeDottedName(vec);
aclass = terms[0].defineClass(c, vec);
vecSize = vec.size();
id = (String) vec.elementAt(vecSize - 1);
}
if (terms[0].isSafeExpr()) {
oldBranch = c.swapBranch(oldBranch);
terms[2].processPass1(c);
c.unionBranch(oldBranch);
} else {
terms[2].processPass1(c);
}
processPassOneInner(c, aclass, terms[0].actualExprType(), vecSize,
id);
}
}
private void processPassOneInner(Context c, ClassDefinition aclass,
ExpressionType actualType0, int vecSize, String id) {
if (vecSize == 0) {
MethodSignature msig = new MethodSignature(id,
terms[2].getSignature());
if (resultClass.objectSize() < Type.CLASSINTERFACE) {
fatalError(c, "Primitive type cannot be dereferenced: "
+ resultClass.name());
return;
}
md = resultClass.matchMethod(msig, c.forClass);
if (md == null) {
undefinedMethod(resultClass, msig, c);
return;
}
if (terms[0].isSuper(false)) {
if (md.isAbstract()) {
fatalError(c, "Abstract method is called: " + md.id());
}
isExact = true;
}
actualClass = resultClass;
actualMethod = md;
if (!md.isClassMethod() && actualType0.objectSize() != Type.NULLREF) {
actualClass = actualType0.receiverClass();
if (actualType0 != actualClass
&& actualType0.objectSize() == Type.CLASSINTERFACE) {
isExact = true;
}
if (actualClass != resultClass && md.allowOverride()) {
actualClass.define(c.forClass);
actualMethod = actualClass.getSameMethod(md);
if (actualMethod == null) {
actualClass = resultClass;
actualMethod = md;
}
}
}
} else if (vecSize > 1) {
if (aclass == null) {
fatalError(c,
"Undefined qualified name: " + terms[0].dottedName());
resultString = VariableDefinition.UNKNOWN_NAME;
resultClass = c.currentClass;
return;
}
actualClass = actualType0.receiverClass();
if (actualType0 != actualClass
&& actualType0.objectSize() == Type.CLASSINTERFACE) {
isExact = true;
}
MethodSignature msig = new MethodSignature(id,
terms[2].getSignature());
resultClass = aclass;
md = aclass.matchMethod(msig, c.forClass);
if (md == null) {
undefinedMethod(aclass, msig, c);
return;
}
assertCond(actualClass != null);
actualMethod = md;
if (actualType0.objectSize() != Type.NULLREF) {
actualClass.define(c.forClass);
if (md.allowOverride()
&& (actualMethod = actualClass.getSameMethod(md)) == null) {
actualClass = resultClass;
actualMethod = md;
}
} else {
actualClass = aclass;
}
} else {
MethodSignature msig = new MethodSignature(id,
terms[2].getSignature());
resultClass = c.currentClass;
resultString = This.CNAME;
while ((md = resultClass.matchMethod(msig, c.forClass)) == null) {
VariableDefinition outerV = resultClass.outerThisRef();
if (outerV != null) {
outerV.markUsed();
resultString = outerV.stringOutput(resultString, 1, false);
}
resultClass = resultClass.outerClass();
if (resultClass == null) {
undefinedMethod(c.currentClass, msig, c);
resultClass = c.currentClass;
return;
}
}
if (!md.isClassMethod() && c.currentMethod != null
&& c.currentMethod.isClassMethod()) {
fatalError(c,
"Instance method used in a static context: " + md.id());
}
actualClass = resultClass;
actualMethod = md;
}
boolean useMethodBranch = false;
if (c.currentClass.superClass() != null
|| md.used()
|| !md.definingClass().name().equals(Names.JAVA_LANG_VMCLASS)
|| !md.isExactMatch(true, Names.JAVA_LANG_CLASS, 0,
Names.SIGN_ARRAYCLASSOF0X)) {
if (isExact && !md.isClassMethod()) {
actualMethod.markUsedThisOnly();
} else {
actualMethod.markUsed(actualClass,
c.containsAccessedClass(actualMethod.definingClass()));
}
if (!c.currentClass.name().equals(
Names.JAVAX_SWING_UIDEFAULTS_PROXYLAZYVALUE)) {
processReflection(c.currentClass, c.forClass);
}
VariableDefinition v = md.isClassMethod() ? null : terms[0]
.getVariable(false);
if (!actualMethod.isNative()
|| !Names
.isVMCoreClass(actualMethod.definingClass().name())) {
if (md.isClassMethod()) {
c.addAccessedClass(md.definingClass());
} else if (!actualClass.isInterface()) {
c.addAccessedClass(actualClass);
} else if (!resultClass.isInterface()) {
c.addAccessedClass(resultClass);
}
if (isExact || !actualMethod.allowOverride()) {
actualMethod.processBranch(c,
v == VariableDefinition.THIS_VAR);
useMethodBranch = true;
}
}
if (v != null) {
c.setVarNotNull(v);
}
noLeaksScope = c.localScope;
isConditional = c.isConditional;
}
actualMethod.incCallsCount(c.currentMethod);
actualMethod.setArgsFormalType(terms[2], useMethodBranch ? c : null);
}
ExpressionType exprType() {
assertCond(resultClass != null);
return md != null ? md.exprType() : Main.dict.classTable[Type.VOID];
}
ExpressionType actualExprType() {
assertCond(resultClass != null);
return actualMethod != null
&& (isExact || !actualMethod.allowOverride()) ? actualMethod
.actualExprType() : exprType();
}
boolean isNotNull() {
assertCond(resultClass != null);
return actualMethod != null
&& (isExact || !actualMethod.allowOverride())
&& actualMethod.isNotNull();
}
boolean isSwitchMapAssign(boolean isMethodCall) {
assertCond(resultClass != null);
VariableDefinition v = terms[0].getVariable(false);
return v != null
&& isMethodCall
&& actualMethod != null
&& actualMethod.definingClass().name()
.equals(Names.JAVA_LANG_ENUM)
&& !actualMethod.isClassMethod()
&& v.isClassVariable()
&& actualMethod.exprType().objectSize() == Type.INT
&& actualMethod.methodSignature().signatureString()
.equals(Names.SIGN_ORDINAL) && v.isFinalVariable();
}
MethodDefinition superMethodCall() {
return terms[0].isSuper(true) ? actualMethod : null;
}
String strLiteralValueGuess() {
assertCond(resultClass != null);
if (md != null) {
if (resultClass.name().equals(Names.JAVA_LANG_CLASS)) {
if (!md.isExactMatch(false, Names.JAVA_LANG_STRING, 0,
Names.SIGN_GETNAME))
return null;
ExpressionType exprType0 = terms[0].classLiteralValGuess();
if (exprType0 == null)
return null;
if (exprType0.signatureDimensions() > 0)
return exprType0.getJavaSignature();
ClassDefinition cd = exprType0.receiverClass();
return cd != exprType0 || cd.isFinal() ? cd.name() : null;
}
if (resultClass.name().equals(Names.JAVA_LANG_STRING)
&& md.isClassMethod()
&& actualMethod.id().equals(Names.VALUEOF))
return decodeFirstArgAsString();
}
return null;
}
ExpressionType classLiteralValGuess() {
assertCond(resultClass != null);
return classLiteralValue != null ? (classLiteralValue.receiverClass()
.isProxyClass() ? null : classLiteralValue)
: actualMethod != null ? actualMethod.classLiteralValGuess()
: null;
}
MethodInvocation getClassNewInstanceCall() {
assertCond(resultClass != null);
MethodInvocation mcall = null;
if (md != null
&& (mcall = actualMethod.getClassNewInstanceCall()) == null
&& (md.definingClass().name().equals(Names.JAVA_LANG_CLASS) ? md
.isExactMatch(false, Names.JAVA_LANG_OBJECT, 0,
Names.SIGN_NEWINSTANCE)
: actualMethod
.definingClass()
.name()
.equals(Names.GNU_CLASSPATH_SERVICEFACTORY_SERVICEITERATOR)
&& md.isExactMatch(false,
Names.JAVA_LANG_OBJECT, 0,
Names.SIGN_NEXT))) {
mcall = this;
}
return mcall;
}
MethodSignature getConstructorInstanceSign() {
assertCond(resultClass != null);
if (md == null)
return null;
MethodSignature msig = actualMethod.getConstructorInstanceSign();
if (msig != null)
return msig;
Term t = terms[2].getArgumentTerm(0);
if (t == null)
return null;
ObjVector parmSig;
String className = md.definingClass().name();
if (className.equals(Names.JAVA_LANG_CLASS)
&& (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_CONSTRUCTOR,
0, Names.SIGN_GETCONSTRUCTOR) || md.isExactMatch(false,
Names.JAVA_LANG_REFLECT_CONSTRUCTOR, 0,
Names.SIGN_GETDECLAREDCONSTRUCTOR))) {
parmSig = new ObjVector();
if (!t.storeClassLiteralsGuess(parmSig, false)
&& t.actualExprType().objectSize() != Type.NULLREF)
return null;
} else {
if (!className.equals(Names.JAVA_LANG_REFLECT_CONSTRUCTOR)
|| !md.isExactMatch(false, Names.JAVA_LANG_OBJECT, 0,
Names.SIGN_NEWINSTANCE_CTOR))
return null;
if ((msig = terms[0].getConstructorInstanceSign()) != null)
return msig;
parmSig = new ObjVector();
parmSig.addElement(Main.dict.classTable[Type.NULLREF]);
}
return new MethodSignature("<init>", parmSig);
}
void discoverObjLeaks() {
assertCond(resultClass != null);
terms[0].discoverObjLeaks();
if (actualMethod != null && actualMethod.used()) {
if (!isExact) {
while (actualMethod.allowOverride()) {
ClassDefinition cd = actualClass.getRealOurClass();
MethodDefinition md2;
if (cd != actualClass
&& (md2 = cd.getSameMethod(actualMethod)) != null) {
assertCond(md2.used());
actualClass = cd;
actualMethod = md2;
if (!actualMethod.allowOverride())
break;
}
if (!actualMethod.isAbstract())
break;
ClassDefinition[] cdArr = new ClassDefinition[1];
md2 = actualClass.getSingleRealMethodInSubclasses(
actualMethod, cdArr);
if (md2 == null)
break;
actualMethod = md2;
actualClass = cdArr[0];
assertCond(actualClass != null);
}
}
String sigString = actualMethod.methodSignature().signatureString();
if (!actualMethod.copyObjLeaksTo(terms[2]) && !isExact
&& actualMethod.allowOverride()) {
actualClass.copyObjLeaksInSubclasses(sigString, terms[2]);
}
if (actualMethod.hasThisObjLeak(false)
|| (!isExact && actualMethod.allowOverride() && actualClass
.hasThisObjLeakInSubclasses(sigString, false))) {
terms[0].setObjLeaks(null);
} else if (actualMethod.isThisStackObjVolatile()
|| (!isExact && actualMethod.allowOverride() && actualClass
.isThisStackObjVltInSubclasses(sigString))) {
terms[0].setStackObjVolatile();
}
if (!actualMethod.allowStackObjRet()
|| (!isExact && actualMethod.allowOverride() && actualClass
.subclassHasMethod(sigString, null))) {
noStackObjRet = true;
} else if (!actualMethod.stackObjRetRequired()) {
Main.dict.stackObjRetCalls.addLast(this);
}
}
terms[2].discoverObjLeaks();
}
void setStackObjVolatile() {
assertCond(resultClass != null);
if (actualMethod != null && actualMethod.used() && !needsLocalVolatile) {
needsLocalVolatile = true;
if (actualMethod.hasThisObjLeak(true)
|| (!isExact && actualMethod.allowOverride() && actualClass
.hasThisObjLeakInSubclasses(actualMethod
.methodSignature().signatureString(), true))) {
terms[0].setStackObjVolatile();
}
terms[2].setStackObjVolatile();
}
}
void setObjLeaks(VariableDefinition v) {
assertCond(resultClass != null);
if (actualMethod != null && actualMethod.used()) {
if (v != VariableDefinition.WRITABLE_ARRAY_VAR
&& (actualMethod.hasThisObjLeak(true) || (!isExact
&& actualMethod.allowOverride() && actualClass
.hasThisObjLeakInSubclasses(actualMethod
.methodSignature().signatureString(), true)))) {
terms[0].setObjLeaks(v);
}
terms[2].setObjLeaks(v);
noLeaksScope = VariableDefinition.addSetObjLeaksTerm(noLeaksScope,
v, this, isConditional || noStackObjRet);
if (noLeaksScope == null
|| v == VariableDefinition.WRITABLE_ARRAY_VAR) {
actualMethod.setWritableArray();
if (!isExact && actualMethod.allowOverride()) {
actualClass.setWritableArrayRetInSubclasses(actualMethod
.methodSignature().signatureString());
}
}
}
}
MethodDefinition getNoLeaksScopeMethod() {
return noLeaksScope != null && !noStackObjRet ? actualMethod : null;
}
MethodDefinition stackObjRetMethodCall() {
assertCond(actualMethod != null
&& (noLeaksScope == null || noStackObjRet));
return actualMethod;
}
int tokenCount() {
return terms[0].tokenCount() + terms[2].tokenCount()
+ (terms[0].isSafeExpr() ? 1 : 2);
}
void allocRcvr(int[] curRcvrs) {
if (actualMethod != null && actualMethod.used()) {
Term t0 = terms[0];
Term t2 = terms[2];
int[] curRcvrs1 = OutputContext.copyRcvrs(curRcvrs);
t0.allocRcvr(curRcvrs);
VariableDefinition v;
if (!actualMethod.isClassMethod()
&& ((t0.isSafeExpr() ? !t0.isNotNull()
&& ((v = t0.getVariable(true)) == null || !v
.isLocalOrParam()) && !t0.isImmutable()
: actualMethod.isAbstract()
|| !t2.isSafeExpr()
|| !t0.isNotNull()
|| t2.isFieldAccessed(null)
|| (!t2.isImmutable() && t0
.isAnyLocalVarChanged(null))
|| (!isExact
&& actualMethod.allowOverride() && actualClass
.subclassHasMethod(actualMethod
.methodSignature()
.signatureString(), null))) || (!t2
.isSafeWithThrow() && !t0.isImmutable() && (t0
.isFieldAccessed(null) || t2
.isAnyLocalVarChanged(t0))))) {
rcvr = ++curRcvrs1[Type.NULLREF];
}
if (!md.isClassMethod() && t2.notEmpty() && !t0.isNotNull()) {
int[] curRcvrs2 = OutputContext.copyRcvrs(curRcvrs1);
t2.markParamRcvr(-1, curRcvrs2);
t2.allocParamRcvr(curRcvrs1,
OutputContext.copyRcvrs(curRcvrs1), curRcvrs2);
} else {
t2.allocRcvr(curRcvrs1);
}
OutputContext.joinRcvrs(curRcvrs, curRcvrs1);
}
}
String writeStackObjDefn(OutputContext oc, boolean needsLocalVolatile) {
assertCond(actualMethod != null);
return actualMethod.writeStackObjDefn(oc, needsLocalVolatile);
}
void writeStackObjs(OutputContext oc, Term scopeTerm) {
if (actualMethod != null && actualMethod.used()) {
terms[0].writeStackObjs(oc, scopeTerm);
terms[2].writeStackObjs(oc, scopeTerm);
if (noLeaksScope == scopeTerm && !noStackObjRet) {
assertCond(scopeTerm != null);
stackObjCode = actualMethod.writeStackObjDefn(oc,
needsLocalVolatile);
}
}
}
void writeStackObjTrigClinit(OutputContext oc) {
assertCond(actualMethod != null);
actualMethod.writeStackObjTrigClinit(oc);
}
ExpressionType writeStackObjRetCode(OutputContext oc) {
assertCond(actualMethod != null
&& (noLeaksScope == null || noStackObjRet));
stackObjCode = MethodDefinition.STACKOBJ_RETNAME;
return actualMethod.writeStackObjRetCode(oc);
}
boolean isAtomary() {
return true;
}
void setVoidExpression() {
isVoidExpr = true;
}
void processOutput(OutputContext oc) {
assertCond(resultClass != null);
if (isVoidExpr
&& md != null
&& !md.isClassMethod()
&& md.exprType().objectSize() != Type.VOID
&& !terms[0].isSuper(false)
&& (!actualMethod.used() || (!isExact && !actualClass
.hasRealInstances()))) {
oc.cPrint("(");
oc.cPrint(Type.cName[Type.VOID]);
oc.cPrint(")");
}
oc.cPrint("(");
String rcvrStr = null;
if (rcvr > 0) {
rcvrStr = OutputContext.getRcvrName(rcvr, Type.CLASSINTERFACE);
oc.cPrint(rcvrStr);
oc.cPrint("= (");
oc.cPrint(Type.cName[Type.CLASSINTERFACE]);
oc.cPrint(")");
ExpressionType oldAssignmentRightType = oc.assignmentRightType;
oc.assignmentRightType = null;
terms[0].atomaryOutput(oc);
oc.assignmentRightType = oldAssignmentRightType;
oc.cPrint(", ");
}
boolean isSpec = false;
boolean rightParenNeeded = false;
String primaryStr = null;
if (md == null || md.isClassMethod() || terms[0].isSuper(false)) {
if (md != null && md.used()) {
terms[2].produceRcvr(oc);
}
if (!terms[0].isSafeExpr()) {
oc.cPrint("(");
oc.cPrint(Type.cName[Type.VOID]);
oc.cPrint(")");
if (rcvrStr != null) {
oc.cPrint(rcvrStr);
} else {
terms[0].atomaryOutput(oc);
}
oc.cPrint(", ");
}
if (md != null) {
if (md.used()) {
oc.cPrint(stackObjCode != null ? md
.stackObjRetRoutineCName() : md.routineCName());
} else {
assertCond(md.definingClass().name()
.equals(Names.JAVA_LANG_VMCLASS)
&& md.isExactMatch(true, Names.JAVA_LANG_CLASS, 0,
Names.SIGN_ARRAYCLASSOF0X));
}
} else {
oc.cPrint(MethodDefinition.UNKNOWN_NAME);
}
Main.dict.normalCalls++;
isSpec = true;
} else {
if (actualMethod.used() && actualClass.hasRealInstances()) {
terms[2].produceRcvr(oc);
}
rightParenNeeded = actualMethod
.writeMethodCall(
oc,
isExact ? null : actualClass,
(rcvrStr != null || actualClass != resultClass ? "("
+ actualClass.castName() + ")"
: "")
+ (rcvrStr != null ? rcvrStr
: resultString != null ? resultString
: actualClass == resultClass
|| terms[0]
.isAtomary() ? (primaryStr = terms[0]
.stringOutput())
: "("
+ (primaryStr = terms[0]
.stringOutput())
+ ")"),
terms[0].isNotNull() ? 1 : forceCheck ? -1 : 0,
stackObjCode != null, md.exprType());
}
if (isSpec || (actualMethod.used() && actualClass.hasRealInstances())) {
oc.cPrint("(");
if (md != null && !md.isClassMethod()) {
oc.cPrint("\010 ");
ClassDefinition cd = actualMethod.definingClass();
if (isSpec || rcvrStr != null || cd != resultClass) {
oc.cPrint("(");
oc.cPrint(cd.castName());
oc.cPrint(")");
}
if (resultString != null) {
oc.cPrint(resultString);
} else if (rcvrStr != null) {
oc.cPrint(rcvrStr);
} else if (primaryStr != null) {
if (cd == resultClass || terms[0].isAtomary()) {
oc.cPrint(primaryStr);
} else {
oc.cPrint("(");
oc.cPrint(primaryStr);
oc.cPrint(")");
}
} else if (cd != resultClass) {
terms[0].atomaryOutput(oc);
} else {
terms[0].processOutput(oc);
}
oc.parameterOutputAsArg(terms[2]);
} else if (md == null || md.used()) {
if (terms[2].notEmpty()) {
oc.cPrint("\010 ");
}
oc.cPrint(OutputContext
.paramStringOutputNoComma(terms[2], true));
} else {
oc.cPrint("(");
oc.cPrint(Type.cName[Type.VOID]);
oc.cPrint(")0");
terms[2].getTermAt(0).parameterOutput(oc, true, Type.NULLREF);
}
if (stackObjCode != null) {
assertCond(md != null);
if (!md.isClassMethod() || terms[2].notEmpty()) {
oc.cPrint(", ");
}
oc.cPrint(stackObjCode);
}
oc.cPrint(")");
}
if (rightParenNeeded) {
oc.cPrint(")");
}
oc.cPrint(")");
}
private void processReflection(ClassDefinition currentClass,
ClassDefinition forClass) {
if (!md.isPublic())
return;
String className = md.definingClass().name();
if (className.equals(Names.JAVA_LANG_REFLECT_PROXY)
&& (md.isExactMatch(true, Names.JAVA_LANG_CLASS, 0,
Names.SIGN_GETPROXYCLASS) || md.isExactMatch(true,
Names.JAVA_LANG_OBJECT, 0, Names.SIGN_NEWPROXYINSTANCE))) {
Term t = terms[2].getArgumentTerm(1);
if (t != null) {
ObjVector parmSig = new ObjVector();
if (t.storeClassLiteralsGuess(parmSig, false)) {
classLiteralValue = Main.dict.addProxyClass(parmSig,
forClass);
}
}
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_CLASS, 0,
Names.SIGN_GETCLASS)) {
ExpressionType actualType0 = terms[0].actualExprType();
if (isExact || actualType0.receiverClass().superClass() != null) {
classLiteralValue = actualType0;
}
if (actualType0.signatureClass().objectSize() == Type.CLASSINTERFACE
&& (actualType0.objectSize() == Type.OBJECTARRAY || (!isExact && actualType0
.receiverClass().superClass() == null))) {
Main.dict.get(Names.JAVA_LANG_VMCLASS).markUsed();
}
return;
}
if (!className.equals(Names.JAVA_LANG_CLASS))
return;
if (md.isExactMatch(false, Names.JAVA_LANG_STRING, 0,
Names.SIGN_GETNAME)) {
Main.dict
.addGetNameClass(terms[0].classLiteralValGuess(), forClass);
return;
}
boolean isForName2 = md.isExactMatch(true, Names.JAVA_LANG_CLASS, 0,
Names.SIGN_FORNAME_2);
if (isForName2
|| md.isExactMatch(true, Names.JAVA_LANG_CLASS, 0,
Names.SIGN_FORNAME)) {
ExpressionType exprType = decodeClassForNameArg(
decodeFirstArgAsString(), currentClass);
if (exprType != null) {
classLiteralValue = exprType;
ClassDefinition cd = exprType.signatureClass();
cd.predefineClass(forClass);
cd.markUsed();
Term t;
ConstValue constVal1;
if (exprType.signatureDimensions() == 0
&& (!isForName2 || ((t = terms[2].getArgumentTerm(1)) != null && ((constVal1 = t
.evaluateConstValue()) == null || constVal1
.isNonZero())))) {
reflectedClass = exprType;
}
}
return;
}
ExpressionType exprType = terms[0].classLiteralValGuess();
ClassDefinition literalClass;
boolean isExactType = false;
if (exprType != null) {
literalClass = null;
if (exprType.objectSize() == Type.CLASSINTERFACE) {
literalClass = exprType.receiverClass();
literalClass.define(forClass);
}
if (literalClass != exprType) {
isExactType = true;
}
if (literalClass != null) {
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_FIELD, 1,
Names.SIGN_GETDECLAREDFIELDS)) {
reflectedClass = literalClass.reflectAllFields(true);
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_FIELD, 1,
Names.SIGN_GETFIELDS)) {
reflectedClass = literalClass.reflectAllFields(false);
reflectInSuper = true;
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_CONSTRUCTOR,
1, Names.SIGN_GETDECLAREDCONSTRUCTORS)) {
reflectConstructors(literalClass, true, null, isExactType);
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_CONSTRUCTOR,
1, Names.SIGN_GETCONSTRUCTORS)) {
reflectConstructors(literalClass, false, null, isExactType);
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_CONSTRUCTOR,
0, Names.SIGN_GETDECLAREDCONSTRUCTOR)) {
reflectConstructors(literalClass, true,
decodeArgAsClassArray(0), isExactType);
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_CONSTRUCTOR,
0, Names.SIGN_GETCONSTRUCTOR)) {
reflectConstructors(literalClass, false,
decodeArgAsClassArray(0), isExactType);
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_METHOD, 1,
Names.SIGN_GETDECLAREDMETHODS)) {
reflectMethods(literalClass, true, null, null, isExactType);
return;
}
if (isExactType
&& md.isExactMatch(false, Names.JAVA_LANG_OBJECT, 0,
Names.SIGN_NEWINSTANCE)) {
reflectConstructors(literalClass, true, new ObjVector(),
true);
return;
}
} else {
literalClass = Main.dict.get(Names.JAVA_LANG_OBJECT);
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_METHOD, 1,
Names.SIGN_GETMETHODS)) {
reflectMethods(literalClass, false, null, null, isExactType);
return;
}
} else {
literalClass = Main.dict.get(Names.JAVA_LANG_OBJECT);
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_FIELD, 0,
Names.SIGN_GETDECLAREDFIELD)) {
String name = decodeFirstArgAsString();
reflectedClass = name != null ? literalClass.reflectField(name,
true, isExactType) : literalClass.reflectAllFields(true);
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_FIELD, 0,
Names.SIGN_GETFIELD)) {
String name = decodeFirstArgAsString();
if (name != null) {
reflectedClass = literalClass.reflectField(name, false,
isExactType);
} else {
reflectedClass = literalClass.reflectAllFields(false);
reflectInSuper = true;
}
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_METHOD, 0,
Names.SIGN_GETDECLAREDMETHOD)) {
reflectMethods(literalClass, true, decodeFirstArgAsString(),
decodeArgAsClassArray(1), isExactType);
return;
}
if (md.isExactMatch(false, Names.JAVA_LANG_REFLECT_METHOD, 0,
Names.SIGN_GETMETHOD)) {
reflectMethods(literalClass, false, decodeFirstArgAsString(),
decodeArgAsClassArray(1), isExactType);
}
}
private String decodeFirstArgAsString() {
Term t = terms[2].getArgumentTerm(0);
return t != null ? t.strLiteralValueGuess() : null;
}
private ObjVector decodeArgAsClassArray(int index) {
Term t = terms[2].getArgumentTerm(index);
if (t == null)
return null;
ObjVector parmSig = new ObjVector();
return t.storeClassLiteralsGuess(parmSig, false)
|| t.actualExprType().objectSize() == Type.NULLREF ? parmSig
: null;
}
void reflectConstructors(ClassDefinition literalClass) {
reflectConstructors(literalClass, false, new ObjVector(), false);
}
private void reflectConstructors(ClassDefinition literalClass,
boolean declaredOnly, ObjVector parmSig, boolean isExactType) {
if (reflectedMethodId == null) {
literalClass.reflectConstructors(
declaredOnly,
parmSig != null ? (new MethodSignature("<init>", parmSig))
.signatureString() : null, isExactType);
reflectedClass = isExactType ? literalClass.asExactClassType()
: literalClass;
reflectedMethodId = "<init>";
reflectedParmSig = parmSig;
reflectInSuper = !declaredOnly;
}
}
private void reflectMethods(ClassDefinition literalClass,
boolean declaredOnly, String id, ObjVector parmSig,
boolean isExactType) {
if (reflectedMethodId == null) {
if (id != null && id.length() == 0) {
id = null;
}
literalClass.reflectMethods(id, declaredOnly, parmSig, isExactType);
reflectedClass = literalClass;
reflectedMethodId = id != null ? id : "";
reflectedParmSig = parmSig;
reflectInSuper = !declaredOnly;
}
}
static ExpressionType decodeClassForNameArg(String str,
ClassDefinition curClass) {
if (str == null)
return null;
int dims = 0;
char ch;
int len = str.length();
do {
if (dims >= len)
return null;
ch = str.charAt(dims);
if (ch != '[')
break;
dims++;
} while (true);
if (dims > 0) {
if (ch != 'L') {
if (len - 1 == dims) {
for (int type = Type.BOOLEAN; type < Type.VOID; type++) {
if (Type.sig[type].charAt(0) == ch)
return Main.dict.classTable[type].asExprType(dims);
}
}
return null;
}
if (len - 1 <= dims || str.charAt(len - 1) != ';')
return null;
str = str.substring(dims + 1, len - 1);
}
if ((curClass != null && !Main.dict.alreadyKnown(str) && (str.indexOf(
'.', 0) < 0 ? curClass.name().indexOf('.', 0) >= 0 : !str
.startsWith(curClass.getPackageName() + ".")))
|| !Main.dict.existsOrInner(str))
return null;
ClassDefinition cd = Main.dict.get(str);
return dims > 0 ? cd.asExprType(dims) : cd.asExactClassType();
}
private void traceReflected() {
if (classLiteralValue != null) {
Main.dict.addDynClassToTrace(classLiteralValue.signatureClass());
}
if (reflectedClass != null) {
ClassDefinition cd = reflectedClass.signatureClass();
MethodDefinition md2;
if ((md2 = Main.dict.curHelperForMethod) != null
&& md2.isClassMethod() && md2.id().equals("initIDs")) {
cd.classTraceClassInit(true);
} else if (reflectedMethodId != null) {
if (reflectedMethodId.equals("<init>")) {
cd.traceReflectedConstructor(
!reflectInSuper,
reflectedParmSig != null ? (new MethodSignature(
"<init>", reflectedParmSig))
.signatureString() : null,
reflectedClass != cd);
} else {
cd.traceReflectedMethod(
reflectedMethodId.length() > 0 ? reflectedMethodId
: null, !reflectInSuper, reflectedParmSig);
}
} else {
cd.classTraceClassInit(Main.dict.classInitWeakDepend);
if (reflectInSuper) {
cd.classTraceForSupers();
}
}
} else if (md != null
&& md.definingClass().name().equals(Names.JAVA_LANG_CLASS)
&& md.isExactMatch(false, Names.JAVA_LANG_OBJECT, 0,
Names.SIGN_NEWINSTANCE)) {
String ourClassName = Main.dict.curTraceInfo.getDefiningClassName();
if (!ourClassName
.equals(Names.GNU_CLASSPATH_SERVICEPROVIDERLOADINGACTION)
&& !ourClassName.equals(Names.JAVA_UTIL_LOGGING_LOGMANAGER)) {
Main.dict.curTraceInfo.setUsesDynClasses();
}
}
}
ExpressionType traceClassInit() {
assertCond(resultClass != null);
if (actualMethod == null)
return null;
ExpressionType curTraceType0 = terms[0].traceClassInit();
ClassDefinition curClass = actualClass;
MethodDefinition curMethod = actualMethod;
if (curTraceType0 != null && !actualMethod.isClassMethod()) {
if (curTraceType0.objectSize() == Type.NULLREF)
return actualMethod.exprType().objectSize() >= Type.CLASSINTERFACE ? curTraceType0
: null;
curClass = curTraceType0.receiverClass();
if (curClass != actualClass) {
if (actualClass.isAssignableFrom(curClass, 0, null)) {
if (actualMethod.allowOverride()
&& ((curMethod = curClass
.getSameMethod(actualMethod)) == null || !curMethod
.used())) {
curClass = actualClass;
curMethod = actualMethod;
}
} else {
curClass = actualClass;
}
}
}
terms[2].traceClassInit();
ObjVector parmTraceSig = null;
if (terms[2].notEmpty()) {
parmTraceSig = new ObjVector();
terms[2].getTraceSignature(parmTraceSig);
}
curTraceType0 = curMethod
.methodTraceClassInit(
false,
isExact
|| (curTraceType0 != null
&& curTraceType0 != curClass
&& curTraceType0.signatureClass() == curClass && curTraceType0
.signatureDimensions() == 0) ? curClass
.asExactClassType() : curClass, parmTraceSig);
if (actualMethod.exprType() == curTraceType0) {
curTraceType0 = null;
}
traceReflected();
return curTraceType0;
}
}