/*
* @(#) $(JCGO)/jtrsrc/com/ivmaisoft/jcgo/MethodTraceInfo.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;
/**
* A traced method info record.
*/
final class MethodTraceInfo {
private static final ObjVector EMPTY_VECTOR = new ObjVector();
private/* final */MethodDefinition md;
private/* final */ExpressionType curActualClass;
private/* final */ObjVector parmTraceSig;
private ObjVector classInitDepend;
private ObjVector weakInitDepend;
private boolean usesDynClasses;
private ObjVector calledMethodInfos;
private ObjVector weakMethodInfos;
private ExpressionType resTraceType;
private MethodTraceInfo(MethodDefinition md, ExpressionType curActualClass,
ObjVector parmTraceSig) {
this.md = md;
this.curActualClass = curActualClass;
this.parmTraceSig = parmTraceSig;
}
static MethodTraceInfo create(MethodDefinition md,
ExpressionType curActualClass, ObjVector parmTraceSig) {
ClassDefinition cd;
if (curActualClass == null) {
curActualClass = md.definingClass();
} else if (curActualClass.objectSize() == Type.CLASSINTERFACE
&& (cd = curActualClass.signatureClass()) != curActualClass
&& !cd.hasInstantatedSubclasses(false)) {
curActualClass = cd;
}
if (parmTraceSig != null
&& md.methodSignature().isSignEqual(parmTraceSig)) {
parmTraceSig = null;
}
cd = md != null ? md.definingClass() : curActualClass.receiverClass();
ObjHashtable knownMethodInfos;
if ((knownMethodInfos = cd.knownMethodInfos) == null) {
cd.knownMethodInfos = knownMethodInfos = new ObjHashtable();
}
String traceSig = getTraceShortSig(md, curActualClass, parmTraceSig);
MethodTraceInfo traceInfo = (MethodTraceInfo) knownMethodInfos
.get(traceSig);
if (traceInfo == null) {
knownMethodInfos.put(traceSig, traceInfo = new MethodTraceInfo(md,
curActualClass, parmTraceSig));
}
return traceInfo;
}
private static String getTraceShortSig(MethodDefinition md,
ExpressionType curActualClass, ObjVector parmTraceSig) {
return md != null ? md.methodSignature().signatureString()
+ (md.definingClass() != curActualClass ? curActualClass
.getJavaSignature() : "")
+ (parmTraceSig != null ? new MethodSignature(md.id(),
parmTraceSig).getJavaSignature() : "") : "<clinit>";
}
String getTraceSig() {
return getDefiningClassName() + "."
+ getTraceShortSig(md, curActualClass, parmTraceSig);
}
boolean addToProcessed(ObjHashtable processed) {
ClassDefinition cd = md != null ? md.definingClass() : curActualClass
.receiverClass();
ObjHashSet traceInfos = (ObjHashSet) processed.get(cd);
if (traceInfos == null) {
processed.put(cd, traceInfos = new ObjHashSet());
}
return traceInfos.add(this);
}
boolean isCallableNow() {
return md == null || md.isClassMethod() || md.isConstructor()
|| !curActualClass.receiverClass().noInstanceYetOnTrace();
}
void setInstanceCreated() {
if (md != null && md.isConstructor()) {
md.definingClass().instanceCreatedOnTrace();
}
}
ExpressionType curThisClass() {
return md != null && !md.isClassMethod() ? curActualClass : null;
}
String getDefiningClassName() {
return (md != null ? md.definingClass() : curActualClass).name();
}
void setUsesDynClasses() {
Term.assertCond(resTraceType == null);
usesDynClasses = true;
}
void addClassInitDepend(boolean isWeak, ClassDefinition cd) {
Term.assertCond(resTraceType == null);
if (classInitDepend == null
|| classInitDepend.identityLastIndexOf(cd) < 0) {
int i = weakInitDepend != null ? weakInitDepend
.identityLastIndexOf(cd) : -1;
if (isWeak) {
if (i < 0) {
if (weakInitDepend == null) {
weakInitDepend = new ObjVector();
}
weakInitDepend.addElement(cd);
}
} else {
if (classInitDepend == null) {
classInitDepend = new ObjVector();
}
classInitDepend.addElement(cd);
if (i >= 0) {
weakInitDepend.removeElementAt(i);
}
}
}
}
void addMethodCall(MethodTraceInfo traceInfo) {
Term.assertCond(resTraceType == null);
if (calledMethodInfos == null
|| calledMethodInfos.identityLastIndexOf(traceInfo) < 0) {
int i = weakMethodInfos != null ? weakMethodInfos
.identityLastIndexOf(traceInfo) : -1;
if (Main.dict.classInitWeakDepend) {
if (i < 0) {
if (weakMethodInfos == null) {
weakMethodInfos = new ObjVector();
}
weakMethodInfos.addElement(traceInfo);
}
} else {
if (calledMethodInfos == null) {
calledMethodInfos = new ObjVector();
}
calledMethodInfos.addElement(traceInfo);
if (i >= 0) {
weakMethodInfos.removeElementAt(i);
}
}
}
}
void doneMethodTracing(ExpressionType resTraceType) {
Term.assertCond(this.resTraceType == null && resTraceType != null);
this.resTraceType = resTraceType;
}
boolean isNotTraced() {
return resTraceType == null;
}
void traceMethod() {
if (resTraceType == null && Main.dict.inProgressMethodInfos.add(this)) {
Term.assertCond(md != null);
MethodTraceInfo oldCurTraceInfo = Main.dict.curTraceInfo;
if (Main.dict.verboseTracing) {
Main.dict.message("Tracing: " + getTraceSig());
}
Main.dict.curTraceInfo = this;
boolean oldClassInitWeakDepend = Main.dict.classInitWeakDepend;
Main.dict.classInitWeakDepend = false;
MethodDefinition oldCurHelperForMethod = Main.dict.curHelperForMethod;
Main.dict.curHelperForMethod = null;
ExpressionType curTraceType = md.traceBody(parmTraceSig);
Main.dict.curHelperForMethod = oldCurHelperForMethod;
Main.dict.classInitWeakDepend = oldClassInitWeakDepend;
doneMethodTracing(curTraceType != null ? curTraceType : md
.exprType());
Main.dict.curTraceInfo = oldCurTraceInfo;
Main.dict.inProgressMethodInfos.remove(this);
Main.dict.tracedInfosCount++;
}
}
ExpressionType getResTraceType() {
return resTraceType != null ? resTraceType : md != null ? md
.actualExprType() : null;
}
boolean usesDynClasses() {
Term.assertCond(resTraceType != null);
return usesDynClasses;
}
ClassDefinition getClassDependElementAt(boolean isWeak, int index) {
Term.assertCond(resTraceType != null);
ObjVector classDepend = isWeak ? weakInitDepend : classInitDepend;
if (classDepend != null && classDepend.size() > index) {
do {
ClassDefinition cd = (ClassDefinition) classDepend
.elementAt(index);
if (cd.classInitializerNotCalledYet())
return cd;
classDepend.removeElementAt(index);
} while (classDepend.size() > index);
if (index == 0) {
if (isWeak) {
weakInitDepend = null;
} else {
classInitDepend = null;
}
}
}
return null;
}
ClassDefinition getDefiningClassDepend() {
Term.assertCond(resTraceType != null);
ClassDefinition cd;
return md != null && (md.isConstructor() || md.isClassMethod())
&& (cd = md.definingClass()).classInitializerNotCalledYet() ? cd
: null;
}
Enumeration getCalledInfosElements(boolean isWeak) {
Term.assertCond(resTraceType != null);
ObjVector methodInfos = isWeak ? weakMethodInfos : calledMethodInfos;
return (methodInfos != null ? methodInfos : EMPTY_VECTOR).elements();
}
}