org.aspectj.weaver.World Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjweaver Show documentation
Show all versions of aspectjweaver Show documentation
The AspectJ weaver applies aspects to Java classes. It can be used as a Java agent in order to apply load-time
weaving (LTW) during class-loading and also contains the AspectJ runtime classes.
/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* 2005,2020 Contributors
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v 2.0
* which accompanies this distribution and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt
* ******************************************************************/
package org.aspectj.weaver;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.WeakHashMap;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.IMessage.Kind;
import org.aspectj.bridge.IMessageHandler;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.MessageUtil;
import org.aspectj.bridge.context.PinpointingMessageHandler;
import org.aspectj.util.IStructureModel;
import org.aspectj.weaver.ResolvedType.Primitive;
import org.aspectj.weaver.UnresolvedType.TypeKind;
import org.aspectj.weaver.patterns.Declare;
import org.aspectj.weaver.patterns.DeclareAnnotation;
import org.aspectj.weaver.patterns.DeclareParents;
import org.aspectj.weaver.patterns.DeclarePrecedence;
import org.aspectj.weaver.patterns.DeclareSoft;
import org.aspectj.weaver.patterns.DeclareTypeErrorOrWarning;
import org.aspectj.weaver.patterns.Pointcut;
import org.aspectj.weaver.patterns.TypePattern;
import org.aspectj.weaver.tools.PointcutDesignatorHandler;
import org.aspectj.weaver.tools.Trace;
import org.aspectj.weaver.tools.TraceFactory;
/**
* A World is a collection of known types and crosscutting members.
*
* @author PARC
* @author Adrian Colyer
* @author Andy Clement
* @author Abraham Nevado
* @author Joseph MacFarlane
*/
public abstract class World implements Dump.INode {
/** handler for any messages produced during resolution etc. */
private IMessageHandler messageHandler = IMessageHandler.SYSTEM_ERR;
/** handler for cross-reference information produced during the weaving process */
private ICrossReferenceHandler xrefHandler = null;
/** Currently 'active' scope in which to lookup (resolve) typevariable references */
private TypeVariableDeclaringElement typeVariableLookupScope;
/** The heart of the world, a map from type signatures to resolved types */
protected TypeMap typeMap = new TypeMap(this);
/** New pointcut designators this world supports */
private Set pointcutDesignators;
// see pr145963
/** Should we create the hierarchy for binary classes and aspects */
public static boolean createInjarHierarchy = true;
/** Calculator for working out aspect precedence */
private final AspectPrecedenceCalculator precedenceCalculator;
/** All of the type and shadow mungers known to us */
private final CrosscuttingMembersSet crosscuttingMembersSet = new CrosscuttingMembersSet(this);
/** The structure model for the compilation */
private IStructureModel model = null;
/** for processing Xlint messages */
private Lint lint = new Lint(this);
/** XnoInline option setting passed down to weaver */
private boolean XnoInline;
/** XlazyTjp option setting passed down to weaver */
private boolean XlazyTjp;
/** XhasMember option setting passed down to weaver */
private boolean XhasMember = false;
/** Xpinpoint controls whether we put out developer info showing the source of messages */
private boolean Xpinpoint = false;
/** When behaving in a Java 5 way autoboxing is considered */
private boolean behaveInJava5Way = false;
/** Should timing information be reported (as info messages)? */
private boolean timing = false;
private boolean timingPeriodically = true;
/** Determines if this world could be used for multiple compiles */
private boolean incrementalCompileCouldFollow = false;
/** The level of the aspectjrt.jar the code we generate needs to run on */
public static final RuntimeVersion RUNTIME_LEVEL_DEFAULT = RuntimeVersion.V1_5;
private RuntimeVersion targetAspectjRuntimeLevel = RUNTIME_LEVEL_DEFAULT;
/** Flags for the new joinpoints that are 'optional': -Xjoinpoints:arrayconstruction -Xjoinpoints:synchronization */
private boolean optionalJoinpoint_ArrayConstruction = false;
private boolean optionalJoinpoint_Synchronization = false;
private boolean addSerialVerUID = false;
private Properties extraConfiguration = null;
private boolean checkedAdvancedConfiguration = false;
private boolean synchronizationPointcutsInUse = false;
// Xset'table options
private boolean runMinimalMemory = false;
private boolean transientTjpFields = false;
private boolean runMinimalMemorySet = false;
private boolean shouldPipelineCompilation = true;
private boolean shouldGenerateStackMaps = false;
protected boolean bcelRepositoryCaching = xsetBCEL_REPOSITORY_CACHING_DEFAULT.equalsIgnoreCase("true");
private boolean fastMethodPacking = false;
private int itdVersion = 2; // defaults to 2nd generation itds
// Minimal Model controls whether model entities that are not involved in relationships are deleted post-build
private boolean minimalModel = true;
private boolean useFinal = true;
private boolean targettingRuntime1_6_10 = false;
private boolean completeBinaryTypes = false;
private boolean overWeaving = false;
private static boolean systemPropertyOverWeaving = false;
public boolean forDEBUG_structuralChangesCode = false;
public boolean forDEBUG_bridgingCode = false;
public boolean optimizedMatching = true;
public boolean generateNewLvts = true;
protected long timersPerJoinpoint = 25000;
protected long timersPerType = 250;
public int infoMessagesEnabled = 0; // 0=uninitialized, 1=no, 2=yes
private static Trace trace = TraceFactory.getTraceFactory().getTrace(World.class);
private boolean errorThreshold;
private boolean warningThreshold;
/**
* A list of RuntimeExceptions containing full stack information for every type we couldn't find.
*/
private List dumpState_cantFindTypeExceptions = null;
static {
try {
String value = System.getProperty("aspectj.overweaving", "false");
if (value.equalsIgnoreCase("true")) {
System.out.println("ASPECTJ: aspectj.overweaving=true: overweaving switched ON");
systemPropertyOverWeaving = true;
}
} catch (Throwable t) {
System.err.println("ASPECTJ: Unable to read system properties");
t.printStackTrace();
}
}
public final Primitive BYTE = new Primitive("B", 1, 0);
public final Primitive CHAR = new Primitive("C", 1, 1);
public final Primitive DOUBLE = new Primitive("D", 2, 2);
public final Primitive FLOAT = new Primitive("F", 1, 3);
public final Primitive INT = new Primitive("I", 1, 4);
public final Primitive LONG = new Primitive("J", 2, 5);
public final Primitive SHORT = new Primitive("S", 1, 6);
public final Primitive BOOLEAN = new Primitive("Z", 1, 7);
public final Primitive VOID = new Primitive("V", 0, 8);
/**
* Insert the primitives
*/
protected World() {
super();
// Dump.registerNode(this.getClass(), this);
typeMap.put("B", BYTE);
typeMap.put("S", SHORT);
typeMap.put("I", INT);
typeMap.put("J", LONG);
typeMap.put("F", FLOAT);
typeMap.put("D", DOUBLE);
typeMap.put("C", CHAR);
typeMap.put("Z", BOOLEAN);
typeMap.put("V", VOID);
precedenceCalculator = new AspectPrecedenceCalculator(this);
}
/**
* Dump processing when a fatal error occurs
*/
@Override
public void accept(Dump.IVisitor visitor) {
// visitor.visitObject("Extra configuration:");
// visitor.visitList(extraConfiguration.);
visitor.visitObject("Shadow mungers:");
visitor.visitList(crosscuttingMembersSet.getShadowMungers());
visitor.visitObject("Type mungers:");
visitor.visitList(crosscuttingMembersSet.getTypeMungers());
visitor.visitObject("Late Type mungers:");
visitor.visitList(crosscuttingMembersSet.getLateTypeMungers());
if (dumpState_cantFindTypeExceptions != null) {
visitor.visitObject("Cant find type problems:");
visitor.visitList(dumpState_cantFindTypeExceptions);
dumpState_cantFindTypeExceptions = null;
}
}
// ==========================================================================
// T Y P E R E S O L U T I O N
// ==========================================================================
/**
* Resolve a type that we require to be present in the world
*/
public ResolvedType resolve(UnresolvedType ty) {
return resolve(ty, false);
}
/**
* Attempt to resolve a type - the source location gives you some context in which resolution is taking place. In the case of an
* error where we can't find the type - we can then at least report why (source location) we were trying to resolve it.
*/
public ResolvedType resolve(UnresolvedType ty, ISourceLocation isl) {
ResolvedType ret = resolve(ty, true);
if (ResolvedType.isMissing(ty)) {
// IMessage msg = null;
getLint().cantFindType.signal(WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE, ty.getName()), isl);
// if (isl!=null) {
// msg = MessageUtil.error(WeaverMessages.format(WeaverMessages.
// CANT_FIND_TYPE,ty.getName()),isl);
// } else {
// msg = MessageUtil.error(WeaverMessages.format(WeaverMessages.
// CANT_FIND_TYPE,ty.getName()));
// }
// messageHandler.handleMessage(msg);
}
return ret;
}
/**
* Convenience method for resolving an array of unresolved types in one hit. Useful for e.g. resolving type parameters in
* signatures.
*/
public ResolvedType[] resolve(UnresolvedType[] types) {
if (types == null) {
return ResolvedType.NONE;
}
ResolvedType[] ret = new ResolvedType[types.length];
for (int i = 0; i < types.length; i++) {
ret[i] = resolve(types[i]);
}
return ret;
}
/**
* Resolve a type. This the hub of type resolution. The resolved type is added to the type map by signature.
*/
public ResolvedType resolve(UnresolvedType ty, boolean allowMissing) {
// special resolution processing for already resolved types.
if (ty instanceof ResolvedType) {
ResolvedType rty = (ResolvedType) ty;
rty = resolve(rty);
// A TypeVariableReferenceType may look like it is resolved (it extends ResolvedType) but the internal
// type variable may not yet have been resolved
if (!rty.isTypeVariableReference() || ((TypeVariableReferenceType) rty).isTypeVariableResolved()) {
return rty;
}
}
// dispatch back to the type variable reference to resolve its
// constituent parts don't do this for other unresolved types otherwise
// you'll end up in a
// loop
if (ty.isTypeVariableReference()) {
return ty.resolve(this);
}
// if we've already got a resolved type for the signature, just return
// it
// after updating the world
String signature = ty.getSignature();
ResolvedType ret = typeMap.get(signature);
if (ret != null) {
ret.world = this; // Set the world for the RTX
return ret;
} else if (signature.equals("?") || signature.equals("*")) {
// might be a problem here, not sure '?' should make it to here as a
// signature, the
// proper signature for wildcard '?' is '*'
// fault in generic wildcard, can't be done earlier because of init
// issues
// TODO ought to be shared single instance representing this
ResolvedType something = getWildcard();
typeMap.put("?", something);
return something;
}
// no existing resolved type, create one
synchronized (buildingTypeLock) {
if (ty.isArray()) {
ResolvedType componentType = resolve(ty.getComponentType(), allowMissing);
ret = new ArrayReferenceType(signature, "[" + componentType.getErasureSignature(), this, componentType);
} else {
ret = resolveToReferenceType(ty, allowMissing);
if (!allowMissing && ret.isMissing()) {
ret = handleRequiredMissingTypeDuringResolution(ty);
}
if (completeBinaryTypes) {
completeBinaryType(ret);
}
}
}
// Pulling in the type may have already put the right entry in the map
ResolvedType result = typeMap.get(signature);
if (result == null && !ret.isMissing()) {
ret = ensureRawTypeIfNecessary(ret);
typeMap.put(signature, ret);
return ret;
}
if (result == null) {
return ret;
} else {
return result;
}
}
private Object buildingTypeLock = new Object();
// Only need one representation of '?' in a world - can be shared
private BoundedReferenceType wildcard;
private BoundedReferenceType getWildcard() {
if (wildcard == null) {
wildcard = new BoundedReferenceType(this);
}
return wildcard;
}
/**
* Called when a type is resolved - enables its type hierarchy to be finished off before we proceed
*/
protected void completeBinaryType(ResolvedType ret) {
}
/**
* Return true if the classloader relating to this world is definetly the one that will define the specified class. Return false
* otherwise or we don't know for certain.
*/
public boolean isLocallyDefined(String classname) {
return false;
}
/**
* We tried to resolve a type and couldn't find it...
*/
private ResolvedType handleRequiredMissingTypeDuringResolution(UnresolvedType ty) {
// defer the message until someone asks a question of the type that we
// can't answer
// just from the signature.
// MessageUtil.error(messageHandler,
// WeaverMessages.format(WeaverMessages.CANT_FIND_TYPE,ty.getName()));
if (dumpState_cantFindTypeExceptions == null) {
dumpState_cantFindTypeExceptions = new ArrayList<>();
}
if (dumpState_cantFindTypeExceptions.size() < 100) { // limit growth
dumpState_cantFindTypeExceptions.add(new RuntimeException("Can't find type " + ty.getName()));
}
return new MissingResolvedTypeWithKnownSignature(ty.getSignature(), this);
}
/**
* Some TypeFactory operations create resolved types directly, but these won't be in the typeMap - this resolution process puts
* them there. Resolved types are also told their world which is needed for the special autoboxing resolved types.
*/
public ResolvedType resolve(ResolvedType ty) {
if (ty.isTypeVariableReference()) {
return ty; // until type variables have proper sigs...
}
ResolvedType resolved = typeMap.get(ty.getSignature());
if (resolved == null) {
resolved = ensureRawTypeIfNecessary(ty);
typeMap.put(ty.getSignature(), resolved);
resolved = ty;
}
resolved.world = this;
return resolved;
}
/**
* When the world is operating in 1.5 mode, the TypeMap should only contain RAW types and never directly generic types. The RAW
* type will contain a reference to the generic type.
*
* @param type a possibly generic type for which the raw needs creating as it is not currently in the world
* @return a type suitable for putting into the world
*/
private ResolvedType ensureRawTypeIfNecessary(ResolvedType type) {
if (!isInJava5Mode() || type.isRawType()) {
return type;
}
// Key requirement here is if it is generic, create a RAW entry to be put in the map that points to it
if (type instanceof ReferenceType && ((ReferenceType) type).getDelegate() != null && type.isGenericType()) {
ReferenceType rawType = new ReferenceType(type.getSignature(), this);
rawType.typeKind = UnresolvedType.TypeKind.RAW;
ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
rawType.setDelegate(delegate);
rawType.setGenericType((ReferenceType) type);
return rawType;
}
// probably parameterized...
return type;
}
/**
* Convenience method for finding a type by name and resolving it in one step.
*/
public ResolvedType resolve(String name) {
// trace.enter("resolve", this, new Object[] {name});
ResolvedType ret = resolve(UnresolvedType.forName(name));
// trace.exit("resolve", ret);
return ret;
}
public ReferenceType resolveToReferenceType(String name) {
return (ReferenceType) resolve(name);
}
public ResolvedType resolve(String name, boolean allowMissing) {
return resolve(UnresolvedType.forName(name), allowMissing);
}
/**
* Resolve to a ReferenceType - simple, raw, parameterized, or generic. Raw, parameterized, and generic versions of a type share
* a delegate.
*/
private final ResolvedType resolveToReferenceType(UnresolvedType ty, boolean allowMissing) {
if (ty.isParameterizedType()) {
// ======= parameterized types ================
ResolvedType rt = resolveGenericTypeFor(ty, allowMissing);
if (rt.isMissing()) {
return rt;
}
ReferenceType genericType = (ReferenceType) rt;
ReferenceType parameterizedType = TypeFactory.createParameterizedType(genericType, ty.typeParameters, this);
return parameterizedType;
} else if (ty.isGenericType()) {
// ======= generic types ======================
ResolvedType rt = resolveGenericTypeFor(ty, false);
if (rt.isMissing()) {
return rt;
}
ReferenceType genericType = (ReferenceType) rt;
if (rt.isMissing()) {
return rt;
}
return genericType;
} else if (ty.isGenericWildcard()) {
// ======= generic wildcard types =============
return resolveGenericWildcardFor((WildcardedUnresolvedType) ty);
} else {
// ======= simple and raw types ===============
String erasedSignature = ty.getErasureSignature();
ReferenceType simpleOrRawType = new ReferenceType(erasedSignature, this);
if (ty.needsModifiableDelegate()) {
simpleOrRawType.setNeedsModifiableDelegate(true);
}
ReferenceTypeDelegate delegate = resolveDelegate(simpleOrRawType);
if (delegate == null) {
return new MissingResolvedTypeWithKnownSignature(ty.getSignature(), erasedSignature, this);
}
if (delegate.isGeneric() && behaveInJava5Way) {
// ======== raw type ===========
simpleOrRawType.typeKind = TypeKind.RAW;
if (simpleOrRawType.hasNewInterfaces()) { // debug 375777
throw new IllegalStateException(
"Simple type promoted forced to raw, but it had new interfaces/superclass. Type is "
+ simpleOrRawType.getName());
}
ReferenceType genericType = makeGenericTypeFrom(delegate, simpleOrRawType);
simpleOrRawType.setDelegate(delegate);
genericType.setDelegate(delegate);
simpleOrRawType.setGenericType(genericType);
return simpleOrRawType;
} else {
// ======== simple type =========
simpleOrRawType.setDelegate(delegate);
return simpleOrRawType;
}
}
}
/**
* Attempt to resolve a type that should be a generic type.
*/
public ResolvedType resolveGenericTypeFor(UnresolvedType anUnresolvedType, boolean allowMissing) {
// Look up the raw type by signature
String rawSignature = anUnresolvedType.getRawType().getSignature();
ResolvedType rawType = typeMap.get(rawSignature);
if (rawType == null) {
rawType = resolve(UnresolvedType.forSignature(rawSignature), allowMissing);
typeMap.put(rawSignature, rawType);
}
if (rawType.isMissing()) {
return rawType;
}
// Does the raw type know its generic form? (It will if we created the
// raw type from a source type, it won't if its been created just
// through
// being referenced, e.g. java.util.List
ResolvedType genericType = rawType.getGenericType();
// There is a special case to consider here (testGenericsBang_pr95993
// highlights it)
// You may have an unresolvedType for a parameterized type but it
// is backed by a simple type rather than a generic type. This occurs
// for
// inner types of generic types that inherit their enclosing types
// type variables.
if (rawType.isSimpleType() && (anUnresolvedType.typeParameters == null || anUnresolvedType.typeParameters.length == 0)) {
rawType.world = this;
return rawType;
}
if (genericType != null) {
genericType.world = this;
return genericType;
} else {
// Fault in the generic that underpins the raw type ;)
ReferenceTypeDelegate delegate = resolveDelegate((ReferenceType) rawType);
ReferenceType genericRefType = makeGenericTypeFrom(delegate, ((ReferenceType) rawType));
((ReferenceType) rawType).setGenericType(genericRefType);
genericRefType.setDelegate(delegate);
((ReferenceType) rawType).setDelegate(delegate);
return genericRefType;
}
}
private ReferenceType makeGenericTypeFrom(ReferenceTypeDelegate delegate, ReferenceType rawType) {
String genericSig = delegate.getDeclaredGenericSignature();
if (genericSig != null) {
return new ReferenceType(UnresolvedType.forGenericTypeSignature(rawType.getSignature(),
delegate.getDeclaredGenericSignature()), this);
} else {
return new ReferenceType(UnresolvedType.forGenericTypeVariables(rawType.getSignature(), delegate.getTypeVariables()),
this);
}
}
/**
* Go from an unresolved generic wildcard (represented by UnresolvedType) to a resolved version (BoundedReferenceType).
*/
private ReferenceType resolveGenericWildcardFor(WildcardedUnresolvedType aType) {
BoundedReferenceType ret = null;
// FIXME asc doesnt take account of additional interface bounds (e.g. ? super R & Serializable - can you do that?)
if (aType.isExtends()) {
ResolvedType resolvedUpperBound = resolve(aType.getUpperBound());
if (resolvedUpperBound.isMissing()) {
return getWildcard();
}
ret = new BoundedReferenceType((ReferenceType)resolvedUpperBound, true, this);
} else if (aType.isSuper()) {
ResolvedType resolvedLowerBound = resolve(aType.getLowerBound());
if (resolvedLowerBound.isMissing()) {
return getWildcard();
}
ret = new BoundedReferenceType((ReferenceType)resolvedLowerBound, false, this);
} else {
// must be ? on its own!
ret = getWildcard();
}
return ret;
}
/**
* Find the ReferenceTypeDelegate behind this reference type so that it can fulfill its contract.
*/
protected abstract ReferenceTypeDelegate resolveDelegate(ReferenceType ty);
/**
* Special resolution for "core" types like OBJECT. These are resolved just like any other type, but if they are not found it is
* more serious and we issue an error message immediately.
*/
// OPTIMIZE streamline path for core types? They are just simple types,
// could look straight in the typemap?
public ResolvedType getCoreType(UnresolvedType tx) {
ResolvedType coreTy = resolve(tx, true);
if (coreTy.isMissing()) {
MessageUtil.error(messageHandler, WeaverMessages.format(WeaverMessages.CANT_FIND_CORE_TYPE, tx.getName()));
}
return coreTy;
}
/**
* Lookup a type by signature, if not found then build one and put it in the map.
*/
public ReferenceType lookupOrCreateName(UnresolvedType ty) {
String signature = ty.getSignature();
ReferenceType ret = lookupBySignature(signature);
if (ret == null) {
ret = ReferenceType.fromTypeX(ty, this);
typeMap.put(signature, ret);
}
return ret;
}
/**
* Lookup a reference type in the world by its signature. Returns null if not found.
*/
public ReferenceType lookupBySignature(String signature) {
return (ReferenceType) typeMap.get(signature);
}
// ==========================================================================
// ===
// T Y P E R E S O L U T I O N -- E N D
// ==========================================================================
// ===
/**
* Member resolution is achieved by resolving the declaring type and then looking up the member in the resolved declaring type.
*/
public ResolvedMember resolve(Member member) {
ResolvedType declaring = member.getDeclaringType().resolve(this);
if (declaring.isRawType()) {
declaring = declaring.getGenericType();
}
ResolvedMember ret;
if (member.getKind() == Member.FIELD) {
ret = declaring.lookupField(member);
} else {
ret = declaring.lookupMethod(member);
}
if (ret != null) {
return ret;
}
return declaring.lookupSyntheticMember(member);
}
private boolean allLintIgnored = false;
public void setAllLintIgnored() {
allLintIgnored = true;
}
public boolean areAllLintIgnored() {
return allLintIgnored;
}
public abstract IWeavingSupport getWeavingSupport();
/**
* Create an advice shadow munger from the given advice attribute
*/
// public abstract Advice createAdviceMunger(AjAttribute.AdviceAttribute
// attribute, Pointcut pointcut, Member signature);
/**
* Create an advice shadow munger for the given advice kind
*/
public final Advice createAdviceMunger(AdviceKind kind, Pointcut p, Member signature, int extraParameterFlags,
IHasSourceLocation loc, ResolvedType declaringAspect) {
AjAttribute.AdviceAttribute attribute = new AjAttribute.AdviceAttribute(kind, p, extraParameterFlags, loc.getStart(),
loc.getEnd(), loc.getSourceContext());
return getWeavingSupport().createAdviceMunger(attribute, p, signature, declaringAspect);
}
/**
* Same signature as org.aspectj.util.PartialOrder.PartialComparable.compareTo
*/
public int compareByPrecedence(ResolvedType aspect1, ResolvedType aspect2) {
return precedenceCalculator.compareByPrecedence(aspect1, aspect2);
}
public Integer getPrecedenceIfAny(ResolvedType aspect1, ResolvedType aspect2) {
return precedenceCalculator.getPrecedenceIfAny(aspect1, aspect2);
}
/**
* compares by precedence with the additional rule that a super-aspect is sorted before its sub-aspects
*/
public int compareByPrecedenceAndHierarchy(ResolvedType aspect1, ResolvedType aspect2) {
return precedenceCalculator.compareByPrecedenceAndHierarchy(aspect1, aspect2);
}
// simple property getter and setters
// ===========================================================
/**
* Nobody should hold onto a copy of this message handler, or setMessageHandler won't work right.
*/
public IMessageHandler getMessageHandler() {
return messageHandler;
}
public void setMessageHandler(IMessageHandler messageHandler) {
if (this.isInPinpointMode()) {
this.messageHandler = new PinpointingMessageHandler(messageHandler);
} else {
this.messageHandler = messageHandler;
}
}
/**
* convenenience method for creating and issuing messages via the message handler - if you supply two locations you will get two
* messages.
*/
public void showMessage(Kind kind, String message, ISourceLocation loc1, ISourceLocation loc2) {
if (loc1 != null) {
messageHandler.handleMessage(new Message(message, kind, null, loc1));
if (loc2 != null) {
messageHandler.handleMessage(new Message(message, kind, null, loc2));
}
} else {
messageHandler.handleMessage(new Message(message, kind, null, loc2));
}
}
public void setCrossReferenceHandler(ICrossReferenceHandler xrefHandler) {
this.xrefHandler = xrefHandler;
}
/**
* Get the cross-reference handler for the world, may be null.
*/
public ICrossReferenceHandler getCrossReferenceHandler() {
return xrefHandler;
}
public void setTypeVariableLookupScope(TypeVariableDeclaringElement scope) {
typeVariableLookupScope = scope;
}
public TypeVariableDeclaringElement getTypeVariableLookupScope() {
return typeVariableLookupScope;
}
public List getDeclareParents() {
return crosscuttingMembersSet.getDeclareParents();
}
public List getDeclareAnnotationOnTypes() {
return crosscuttingMembersSet.getDeclareAnnotationOnTypes();
}
public List getDeclareAnnotationOnFields() {
return crosscuttingMembersSet.getDeclareAnnotationOnFields();
}
public List getDeclareAnnotationOnMethods() {
return crosscuttingMembersSet.getDeclareAnnotationOnMethods();
}
public List getDeclareTypeEows() {
return crosscuttingMembersSet.getDeclareTypeEows();
}
public List getDeclareSoft() {
return crosscuttingMembersSet.getDeclareSofts();
}
public CrosscuttingMembersSet getCrosscuttingMembersSet() {
return crosscuttingMembersSet;
}
public IStructureModel getModel() {
return model;
}
public void setModel(IStructureModel model) {
this.model = model;
}
public Lint getLint() {
return lint;
}
public void setLint(Lint lint) {
this.lint = lint;
}
public boolean isXnoInline() {
return XnoInline;
}
public void setXnoInline(boolean xnoInline) {
XnoInline = xnoInline;
}
public boolean isXlazyTjp() {
return XlazyTjp;
}
public void setXlazyTjp(boolean b) {
XlazyTjp = b;
}
public boolean isHasMemberSupportEnabled() {
return XhasMember;
}
public void setXHasMemberSupportEnabled(boolean b) {
XhasMember = b;
}
public boolean isInPinpointMode() {
return Xpinpoint;
}
public void setPinpointMode(boolean b) {
Xpinpoint = b;
}
public boolean useFinal() {
return useFinal;
}
public boolean isMinimalModel() {
ensureAdvancedConfigurationProcessed();
return minimalModel;
}
public boolean isTargettingRuntime1_6_10() {
ensureAdvancedConfigurationProcessed();
return targettingRuntime1_6_10;
}
public void setBehaveInJava5Way(boolean b) {
behaveInJava5Way = b;
}
/**
* Set the timing option (whether to collect timing info), this will also need INFO messages turned on for the message handler
* being used. The reportPeriodically flag should be set to false under AJDT so numbers just come out at the end.
*/
public void setTiming(boolean timersOn, boolean reportPeriodically) {
timing = timersOn;
timingPeriodically = reportPeriodically;
}
/**
* Set the error and warning threashold which can be taken from CompilerOptions (see bug 129282)
*
* @param errorThreshold
* @param warningThreshold
*/
public void setErrorAndWarningThreshold(boolean errorThreshold, boolean warningThreshold) {
this.errorThreshold = errorThreshold;
this.warningThreshold = warningThreshold;
}
/**
* @return true if ignoring the UnusedDeclaredThrownException and false if this compiler option is set to error or warning
*/
public boolean isIgnoringUnusedDeclaredThrownException() {
// the 0x800000 is CompilerOptions.UnusedDeclaredThrownException
// which is ASTNode.bit24
return errorThreshold||warningThreshold;
// if ((errorThreshold & 0x800000) != 0 || (warningThreshold & 0x800000) != 0) {
// return false;
// }
// return true;
}
public void performExtraConfiguration(String config) {
if (config == null) {
return;
}
// Bunch of name value pairs to split
extraConfiguration = new Properties();
int pos = -1;
while ((pos = config.indexOf(",")) != -1) {
String nvpair = config.substring(0, pos);
int pos2 = nvpair.indexOf("=");
if (pos2 != -1) {
String n = nvpair.substring(0, pos2);
String v = nvpair.substring(pos2 + 1);
extraConfiguration.setProperty(n, v);
}
config = config.substring(pos + 1);
}
if (config.length() > 0) {
int pos2 = config.indexOf("=");
if (pos2 != -1) {
String n = config.substring(0, pos2);
String v = config.substring(pos2 + 1);
extraConfiguration.setProperty(n, v);
}
}
ensureAdvancedConfigurationProcessed();
}
public boolean areInfoMessagesEnabled() {
if (infoMessagesEnabled == 0) {
infoMessagesEnabled = (messageHandler.isIgnoring(IMessage.INFO) ? 1 : 2);
}
return infoMessagesEnabled == 2;
}
/**
* may return null
*/
public Properties getExtraConfiguration() {
return extraConfiguration;
}
public final static String xsetAVOID_FINAL = "avoidFinal"; // default true
public final static String xsetWEAVE_JAVA_PACKAGES = "weaveJavaPackages"; // default
// false
// -
// controls
// LTW
public final static String xsetWEAVE_JAVAX_PACKAGES = "weaveJavaxPackages"; // default
// false
// -
// controls
// LTW
public final static String xsetCAPTURE_ALL_CONTEXT = "captureAllContext"; // default
// false
public final static String xsetRUN_MINIMAL_MEMORY = "runMinimalMemory"; // default
// true
public final static String xsetDEBUG_STRUCTURAL_CHANGES_CODE = "debugStructuralChangesCode"; // default
// false
public final static String xsetDEBUG_BRIDGING = "debugBridging"; // default
// false
public final static String xsetTRANSIENT_TJP_FIELDS = "makeTjpFieldsTransient"; // default false
public final static String xsetBCEL_REPOSITORY_CACHING = "bcelRepositoryCaching";
public final static String xsetPIPELINE_COMPILATION = "pipelineCompilation";
public final static String xsetGENERATE_STACKMAPS = "generateStackMaps";
public final static String xsetPIPELINE_COMPILATION_DEFAULT = "true";
public final static String xsetCOMPLETE_BINARY_TYPES = "completeBinaryTypes";
public final static String xsetCOMPLETE_BINARY_TYPES_DEFAULT = "false";
public final static String xsetTYPE_DEMOTION = "typeDemotion";
public final static String xsetTYPE_DEMOTION_DEBUG = "typeDemotionDebug";
public final static String xsetTYPE_REFS = "useWeakTypeRefs";
public final static String xsetBCEL_REPOSITORY_CACHING_DEFAULT = "true";
public final static String xsetFAST_PACK_METHODS = "fastPackMethods"; // default true
public final static String xsetOVERWEAVING = "overWeaving";
public final static String xsetOPTIMIZED_MATCHING = "optimizedMatching";
public final static String xsetTIMERS_PER_JOINPOINT = "timersPerJoinpoint";
public final static String xsetTIMERS_PER_FASTMATCH_CALL = "timersPerFastMatchCall";
public final static String xsetITD_VERSION = "itdVersion";
public final static String xsetITD_VERSION_ORIGINAL = "1";
public final static String xsetITD_VERSION_2NDGEN = "2";
public final static String xsetITD_VERSION_DEFAULT = xsetITD_VERSION_2NDGEN;
public final static String xsetMINIMAL_MODEL = "minimalModel";
public final static String xsetTARGETING_RUNTIME_1610 = "targetRuntime1_6_10";
// This option allows you to prevent AspectJ adding local variable tables - some tools (e.g. dex) may
// not like what gets created because even though it is valid, the bytecode they are processing has
// unexpected quirks that mean the table entries are violated in the code. See issue:
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=470658
public final static String xsetGENERATE_NEW_LVTS="generateNewLocalVariableTables";
public boolean isInJava5Mode() {
return behaveInJava5Way;
}
public boolean isTimingEnabled() {
return timing;
}
public void setTargetAspectjRuntimeLevel(String s) {
targetAspectjRuntimeLevel = RuntimeVersion.getVersionFor(s);
}
public void setOptionalJoinpoints(String jps) {
if (jps == null) {
return;
}
if (jps.contains("arrayconstruction")) {
optionalJoinpoint_ArrayConstruction = true;
}
if (jps.contains("synchronization")) {
optionalJoinpoint_Synchronization = true;
}
}
public boolean isJoinpointArrayConstructionEnabled() {
return optionalJoinpoint_ArrayConstruction;
}
public boolean isJoinpointSynchronizationEnabled() {
return optionalJoinpoint_Synchronization;
}
public RuntimeVersion getTargetAspectjRuntimeLevel() {
return targetAspectjRuntimeLevel;
}
// OPTIMIZE are users falling foul of not supplying -1.5 and so targetting the old runtime?
public boolean isTargettingAspectJRuntime12() {
boolean b = false; // pr116679
if (!isInJava5Mode()) {
b = true;
} else {
b = (getTargetAspectjRuntimeLevel() == RuntimeVersion.V1_2);
}
return b;
}
/*
* Map of types in the world, can have 'references' to expendable ones which can be garbage collected to recover memory. An
* expendable type is a reference type that is not exposed to the weaver (ie just pulled in for type resolution purposes).
* Generic types have their raw form added to the map, which has a pointer to the underlying generic.
*/
public static class TypeMap {
// Strategy for entries in the expendable map
public final static int DONT_USE_REFS = 0; // Hang around forever
public final static int USE_WEAK_REFS = 1; // Collected asap
public final static int USE_SOFT_REFS = 2; // Collected when short on memory
public List addedSinceLastDemote;
public List writtenClasses;
private static boolean debug = false;
public static boolean useExpendableMap = true; // configurable for reliable testing
private boolean demotionSystemActive;
private boolean debugDemotion = false;
public int policy = USE_WEAK_REFS;
// Map of types that never get thrown away
final Map tMap = new HashMap<>();
// Map of types that may be ejected from the cache if we need space
final Map> expendableMap = Collections
.synchronizedMap(new WeakHashMap<>());
private final World w;
// profiling tools...
private boolean memoryProfiling = false;
private int maxExpendableMapSize = -1;
private int collectedTypes = 0;
private final ReferenceQueue rq = new ReferenceQueue<>();
TypeMap(World w) {
// Demotion activated when switched on and loadtime weaving or in AJDT
demotionSystemActive = w.isDemotionActive() && (w.isLoadtimeWeaving() || w.couldIncrementalCompileFollow());
addedSinceLastDemote = new ArrayList<>();
writtenClasses = new ArrayList<>();
this.w = w;
memoryProfiling = false;// !w.getMessageHandler().isIgnoring(Message.INFO);
}
// For testing
public Map> getExpendableMap() {
return expendableMap;
}
// For testing
public Map getMainMap() {
return tMap;
}
public int demote() {
return demote(false);
}
/**
* Go through any types added during the previous file weave. If any are suitable for demotion, then put them in the
* expendable map where GC can claim them at some point later. Demotion means: the type is not an aspect, the type is not
* java.lang.Object, the type is not primitive and the type is not affected by type mungers in any way. Further refinements
* of these conditions may allow for more demotions.
*
* @return number of types demoted
*/
public int demote(boolean atEndOfCompile) {
if (!demotionSystemActive) {
return 0;
}
if (debugDemotion) {
System.out.println("Demotion running " + addedSinceLastDemote);
}
boolean isLtw = w.isLoadtimeWeaving();
int demotionCounter = 0;
if (isLtw) {
// Loadtime weaving demotion strategy
for (String key : addedSinceLastDemote) {
ResolvedType type = tMap.get(key);
if (type != null && !type.isAspect() && !type.equals(UnresolvedType.OBJECT) && !type.isPrimitiveType()) {
List typeMungers = type.getInterTypeMungers();
if (typeMungers == null || typeMungers.size() == 0) {
tMap.remove(key);
insertInExpendableMap(key, type);
demotionCounter++;
}
}
}
addedSinceLastDemote.clear();
} else {
// Compile time demotion strategy
List forRemoval = new ArrayList<>();
for (String key : addedSinceLastDemote) {
ResolvedType type = tMap.get(key);
if (type == null) {
// TODO not 100% sure why it is not there, where did it go?
forRemoval.add(key);
continue;
}
if (!writtenClasses.contains(type.getName())) { // COSTLY
continue;
}
if (type != null && !type.isAspect() && !type.equals(UnresolvedType.OBJECT) && !type.isPrimitiveType()) {
List typeMungers = type.getInterTypeMungers();
if (typeMungers == null || typeMungers.size() == 0) {
/*
* if (type.isNested()) { try { ReferenceType rt = (ReferenceType) w.resolve(type.getOutermostType());
* if (!rt.isMissing()) { ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate(); boolean
* isWeavable = delegate == null ? false : delegate.isExposedToWeaver(); boolean hasBeenWoven = delegate
* == null ? false : delegate.hasBeenWoven(); if (isWeavable && !hasBeenWoven) { // skip demotion of
* this inner type for now continue; } } } catch (ClassCastException cce) { cce.printStackTrace();
* System.out.println("outer of " + key + " is not a reftype? " + type.getOutermostType()); // throw new
* IllegalStateException(cce); } }
*/
ReferenceTypeDelegate delegate = ((ReferenceType) type).getDelegate();
boolean isWeavable = delegate == null ? false : delegate.isExposedToWeaver();
boolean hasBeenWoven = delegate == null ? false : delegate.hasBeenWoven();
if (!isWeavable || hasBeenWoven) {
if (debugDemotion) {
System.out.println("Demoting " + key);
}
forRemoval.add(key);
tMap.remove(key);
insertInExpendableMap(key, type);
demotionCounter++;
}
} else {
// no need to try this again, it will never be demoted
writtenClasses.remove(type.getName());
forRemoval.add(key);
}
} else {
writtenClasses.remove(type.getName());
// no need to try this again, it will never be demoted
forRemoval.add(key);
}
}
addedSinceLastDemote.removeAll(forRemoval);
}
if (debugDemotion) {
System.out.println("Demoted " + demotionCounter + " types. Types remaining in fixed set #" + tMap.keySet().size()
+ ". addedSinceLastDemote size is " + addedSinceLastDemote.size());
System.out.println("writtenClasses.size() = " + writtenClasses.size() + ": " + writtenClasses);
}
if (atEndOfCompile) {
if (debugDemotion) {
System.out.println("Clearing writtenClasses");
}
writtenClasses.clear();
}
return demotionCounter;
}
private void insertInExpendableMap(String key, ResolvedType type) {
if (useExpendableMap) {
// Need to check both whether the entry is gone, or whether the entry has had
// the WR to the value cleared.
Reference existingReference = expendableMap.get(key);
if (existingReference == null || existingReference.get() == null) {
// If a previous key is in there, WeakHashMap.put will update the value on the
// entry but not the key. We can't allow this as the old key won't
// be directly referenced by the new type, meaning that the key and value
// might be GC'd independently.
expendableMap.remove(key);
if (policy == USE_SOFT_REFS) {
expendableMap.put(key, new SoftReference<>(type));
} else {
expendableMap.put(key, new WeakReference<>(type));
}
}
}
}
/**
* Add a new type into the map, the key is the type signature. Some types do *not* go in the map, these are ones involving
* *member* type variables. The reason is that when all you have is the signature which gives you a type variable name, you
* cannot guarantee you are using the type variable in the same way as someone previously working with a similarly named
* type variable. So, these do not go into the map: - TypeVariableReferenceType. - ParameterizedType where a member type
* variable is involved. - BoundedReferenceType when one of the bounds is a type variable.
*
* definition: "member type variables" - a tvar declared on a generic method/ctor as opposed to those you see declared on a
* generic type.
*/
public ResolvedType put(String key, ResolvedType type) {
if (!type.isCacheable()) {
return type;
}
if (type.isParameterizedType() && type.isParameterizedWithTypeVariable()) {
if (debug) {
System.err
.println("Not putting a parameterized type that utilises member declared type variables into the typemap: key="
+ key + " type=" + type);
}
return type;
}
if (type.isTypeVariableReference()) {
if (debug) {
System.err.println("Not putting a type variable reference type into the typemap: key=" + key + " type=" + type);
}
return type;
}
// this test should be improved - only avoid putting them in if one of the
// bounds is a member type variable
if (type instanceof BoundedReferenceType) {
if (debug) {
System.err.println("Not putting a bounded reference type into the typemap: key=" + key + " type=" + type);
}
return type;
}
if (type instanceof MissingResolvedTypeWithKnownSignature) {
if (debug) {
System.err.println("Not putting a missing type into the typemap: key=" + key + " type=" + type);
}
return type;
}
if ((type instanceof ReferenceType) && (((ReferenceType) type).getDelegate() == null) && w.isExpendable(type)) {
if (debug) {
System.err.println("Not putting expendable ref type with null delegate into typemap: key=" + key + " type="
+ type);
}
return type;
}
// TODO should this be in as a permanent assertion?
if ((type instanceof ReferenceType) && type.getWorld().isInJava5Mode()
&& (((ReferenceType) type).getDelegate() != null) && type.isGenericType()) {
throw new BCException("Attempt to add generic type to typemap " + type.toString() + " (should be raw)");
}
if (w.isExpendable(type)) {
if (useExpendableMap) {
// If a previous key is in there, WeakHashMap.put will update the value on the
// entry but not the key. We can't allow this as the old key won't be directly
// referenced by the new type, meaning that the key and value might
// be GC'd independently.
expendableMap.remove(key);
// Dont use reference queue for tracking if not profiling...
if (policy == USE_WEAK_REFS) {
if (memoryProfiling) {
expendableMap.put(key, new WeakReference<>(type, rq));
} else {
expendableMap.put(key, new WeakReference<>(type));
}
} else if (policy == USE_SOFT_REFS) {
if (memoryProfiling) {
expendableMap.put(key, new SoftReference<>(type, rq));
} else {
expendableMap.put(key, new SoftReference<>(type));
}
// } else {
// expendableMap.put(key, type);
}
}
if (memoryProfiling && expendableMap.size() > maxExpendableMapSize) {
maxExpendableMapSize = expendableMap.size();
}
return type;
} else {
if (demotionSystemActive) {
// System.out.println("Added since last demote " + key);
addedSinceLastDemote.add(key);
}
return tMap.put(key, type);
}
}
public void report() {
if (!memoryProfiling) {
return;
}
checkq();
w.getMessageHandler().handleMessage(
MessageUtil.info("MEMORY: world expendable type map reached maximum size of #" + maxExpendableMapSize
+ " entries"));
w.getMessageHandler().handleMessage(
MessageUtil.info("MEMORY: types collected through garbage collection #" + collectedTypes + " entries"));
}
public void checkq() {
if (!memoryProfiling) {
return;
}
Reference extends ResolvedType> r = null;
while ((r=rq.poll()) != null) {
collectedTypes++;
}
}
/**
* Lookup a type by its signature, always look in the real map before the expendable map
*/
public ResolvedType get(String key) {
checkq();
ResolvedType ret = tMap.get(key);
if (ret == null) {
if (policy == USE_WEAK_REFS) {
WeakReference ref = (WeakReference) expendableMap.get(key);
if (ref != null) {
ret = ref.get();
// if (ret==null) {
// expendableMap.remove(key);
// }
}
} else if (policy == USE_SOFT_REFS) {
SoftReference ref = (SoftReference) expendableMap.get(key);
if (ref != null) {
ret = ref.get();
// if (ret==null) {
// expendableMap.remove(key);
// }
}
// } else {
// return (ResolvedType) expendableMap.get(key);
}
}
return ret;
}
/** Remove a type from the map */
public ResolvedType remove(String key) {
ResolvedType ret = tMap.remove(key);
if (ret == null) {
if (policy == USE_WEAK_REFS) {
WeakReference wref = (WeakReference) expendableMap.remove(key);
if (wref != null) {
ret = wref.get();
}
} else if (policy == USE_SOFT_REFS) {
SoftReference wref = (SoftReference) expendableMap.remove(key);
if (wref != null) {
ret = wref.get();
}
// } else {
// ret = (ResolvedType) expendableMap.remove(key);
}
}
return ret;
}
public void classWriteEvent(String classname) {
// that is a name com.Foo and not a signature Lcom/Foo; boooooooooo!
if (demotionSystemActive) {
writtenClasses.add(classname);
}
if (debugDemotion) {
System.out.println("Class write event for " + classname);
}
}
public void demote(ResolvedType type) {
String key = type.getSignature();
if (debugDemotion) {
addedSinceLastDemote.remove(key);
}
tMap.remove(key);
insertInExpendableMap(key, type);
}
// public ResolvedType[] getAllTypes() {
// List/* ResolvedType */results = new ArrayList();
//
// collectTypes(expendableMap, results);
// collectTypes(tMap, results);
// return (ResolvedType[]) results.toArray(new
// ResolvedType[results.size()]);
// }
//
// private void collectTypes(Map map, List/* ResolvedType */results) {
// for (Iterator iterator = map.keySet().iterator();
// iterator.hasNext();) {
// String key = (String) iterator.next();
// ResolvedType type = get(key);
// if (type != null)
// results.add(type);
// else
// System.err.println("null!:" + key);
// }
// }
}
/**
* This class is used to compute and store precedence relationships between aspects.
*/
private static class AspectPrecedenceCalculator {
private final World world;
private final Map cachedResults;
public AspectPrecedenceCalculator(World forSomeWorld) {
world = forSomeWorld;
cachedResults = new HashMap<>();
}
/**
* Ask every declare precedence in the world to order the two aspects. If more than one declare precedence gives an
* ordering, and the orderings conflict, then that's an error.
*/
public int compareByPrecedence(ResolvedType firstAspect, ResolvedType secondAspect) {
PrecedenceCacheKey key = new PrecedenceCacheKey(firstAspect, secondAspect);
if (cachedResults.containsKey(key)) {
return cachedResults.get(key);
} else {
int order = 0;
DeclarePrecedence orderer = null; // Records the declare
// precedence statement that
// gives the first ordering
for (Declare declare : world.getCrosscuttingMembersSet().getDeclareDominates()) {
DeclarePrecedence d = (DeclarePrecedence) declare;
int thisOrder = d.compare(firstAspect, secondAspect);
if (thisOrder != 0) {
if (orderer == null) {
orderer = d;
}
if (order != 0 && order != thisOrder) {
ISourceLocation[] isls = new ISourceLocation[2];
isls[0] = orderer.getSourceLocation();
isls[1] = d.getSourceLocation();
Message m = new Message("conflicting declare precedence orderings for aspects: "
+ firstAspect.getName() + " and " + secondAspect.getName(), null, true, isls);
world.getMessageHandler().handleMessage(m);
} else {
order = thisOrder;
}
}
}
cachedResults.put(key, order);
return order;
}
}
public Integer getPrecedenceIfAny(ResolvedType aspect1, ResolvedType aspect2) {
return cachedResults.get(new PrecedenceCacheKey(aspect1, aspect2));
}
public int compareByPrecedenceAndHierarchy(ResolvedType firstAspect, ResolvedType secondAspect) {
if (firstAspect.equals(secondAspect)) {
return 0;
}
int ret = compareByPrecedence(firstAspect, secondAspect);
if (ret != 0) {
return ret;
}
if (firstAspect.isAssignableFrom(secondAspect)) {
return -1;
} else if (secondAspect.isAssignableFrom(firstAspect)) {
return +1;
}
return 0;
}
private static class PrecedenceCacheKey {
public ResolvedType aspect1;
public ResolvedType aspect2;
public PrecedenceCacheKey(ResolvedType a1, ResolvedType a2) {
aspect1 = a1;
aspect2 = a2;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PrecedenceCacheKey)) {
return false;
}
PrecedenceCacheKey other = (PrecedenceCacheKey) obj;
return (aspect1 == other.aspect1 && aspect2 == other.aspect2);
}
@Override
public int hashCode() {
return aspect1.hashCode() + aspect2.hashCode();
}
}
}
public void validateType(UnresolvedType type) {
}
// --- with java5 we can get into a recursive mess if we aren't careful when
// resolving types (*cough* java.lang.Enum) ---
public boolean isDemotionActive() {
return true;
}
// --- this first map is for java15 delegates which may try and recursively
// access the same type variables.
// --- I would rather stash this against a reference type - but we don't
// guarantee referencetypes are unique for
// so we can't :(
private final Map, TypeVariable[]> workInProgress1 = new HashMap<>();
public TypeVariable[] getTypeVariablesCurrentlyBeingProcessed(Class> baseClass) {
return workInProgress1.get(baseClass);
}
public void recordTypeVariablesCurrentlyBeingProcessed(Class> baseClass, TypeVariable[] typeVariables) {
workInProgress1.put(baseClass, typeVariables);
}
public void forgetTypeVariablesCurrentlyBeingProcessed(Class> baseClass) {
workInProgress1.remove(baseClass);
}
public void setAddSerialVerUID(boolean b) {
addSerialVerUID = b;
}
public boolean isAddSerialVerUID() {
return addSerialVerUID;
}
/** be careful calling this - pr152257 */
public void flush() {
typeMap.expendableMap.clear();
}
public void ensureAdvancedConfigurationProcessed() {
// Check *once* whether the user has switched asm support off
if (!checkedAdvancedConfiguration) {
Properties p = getExtraConfiguration();
if (p != null) {
String s = p.getProperty(xsetBCEL_REPOSITORY_CACHING, xsetBCEL_REPOSITORY_CACHING_DEFAULT);
bcelRepositoryCaching = s.equalsIgnoreCase("true");
if (!bcelRepositoryCaching) {
getMessageHandler().handleMessage(
MessageUtil
.info("[bcelRepositoryCaching=false] AspectJ will not use a bcel cache for class information"));
}
// ITD Versions
// 1 is the first version in use up to AspectJ 1.6.8
// 2 is from 1.6.9 onwards
s = p.getProperty(xsetITD_VERSION, xsetITD_VERSION_DEFAULT);
if (s.equals(xsetITD_VERSION_ORIGINAL)) {
itdVersion = 1;
}
s = p.getProperty(xsetAVOID_FINAL, "false");
if (s.equalsIgnoreCase("true")) {
useFinal = false; // if avoidFinal=true, then set useFinal to false
}
s = p.getProperty(xsetMINIMAL_MODEL, "true");
if (s.equalsIgnoreCase("false")) {
minimalModel = false;
}
s = p.getProperty(xsetTARGETING_RUNTIME_1610, "false");
if (s.equalsIgnoreCase("true")) {
targettingRuntime1_6_10 = true;
}
s = p.getProperty(xsetFAST_PACK_METHODS, "true");
fastMethodPacking = s.equalsIgnoreCase("true");
s = p.getProperty(xsetPIPELINE_COMPILATION, xsetPIPELINE_COMPILATION_DEFAULT);
shouldPipelineCompilation = s.equalsIgnoreCase("true");
s = p.getProperty(xsetGENERATE_STACKMAPS, "false");
shouldGenerateStackMaps = s.equalsIgnoreCase("true");
s = p.getProperty(xsetCOMPLETE_BINARY_TYPES, xsetCOMPLETE_BINARY_TYPES_DEFAULT);
completeBinaryTypes = s.equalsIgnoreCase("true");
if (completeBinaryTypes) {
getMessageHandler().handleMessage(
MessageUtil.info("[completeBinaryTypes=true] Completion of binary types activated"));
}
s = p.getProperty(xsetTYPE_DEMOTION); // default is: ON
if (s != null) {
boolean b = typeMap.demotionSystemActive;
if (b && s.equalsIgnoreCase("false")) {
System.out.println("typeDemotion=false: type demotion switched OFF");
typeMap.demotionSystemActive = false;
} else if (!b && s.equalsIgnoreCase("true")) {
System.out.println("typeDemotion=true: type demotion switched ON");
typeMap.demotionSystemActive = true;
}
}
s = p.getProperty(xsetOVERWEAVING, "false");
if (s.equalsIgnoreCase("true")) {
overWeaving = true;
}
s = p.getProperty(xsetTYPE_DEMOTION_DEBUG, "false");
if (s.equalsIgnoreCase("true")) {
typeMap.debugDemotion = true;
}
s = p.getProperty(xsetTYPE_REFS, "true");
if (s.equalsIgnoreCase("false")) {
typeMap.policy = TypeMap.USE_SOFT_REFS;
}
runMinimalMemorySet = p.getProperty(xsetRUN_MINIMAL_MEMORY) != null;
s = p.getProperty(xsetRUN_MINIMAL_MEMORY, "false");
runMinimalMemory = s.equalsIgnoreCase("true");
// if (runMinimalMemory)
// getMessageHandler().handleMessage(MessageUtil.info(
// "[runMinimalMemory=true] Optimizing bcel processing (and cost of performance) to use less memory"
// ));
s = p.getProperty(xsetDEBUG_STRUCTURAL_CHANGES_CODE, "false");
forDEBUG_structuralChangesCode = s.equalsIgnoreCase("true");
s = p.getProperty(xsetTRANSIENT_TJP_FIELDS,"false");
transientTjpFields = s.equalsIgnoreCase("true");
s = p.getProperty(xsetDEBUG_BRIDGING, "false");
forDEBUG_bridgingCode = s.equalsIgnoreCase("true");
s = p.getProperty(xsetGENERATE_NEW_LVTS,"true");
generateNewLvts = s.equalsIgnoreCase("true");
if (!generateNewLvts) {
getMessageHandler().handleMessage(MessageUtil.info("[generateNewLvts=false] for methods without an incoming local variable table, do not generate one"));
}
s = p.getProperty(xsetOPTIMIZED_MATCHING, "true");
optimizedMatching = s.equalsIgnoreCase("true");
if (!optimizedMatching) {
getMessageHandler().handleMessage(MessageUtil.info("[optimizedMatching=false] optimized matching turned off"));
}
s = p.getProperty(xsetTIMERS_PER_JOINPOINT, "25000");
try {
timersPerJoinpoint = Integer.parseInt(s);
} catch (Exception e) {
getMessageHandler().handleMessage(MessageUtil.error("unable to process timersPerJoinpoint value of " + s));
timersPerJoinpoint = 25000;
}
s = p.getProperty(xsetTIMERS_PER_FASTMATCH_CALL, "250");
try {
timersPerType = Integer.parseInt(s);
} catch (Exception e) {
getMessageHandler().handleMessage(MessageUtil.error("unable to process timersPerType value of " + s));
timersPerType = 250;
}
}
try {
if (systemPropertyOverWeaving) {
overWeaving = true;
}
String value = null;
value = System.getProperty("aspectj.typeDemotion", "false");
if (value.equalsIgnoreCase("true")) {
System.out.println("ASPECTJ: aspectj.typeDemotion=true: type demotion switched ON");
typeMap.demotionSystemActive = true;
}
value = System.getProperty("aspectj.minimalModel", "false");
if (value.equalsIgnoreCase("true")) {
System.out.println("ASPECTJ: aspectj.minimalModel=true: minimal model switched ON");
minimalModel = true;
}
} catch (Throwable t) {
System.err.println("ASPECTJ: Unable to read system properties");
t.printStackTrace();
}
checkedAdvancedConfiguration = true;
}
}
public boolean isRunMinimalMemory() {
ensureAdvancedConfigurationProcessed();
return runMinimalMemory;
}
public boolean isTransientTjpFields() {
ensureAdvancedConfigurationProcessed();
return transientTjpFields;
}
public boolean isRunMinimalMemorySet() {
ensureAdvancedConfigurationProcessed();
return runMinimalMemorySet;
}
public boolean shouldFastPackMethods() {
ensureAdvancedConfigurationProcessed();
return fastMethodPacking;
}
public boolean shouldPipelineCompilation() {
ensureAdvancedConfigurationProcessed();
return shouldPipelineCompilation;
}
public boolean shouldGenerateStackMaps() {
ensureAdvancedConfigurationProcessed();
return shouldGenerateStackMaps;
}
public void setIncrementalCompileCouldFollow(boolean b) {
incrementalCompileCouldFollow = b;
}
public boolean couldIncrementalCompileFollow() {
return incrementalCompileCouldFollow;
}
public void setSynchronizationPointcutsInUse() {
if (trace.isTraceEnabled()) {
trace.enter("setSynchronizationPointcutsInUse", this);
}
synchronizationPointcutsInUse = true;
if (trace.isTraceEnabled()) {
trace.exit("setSynchronizationPointcutsInUse");
}
}
public boolean areSynchronizationPointcutsInUse() {
return synchronizationPointcutsInUse;
}
/**
* Register a new pointcut designator handler with the world - this can be used by any pointcut parsers attached to the world.
*
* @param designatorHandler handler for the new pointcut
*/
public void registerPointcutHandler(PointcutDesignatorHandler designatorHandler) {
if (pointcutDesignators == null) {
pointcutDesignators = new HashSet<>();
}
pointcutDesignators.add(designatorHandler);
}
public Set getRegisteredPointcutHandlers() {
if (pointcutDesignators == null) {
return Collections.emptySet();
}
return pointcutDesignators;
}
public void reportMatch(ShadowMunger munger, Shadow shadow) {
}
public boolean isOverWeaving() {
return overWeaving;
}
public void reportCheckerMatch(Checker checker, Shadow shadow) {
}
/**
* @return true if this world has the activation and scope of application of the aspects controlled via aop.xml files
*/
public boolean isXmlConfigured() {
return false;
}
public boolean isAspectIncluded(ResolvedType aspectType) {
return true;
}
/**
* Determine if the named aspect requires a particular type around in order to be useful. The type is named in the aop.xml file
* against the aspect.
*
* @return true if there is a type missing that this aspect really needed around
*/
public boolean hasUnsatisfiedDependency(ResolvedType aspectType) {
return false;
}
public TypePattern getAspectScope(ResolvedType declaringType) {
return null;
}
public Map getFixed() {
return typeMap.tMap;
}
public Map> getExpendable() {
return typeMap.expendableMap;
}
/**
* Ask the type map to demote any types it can - we don't want them anchored forever.
*/
public void demote() {
typeMap.demote();
}
// protected boolean isExpendable(ResolvedType type) {
// if (type.equals(UnresolvedType.OBJECT))
// return false;
// if (type == null)
// return false;
// boolean isExposed = type.isExposedToWeaver();
// boolean nullDele = (type instanceof ReferenceType) ? ((ReferenceType) type).getDelegate() != null : true;
// if (isExposed || !isExposed && nullDele)
// return false;
// return !type.isPrimitiveType();
// }
/**
* Reference types we don't intend to weave may be ejected from the cache if we need the space.
*/
protected boolean isExpendable(ResolvedType type) {
return !type.equals(UnresolvedType.OBJECT) && !type.isExposedToWeaver() && !type.isPrimitiveType()
&& !type.isPrimitiveArray();
}
// map from aspect > excluded types
// memory issue here?
private Map> exclusionMap = new HashMap<>();
public Map> getExclusionMap() {
return exclusionMap;
}
private TimeCollector timeCollector = null;
/**
* Record the time spent matching a pointcut - this will accumulate over the lifetime of this world/weaver and be reported every
* 25000 join points.
*/
public void record(Pointcut pointcut, long timetaken) {
if (timeCollector == null) {
ensureAdvancedConfigurationProcessed();
timeCollector = new TimeCollector(this);
}
timeCollector.record(pointcut, timetaken);
}
/**
* Record the time spent fastmatching a pointcut - this will accumulate over the lifetime of this world/weaver and be reported
* every 250 types.
*/
public void recordFastMatch(Pointcut pointcut, long timetaken) {
if (timeCollector == null) {
ensureAdvancedConfigurationProcessed();
timeCollector = new TimeCollector(this);
}
timeCollector.recordFastMatch(pointcut, timetaken);
}
public void reportTimers() {
if (timeCollector != null && !timingPeriodically) {
timeCollector.report();
timeCollector = new TimeCollector(this);
}
}
private static class TimeCollector {
private World world;
long joinpointCount;
long typeCount;
long perJoinpointCount;
long perTypes;
Map joinpointsPerPointcut = new HashMap<>();
Map timePerPointcut = new HashMap<>();
Map fastMatchTimesPerPointcut = new HashMap<>();
Map fastMatchTypesPerPointcut = new HashMap<>();
TimeCollector(World world) {
this.perJoinpointCount = world.timersPerJoinpoint;
this.perTypes = world.timersPerType;
this.world = world;
this.joinpointCount = 0;
this.typeCount = 0;
this.joinpointsPerPointcut = new HashMap<>();
this.timePerPointcut = new HashMap<>();
}
public void report() {
long totalTime = 0L;
for (String p : joinpointsPerPointcut.keySet()) {
totalTime += timePerPointcut.get(p);
}
world.getMessageHandler().handleMessage(
MessageUtil.info("Pointcut matching cost (total=" + (totalTime / 1000000) + "ms for " + joinpointCount
+ " joinpoint match calls):"));
for (String p : joinpointsPerPointcut.keySet()) {
StringBuilder sb = new StringBuilder();
sb.append("Time:" + (timePerPointcut.get(p) / 1000000) + "ms (jps:#" + joinpointsPerPointcut.get(p)
+ ") matching against " + p);
world.getMessageHandler().handleMessage(MessageUtil.info(sb.toString()));
}
world.getMessageHandler().handleMessage(MessageUtil.info("---"));
totalTime = 0L;
for (String p : fastMatchTimesPerPointcut.keySet()) {
totalTime += fastMatchTimesPerPointcut.get(p);
}
world.getMessageHandler().handleMessage(
MessageUtil.info("Pointcut fast matching cost (total=" + (totalTime / 1000000) + "ms for " + typeCount
+ " fast match calls):"));
for (String p : fastMatchTimesPerPointcut.keySet()) {
StringBuilder sb = new StringBuilder();
sb.append("Time:" + (fastMatchTimesPerPointcut.get(p) / 1000000) + "ms (types:#" + fastMatchTypesPerPointcut.get(p)
+ ") fast matching against " + p);
world.getMessageHandler().handleMessage(MessageUtil.info(sb.toString()));
}
world.getMessageHandler().handleMessage(MessageUtil.info("---"));
}
void record(Pointcut pointcut, long timetakenInNs) {
joinpointCount++;
String pointcutText = pointcut.toString();
Long jpcounter = joinpointsPerPointcut.get(pointcutText);
if (jpcounter == null) {
jpcounter = 1L;
} else {
jpcounter++;
}
joinpointsPerPointcut.put(pointcutText, jpcounter);
Long time = timePerPointcut.get(pointcutText);
if (time == null) {
time = timetakenInNs;
} else {
time += timetakenInNs;
}
timePerPointcut.put(pointcutText, time);
if (world.timingPeriodically) {
if ((joinpointCount % perJoinpointCount) == 0) {
long totalTime = 0L;
for (String p : joinpointsPerPointcut.keySet()) {
totalTime += timePerPointcut.get(p);
}
world.getMessageHandler().handleMessage(
MessageUtil.info("Pointcut matching cost (total=" + (totalTime / 1000000) + "ms for " + joinpointCount
+ " joinpoint match calls):"));
for (String p : joinpointsPerPointcut.keySet()) {
StringBuilder sb = new StringBuilder();
sb.append("Time:" + (timePerPointcut.get(p) / 1000000) + "ms (jps:#" + joinpointsPerPointcut.get(p)
+ ") matching against " + p);
world.getMessageHandler().handleMessage(MessageUtil.info(sb.toString()));
}
world.getMessageHandler().handleMessage(MessageUtil.info("---"));
}
}
}
void recordFastMatch(Pointcut pointcut, long timetakenInNs) {
typeCount++;
String pointcutText = pointcut.toString();
Long typecounter = fastMatchTypesPerPointcut.get(pointcutText);
if (typecounter == null) {
typecounter = 1L;
} else {
typecounter++;
}
fastMatchTypesPerPointcut.put(pointcutText, typecounter);
Long time = fastMatchTimesPerPointcut.get(pointcutText);
if (time == null) {
time = timetakenInNs;
} else {
time += timetakenInNs;
}
fastMatchTimesPerPointcut.put(pointcutText, time);
if (world.timingPeriodically) {
if ((typeCount % perTypes) == 0) {
long totalTime = 0L;
for (String p : fastMatchTimesPerPointcut.keySet()) {
totalTime += fastMatchTimesPerPointcut.get(p);
}
world.getMessageHandler().handleMessage(
MessageUtil.info("Pointcut fast matching cost (total=" + (totalTime / 1000000) + "ms for " + typeCount
+ " fast match calls):"));
for (String p : fastMatchTimesPerPointcut.keySet()) {
StringBuilder sb = new StringBuilder();
sb.append("Time:" + (fastMatchTimesPerPointcut.get(p) / 1000000) + "ms (types:#"
+ fastMatchTypesPerPointcut.get(p) + ") fast matching against " + p);
world.getMessageHandler().handleMessage(MessageUtil.info(sb.toString()));
}
world.getMessageHandler().handleMessage(MessageUtil.info("---"));
}
}
}
}
public TypeMap getTypeMap() {
return typeMap;
}
public static void reset() {
// ResolvedType.resetPrimitives();
}
/**
* Returns the version of ITD that this world wants to create. The default is the new style (2) but in some cases where there
* might be a clash, the old style can be used. It is set through the option -Xset:itdVersion=1
*
* @return the ITD version this world wants to create - 1=oldstyle 2=new, transparent style
*/
public int getItdVersion() {
return itdVersion;
}
// if not loadtime weaving then we are compile time weaving or post-compile time weaving
public abstract boolean isLoadtimeWeaving();
public void classWriteEvent(char[][] compoundName) {
// override if interested in write events
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy