mirror of
https://github.com/2003scape/deep-c-rsc.git
synced 2024-03-22 05:49:51 -04:00
1081 lines
44 KiB
Java
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;
|
|
}
|
|
}
|