diff options
author | wisberg <wisberg> | 2002-12-16 17:58:19 +0000 |
---|---|---|
committer | wisberg <wisberg> | 2002-12-16 17:58:19 +0000 |
commit | d842c4f1139629c1f062b74ba818d233b2c31043 (patch) | |
tree | 842d3871620bc0eb60edcd95e55804d67e0f61fa /weaver | |
parent | 3ce247199704eae6b2c92c6e38c69584e3250c52 (diff) | |
download | aspectj-d842c4f1139629c1f062b74ba818d233b2c31043.tar.gz aspectj-d842c4f1139629c1f062b74ba818d233b2c31043.zip |
initial version
Diffstat (limited to 'weaver')
257 files changed, 35118 insertions, 0 deletions
diff --git a/weaver/.classpath b/weaver/.classpath new file mode 100644 index 000000000..17ae558e0 --- /dev/null +++ b/weaver/.classpath @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="testsrc"/> + <classpathentry kind="var" path="JRE_LIB" rootpath="JRE_SRCROOT" sourcepath="JRE_SRC"/> + <classpathentry kind="src" path="/runtime"/> + <classpathentry kind="lib" path="/lib/bcel/bcel.jar" + rootpath="bcel-5.0/src/java" sourcepath="/lib/bcel/bcel-src.zip"/> + <classpathentry kind="lib" path="/lib/junit/junit.jar" sourcepath="/lib/junit/src.jar"/> + <classpathentry kind="src" path="/util"/> + <classpathentry kind="src" path="/testing-util"/> + <classpathentry kind="src" path="/bridge"/> + <classpathentry kind="src" path="/asm"/> + <classpathentry kind="output" path="bin"/> +</classpath> diff --git a/weaver/.project b/weaver/.project new file mode 100644 index 000000000..940c812a5 --- /dev/null +++ b/weaver/.project @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>weaver</name> + <comment></comment> + <projects> + <project>asm</project> + <project>bridge</project> + <project>runtime</project> + <project>testing-util</project> + <project>util</project> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/weaver/bcelIssues.txt b/weaver/bcelIssues.txt new file mode 100644 index 000000000..14bf0b16d --- /dev/null +++ b/weaver/bcelIssues.txt @@ -0,0 +1,12 @@ +* updateTarget doesn't work with exnTargets, in particular, when the startPC and endPC are the same handle. + +* RemoveNOP doesn't work properly with exnTargets (and, much less importantly, local variable tables), + because it always retargets to the NEXT instruction... the endPC should retarget to the LAST instruction. + +* parameter names aren't set correctly (to anything) when a MethodGen is read from a Method. + +* the superclassname of java.lang.object is set to java.lang.object (!!) + +* RET should be a local variable instruction + + diff --git a/weaver/features.txt b/weaver/features.txt new file mode 100644 index 000000000..2c62391eb --- /dev/null +++ b/weaver/features.txt @@ -0,0 +1,305 @@ +AspectJ 1.1 Features +------------------------------------------------------------ + + +------------------------------ +About this document + +This document contains information about the proposed features of +AspectJ 1.1. It assumes as a baseline that AspectJ 1.1 includes all +the features of AspectJ 1.0.6. Any feature difference, especially +incompatible changes, should be noted. It is organized by DOWNLOAD. +Inside the tools download there are sections per feature. + +Feel free to just stick shorthand notes at the end of this file, and +move them up to the New Features (or other) section as we want. + + +------------------------------ +OPEN ISSUES + +* -sourceroots/-injars matrix completeness + +* do we release ant tasks in beta? + +* do we call beta alpha or alpha beta? + +------------------------------ +DOWNLOAD: Tools + +General deliverables: Two licence files. A readme. Possibly a changes. + +---- runtime + +Deliverable: aspectjrt.jar + +Changes: + +* RUNTIME_LICENCE: AspectjRT.jar now has a BSD-style licence [NOT BETA] + +* JOINPOINT_NAMES: Added constant fields holding constant names for + the join points. + +* NO_COLUMN_NUMBER: thisJoinPoint.getSourceLocation().getColumn() + is incompatible with bytecode weaving and can not be supported. + Do we want to remove the method or make it return -1? + +* NOT_10_BINARY_COMPATIBLE: Some modifications to classes in internal + packages means that code built with 1.1 won't run on the 1.0 version + of aspectjrt.jar. + [XXX this has always been true and sounds more scary than it is. + The readme/docs do/should always say that you need to compile and + run with at least the same version of the runtime classes as + the compiler] + +---- tools + +Deliverable: aspectjtools.jar + +* Single jar containing .class files for all components listed below. + This will contain code under both the CPL and the MPL. + +---- ajc + +Deliverable: ajc, ajc.bat + +Changes: + +-- new features +* NO_SOURCE: -source/-usejavac options are not supported [INCOMPATIBLE] + +* SOURCEROOT: -sourceroots option indicates that all source files in + a particular directory tree should be compiled [NEW] + This option is the only way that sourcefiles can currently be + specified for incremental compilation on the command-line. + +* BYTECODE_WEAVING: supporting bytecode-containing jar files as input + for the compiler. [NEW] + * Command-line: -injars option + Not supported in incremental mode. + * Eclipse: not supported [BETA] + This has a ripple effect on "code the compiler controls" issues. + There are obfustication issues that should be discussed in the readme + +* OUTJAR: supports generating a single .jar file with the results of a + compilation, rather than separate .class files. This should be + most useful when weaving into existing .jar files. The resulting jar + file has no meta-information, just classes. [question: compression level?] + [NEW] + +* BINARY_ASPECTS: Aspects may be compiled to a standalone bytecode + form, and later be used in a linking/compiling phase to affect join + points. [NEW] + This will only be partially working in beta1: The front-end is not + reading the binary aspects. [BETA] + +* INCREMENTAL: incremental compilation [NEW] + * Command-line: interface is using -sourceroots and typing <enter> + for an incremental recompile. Better interfaces are possible + in the future. + * Eclipse: invisible + * JBuilder/Netbeans: ?? + * Emacs: possibly using new command-line interface? + * Ant: unsupported in BETA + +* NORMAL_OPTIONS: now supporting many javac options ajc failed to in 1.0: + essentially those supported in the ECLIPSE_OPTIONS [NEW] + +* ECLIPSE_OPTIONS: The eclipse compiler provides a large number of + options for controlling its behavior, i.e. -warn:unusedLocals. All + of these options may be passed to the command-line ajc compiler. Mik should + be bugged to get full list and description of the options [NEW] + + +-- features not supported yet + +* NO_WEAVE: An option with unknown name that generates code but does + no back-end weaving [NO BETA] + +* SOURCE_INFORMATION: Source file information in error messages may be + either better or worse (depending on how well we do our eclipse + integration, this may not happen). [INCOMPATIBLE, MINIMAL] + JSR 45 information is not created/maintained. [BETA] + +* NO_AROUND_OPTIMIZATION: -XinlineAroundClosure not implemented. + [INCOMPATIBLE] No inlining at all [BETA]. + +* NO_CALLEE_SIDE_CALL: Not implemented [BETA] + +* OTHER_X_OPTIONS: XaddSafePrefix (not used anymore, but we make some + weak guarantees about this), XserializableAspects [see below] + XTargetNearSource [see below] + + +-- features no longer supported +* NO_SOURCE: -preprocess/-usejavac/-nocomment/-workingdir options are + not supported [INCOMPATIBLE] + +* NO_STRICT_LENIENT: The -strict/-lenient flags are no longer + supported, since we no longer own the compiler [INCOMPATIBLE, MINIMAL] + + +* NO_PORTING: The -porting flag is no longer supported. + +---- Ajdb + +* NO_AJDB: Ajdb is no longer supported, shipped, talked about, + seen, or believed to exist. We write a nice couple of paragraphs + about JSR 45. [INCOMPATIBLE] + + +---- Ajdoc + +* NO_AJDOC: Ajdoc is not provided [BETA, possibly but not certainly + FINAL as well] + +---- ajbrowser + +* NO_CROSSCUTTING_STRUCTURE: Crosscutting structure is not shown + [BETA_ONLY] + + +------------------------------ +DOWNLOADS: AJDE for Jbuilder, AJDE for Netbeans, AJDE for Emacs + +Deliverables: 3 downloads, same as 1.0.6 (Mik, expand?) + +Changes: + +* NO_AJDE_INCREMENTAL_COMPILATION: the 1.1 compiler will only + work in batch mode [BETA_ONLY] + +* NO_TARGET_NEAR_SOURCE: -XTargetNearSource option is not supported in + the 1.1 command-line compiler. [INCOMPATIBLE] + + +------------------------------ +DOWNLOAD: ajc ant tasks + +Deliverables: 1 download, same as 1.0.6 + +Changes: + - adding experimental taskdef based on DefaultCompilerAdapter + - updated taskdef to use new compiler interface + - neither support incremental mode [XXX leave ant running, touch tag file?] + +------------------------------ +DOWNLOAD: Source distributions + +Tools Source: completely revamped, includes license for org.eclipse package +AJDE-JBuilder Source: basically the same, if aspectjtools.jar is one jar +AJDE-Netbeans Source: basically the same, if aspectjtools.jar is one jar + +------------------------------ +DOWNLOAD: Documentation + +Deliverable: 1 or 0 downloads. Main deliverable is fleshed-out +version of this document with outgoing links to bare or updated 1.0.6 +documentation. + +Changes (language changes): + +* THROWS_PATTERN: Typename patterns are allowed in place of typenames + in throws clauses. This is + http://aspectj.org/home/hugunin/features11.html#throws-patterns [NEW] + +* CALLEE_SIDE_CALLS: 1.1 may pick out different callee-side call join + points than 1.0.6 on the same code. [INCOMPATIBLE] + +* SINGLE_INTERCLASS_TARGET: 1.1 does not allow inter-class + declarations to be made with a TypePattern as target. (workaround + available, defense can be presented if asked). [INCOMPATIBLE] + +* SINGLE_TYPENAME_PATTERN_TARGET: A simple type-name pattern with no + wildcard can match no more than one type. The type that it matches + is determined at compile-time. [INCOMPATIBLE] + [THIS IS NO LONGER THE CASE, SO IT IS NOT DOCUMENTED AS SUCH] + +* ASPECT_PRECEDENCE: Dominates is replaced/mirrored with alternate + declare-space specification, or it's not. (??) [INCOMPATIBLE, or + NEW, or NOTHING] + +* UNAVAILABLE_JOIN_POINTS: [INCOMPATIBLE, MINIMAL] + * Initializer Execution join points no longer exist. The + information needed to pick them out doesn't exist in bytecode. + there was not kinded pcd for it, and we're not sure anyone will + actually notice the difference. + * Others? (??) + +* CONSTRUCTOR_EXECUTION_IS_BIGGER: constructor execution join points + (of constructors which call super) include the code for instance + initialization (the code inside the old initializer execution join + point). Again, the information needed to NOT include this code + isn't available in bytecode. This could be a big deal... before + advice on many constructor execution join points will run before the + dynamic initializers run. [INCOMPATIBLE] + +* NEW_PCDS: Kinded PCDs are available for every kind of join + point. This is + http://aspectj.org/home/hugunin/features11.html#kinded-pcds [NEW] + * adviceExecution (spelling?) + * preInitialization (spelling?) + +* WITHIN_MEMBER_TYPES: Within of a member type (NOT a package-level + type) such as within(pkg.Type.MemberType) is not guaranteed to pick + out code inside anonymous and local types. (JLS 13.1). If anyone + cares, we can do tests on jikes/javac/eclipse to see if we actually + do, but this is hopefully a completely minimal issue [INCOMPATIBLE, + MINIMAL]. It is unclear if this is a fundamental limitation of + bytecode weaving or if it can be fixed with further work. + + +Documentation caveats: + +- example code not updated [XXX?] +- quick ref +- + +------------------------------ +Future work + +There are a number of changes that clearly would be either useful or +easy (hopefully things that are both useful and easy are already +done), but we don't plan to actually ship them in 1.1. + +* HANDLER_EXCLUDES_NON_EXCEPTIONS: (PR826) + +* SUPERTYPES_TYPE_PATTERN: + +* DYNAMIC_CLASSLOADER_WEAVER: + +* SOURCE_WEAVING: + +------------------------------ +Shorthand notes + +- no optimizations for per* aspects + +- declare soft unimplemented [this is on the table for not doing for beta] + +- privileged unimplemented [this is on the table for not doing for beta] + +- declare dominates (?) [decided before beta] + +- declare error/warning source locations are weaker than just missing column [BETA] + + +- a note for the dangerous bends section of the programming guide + + Base.m() throws IOException + Derived.m() [no throws] + + call(void Base.m() throws IOException) + --> this doesn't match new Derived().m(), but will without the throws + + +- The status of the -XserializableAspects flag is iceberg-like. + +- Don't implement intra-type static members onto interfaces + +- Don't handle introduced fields with constant values + +- no crosscuting structure means no inline annotations w/ -emacssym, but speedbar still + shows declaration tree + + diff --git a/weaver/src/.cvsignore b/weaver/src/.cvsignore new file mode 100644 index 000000000..defacf099 --- /dev/null +++ b/weaver/src/.cvsignore @@ -0,0 +1,2 @@ +bcweaver.lst +bcweaverSrc.lst diff --git a/weaver/src/org/aspectj/weaver/Advice.java b/weaver/src/org/aspectj/weaver/Advice.java new file mode 100644 index 000000000..e20627ab0 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/Advice.java @@ -0,0 +1,243 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.util.*; +import java.util.List; + +import org.aspectj.bridge.MessageUtil; +import org.aspectj.weaver.patterns.*; + +public abstract class Advice extends ShadowMunger { + + protected AdviceKind kind; + protected Member signature; + protected int extraParameterFlags; + protected int lexicalPosition; + + // not necessarily declaring aspect, this is a semantics change from 1.0 + protected ResolvedTypeX concreteAspect; // null until after concretize + + protected List innerCflowEntries = Collections.EMPTY_LIST; // just for cflow*Entry kinds + protected int nFreeVars; // just for cflow*Entry kinds + + protected TypePattern exceptionType; // just for Softener kind + + public static Advice makeCflowEntry(World world, Pointcut entry, boolean isBelow, Member stackField, int nFreeVars, List innerCflowEntries) { + Advice ret = world.concreteAdvice(isBelow ? AdviceKind.CflowBelowEntry : AdviceKind.CflowEntry, + entry, stackField, 0, entry); + //0); + ret.innerCflowEntries = innerCflowEntries; + ret.nFreeVars = nFreeVars; + return ret; + } + + public static Advice makePerCflowEntry(World world, Pointcut entry, boolean isBelow, + Member stackField, ResolvedTypeX inAspect, List innerCflowEntries) + { + Advice ret = world.concreteAdvice(isBelow ? AdviceKind.PerCflowBelowEntry : AdviceKind.PerCflowEntry, + entry, stackField, 0, entry); + ret.innerCflowEntries = innerCflowEntries; + ret.concreteAspect = inAspect; + return ret; + } + + public static Advice makePerObjectEntry(World world, Pointcut entry, boolean isThis, + ResolvedTypeX inAspect) + { + Advice ret = world.concreteAdvice(isThis ? AdviceKind.PerThisEntry : AdviceKind.PerTargetEntry, + entry, null, 0, entry); + + ret.concreteAspect = inAspect; + return ret; + } + + public static Advice makeSoftener(World world, Pointcut entry, TypePattern exceptionType) { + Advice ret = world.concreteAdvice(AdviceKind.Softener, + entry, null, 0, entry); + + ret.exceptionType = exceptionType; + //System.out.println("made ret: " + ret + " with " + exceptionType); + return ret; + } + + + public Advice(AdviceKind kind, Pointcut pointcut, Member signature, + int extraParameterFlags, int start, int end, ISourceContext sourceContext) + { + super(pointcut, start, end, sourceContext); + this.kind = kind; + this.signature = signature; + this.extraParameterFlags = extraParameterFlags; + this.lexicalPosition = start; //XXX should go away + } + + + public boolean match(Shadow shadow, World world) { + if (super.match(shadow, world)) { + if (hasExtraParameter() && kind == AdviceKind.AfterReturning) { + return getExtraParameterType().isConvertableFrom(shadow.getReturnType(), world); + } else if (kind == AdviceKind.PerTargetEntry) { + return shadow.hasTarget(); + } else if (kind == AdviceKind.PerThisEntry) { + return shadow.hasThis(); + } else if (kind == AdviceKind.Around) { + if (shadow.getKind() == Shadow.PreInitialization) { + world.getMessageHandler().handleMessage( + MessageUtil.error("Around on pre-initialization not supported in 1.1", + getSourceLocation())); + world.getMessageHandler().handleMessage( + MessageUtil.error("Around on pre-initialization not supported in 1.1", + shadow.getSourceLocation())); + return false; + } else { + if (!getSignature().getReturnType().isConvertableFrom(shadow.getReturnType(), world)) { + //System.err.println(this + ", " + sourceContext + ", " + start); + + world.getMessageHandler().handleMessage( + MessageUtil.error("incompatible return type applying to " + shadow, + getSourceLocation())); + //XXX need a crosscutting error message here + return false; + } + } + } + return true; + } else { + return false; + } + } + + + // ---- + + public AdviceKind getKind() { + return kind; + } + + public Member getSignature() { + return signature; + } + + public boolean hasExtraParameter() { + return (extraParameterFlags & ExtraArgument) != 0; + } + + protected int getExtraParameterCount() { + return countOnes(extraParameterFlags & ParameterMask); + } + + public static int countOnes(int bits) { + int ret = 0; + while (bits != 0) { + if ((bits & 1) != 0) ret += 1; + bits = bits >> 1; + } + return ret; + } + + public int getBaseParameterCount() { + return signature.getParameterTypes().length - getExtraParameterCount(); + } + + public TypeX getExtraParameterType() { + if (!hasExtraParameter()) return ResolvedTypeX.MISSING; + return signature.getParameterTypes()[getBaseParameterCount()]; + } + + public TypeX getDeclaringAspect() { + return signature.getDeclaringType(); + } + + protected String extraParametersToString() { + if (extraParameterFlags == 0) { + return ""; + } else { + return "(extraFlags: " + extraParameterFlags + ")"; + } + } + + public Pointcut getPointcut() { + return pointcut; + } + + // ---- + + /** @param fromType is guaranteed to be a non-abstract aspect + * @param perClause has been concretized at a higher level + */ + public ShadowMunger concretize(ResolvedTypeX fromType, World world, PerClause clause) { + // assert !fromType.isAbstract(); + Pointcut p = pointcut.concretize(fromType, signature.getArity(), this); + if (clause != null) { + p = new AndPointcut(clause, p); + p.state = Pointcut.CONCRETE; + } + + Advice munger = world.concreteAdvice(kind, p, signature, extraParameterFlags, start, end, sourceContext); + munger.concreteAspect = fromType; + //System.err.println("concretizing here " + p + " with clause " + clause); + return munger; + } + + // ---- from object + + public String toString() { + return "(" + + getKind() + + extraParametersToString() + + ": " + + pointcut + + "->" + + signature + + ")"; + } + public boolean equals(Object other) { + if (! (other instanceof Advice)) return false; + Advice o = (Advice) other; + return o.kind == kind && o.pointcut.equals(pointcut) && o.signature.equals(signature) && + o.extraParameterFlags == extraParameterFlags; + } + private volatile int hashCode = 0; + public int hashCode() { + if (hashCode == 0) { + int result = 17; + result = 37*result + kind.hashCode(); + result = 37*result + pointcut.hashCode(); + if (signature != null) result = 37*result + signature.hashCode(); + hashCode = result; + } + return hashCode; + } + + // ---- fields + + + public static final int ExtraArgument = 1; + public static final int ThisJoinPoint = 2; + public static final int ThisJoinPointStaticPart = 4; + public static final int ThisEnclosingJoinPointStaticPart = 8; + public static final int ParameterMask = 0xf; + + public static final int CanInline = 0x40; + + public void setLexicalPosition(int lexicalPosition) { + this.lexicalPosition = lexicalPosition; + } + + public ResolvedTypeX getConcreteAspect() { + return concreteAspect; + } + +} diff --git a/weaver/src/org/aspectj/weaver/AdviceKind.java b/weaver/src/org/aspectj/weaver/AdviceKind.java new file mode 100644 index 000000000..17e94328c --- /dev/null +++ b/weaver/src/org/aspectj/weaver/AdviceKind.java @@ -0,0 +1,110 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; + +import org.aspectj.util.TypeSafeEnum; + +/** + * The 5 kinds of advice in AspectJ. + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public class AdviceKind extends TypeSafeEnum { + private int precedence; + private boolean isAfter; + private boolean isCflow; + public AdviceKind(String name, int key, int precedence, boolean isAfter, boolean isCflow) { + super(name, key); + this.precedence = precedence; + this.isAfter = isAfter; + this.isCflow = isCflow; + } + + public static AdviceKind read(DataInputStream s) throws IOException { + int key = s.readByte(); + switch(key) { + case 1: return Before; + case 2: return After; + case 3: return AfterThrowing; + case 4: return AfterReturning; + case 5: return Around; + case 6: return CflowEntry; + case 7: return CflowBelowEntry; + + case 8: return InterInitializer; + + case 9: return PerCflowEntry; + case 10: return PerCflowBelowEntry; + case 11: return PerThisEntry; + case 12: return PerTargetEntry; + + case 13: return Softener; + } + throw new RuntimeException("unimplemented kind: " + key); + } + + public static final AdviceKind Before = new AdviceKind("before", 1, 0, false, false); + public static final AdviceKind After = new AdviceKind("after", 2, 0, true, false); + public static final AdviceKind AfterThrowing = new AdviceKind("afterThrowing", 3, 0, true, false); + public static final AdviceKind AfterReturning = new AdviceKind("afterReturning", 4, 0, true, false); + public static final AdviceKind Around = new AdviceKind("around", 5, 0, false, false); + + // these kinds can't be declared, but are used by the weaver + public static final AdviceKind CflowEntry = new AdviceKind("cflowEntry", 6, 1, false, true); + public static final AdviceKind CflowBelowEntry = new AdviceKind("cflowBelowEntry", 7, -1, false, true); //XXX resolve precednece with the below + public static final AdviceKind InterInitializer = new AdviceKind("interInitializer", 8, -2, false, false); + + public static final AdviceKind PerCflowEntry = new AdviceKind("perCflowEntry", 9, 1, false, true); + public static final AdviceKind PerCflowBelowEntry = new AdviceKind("perCflowBelowEntry", 10, -1, false, true); + + public static final AdviceKind PerThisEntry = new AdviceKind("perThisEntry", 11, 1, false, false); + public static final AdviceKind PerTargetEntry = new AdviceKind("perTargetEntry", 12, 1, false, false); + + public static final AdviceKind Softener = new AdviceKind("softener", 13, 1, false, false); + + + public static AdviceKind stringToKind(String s) { + if (s.equals(Before.getName())) return Before; + if (s.equals(After.getName())) return After; + if (s.equals(AfterThrowing.getName())) return AfterThrowing; + if (s.equals(AfterReturning.getName())) return AfterReturning; + if (s.equals(Around.getName())) return Around; + throw new IllegalArgumentException("unknown kind: " + "\"" + s + "\""); + } + + public boolean isAfter() { + return this.isAfter; + } + + public boolean isCflow() { + return this.isCflow; + } + + public int getPrecedence() { + return precedence; + } + + public boolean isPerEntry() { + return this == PerCflowEntry || this == PerCflowBelowEntry || + this == PerThisEntry || this == PerTargetEntry; + } + + public boolean isPerObjectEntry() { + return this == PerThisEntry || this == PerTargetEntry; + } + +} diff --git a/weaver/src/org/aspectj/weaver/AjAttribute.java b/weaver/src/org/aspectj/weaver/AjAttribute.java new file mode 100644 index 000000000..864513371 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/AjAttribute.java @@ -0,0 +1,411 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; + +import org.aspectj.util.FileUtil; +import org.aspectj.weaver.patterns.*; + +/** + * These attributes are written to and read from .class files (see the JVM spec). + * + * <p>Each member or type can have a number of AjAttributes. Each + * such attribute is in 1-1 correspondence with an Unknown bcel attribute. + * Creating one of these does NOTHING to the underlying thing, so if you really + * want to add an attribute to a particular thing, well, you'd better actually do that. + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public abstract class AjAttribute { + + public static final String AttributePrefix = "org.aspectj.weaver"; + + protected abstract void write(DataOutputStream s) throws IOException; + + public abstract String getNameString(); + public char[] getNameChars() { + return getNameString().toCharArray(); + } + + /** + * Just writes the contents + */ + public byte[] getBytes() { + try { + ByteArrayOutputStream b0 = new ByteArrayOutputStream(); + DataOutputStream s0 = new DataOutputStream(b0); + write(s0); + return b0.toByteArray(); + } catch (IOException e) { + // shouldn't happen with ByteArrayOutputStreams + throw new RuntimeException("sanity check"); + } + } + + /** + * Writes the full attribute, i.e. name_index, length, and contents + */ + public byte[] getAllBytes(short nameIndex) { + try { + byte[] bytes = getBytes(); + + ByteArrayOutputStream b0 = new ByteArrayOutputStream(); + DataOutputStream s0 = new DataOutputStream(b0); + + s0.writeShort(nameIndex); + s0.writeInt(bytes.length); + s0.write(bytes); + return b0.toByteArray(); + } catch (IOException e) { + // shouldn't happen with ByteArrayOutputStreams + throw new RuntimeException("sanity check"); + } + } + + public static AjAttribute read(String name, byte[] bytes, ISourceContext context) { + try { + if (bytes == null) bytes = new byte[0]; + DataInputStream s = new DataInputStream(new ByteArrayInputStream(bytes)); + if (name.equals(Aspect.AttributeName)) { + return new Aspect(PerClause.readPerClause(s, context)); + } else if (name.equals(WeaverState.AttributeName)) { + return new WeaverState(WeaverStateKind.read(s)); + } else if (name.equals(AdviceAttribute.AttributeName)) { + return AdviceAttribute.read(s, context); + } else if (name.equals(PointcutDeclarationAttribute.AttributeName)) { + return new PointcutDeclarationAttribute(ResolvedPointcutDefinition.read(s, context)); + } else if (name.equals(TypeMunger.AttributeName)) { + return new TypeMunger(ResolvedTypeMunger.read(s, context)); + } else if (name.equals(AjSynthetic.AttributeName)) { + return new AjSynthetic(); + } else if (name.equals(DeclareAttribute.AttributeName)) { + return new DeclareAttribute(Declare.read(s, context)); + } else if (name.equals(PrivilegedAttribute.AttributeName)) { + return PrivilegedAttribute.read(s, context); + } else if (name.equals(SourceContextAttribute.AttributeName)) { + return SourceContextAttribute.read(s); + } else if (name.equals(EffectiveSignatureAttribute.AttributeName)) { + return EffectiveSignatureAttribute.read(s, context); + } else { + throw new BCException("unknown attribute" + name); + } + } catch (IOException e) { + throw new BCException("malformed " + name + " attribute " + e); + } + } + + //---- + + /** Synthetic members should have NO advice put on them or on their contents. + * This attribute is currently unused as we consider all members starting + * with NameMangler.PREFIX to automatically be synthetic. As we use this we might + * find that we want multiple + * kinds of synthetic. In particular, if we want to treat the call to a synthetic getter + * (say, of an introduced field) as a field reference itself, then a method might want + * a particular kind of AjSynthetic attribute that also includes a signature of what + * it stands for. + */ + public static class AjSynthetic extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.AjSynthetic"; + + public String getNameString() { + return AttributeName; + } + private ResolvedTypeMunger munger; + public AjSynthetic() {} + + public void write(DataOutputStream s) throws IOException {} + } + + public static class TypeMunger extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.TypeMunger"; + + public String getNameString() { + return AttributeName; + } + private ResolvedTypeMunger munger; + public TypeMunger(ResolvedTypeMunger munger) { + this.munger = munger; + } + + public void write(DataOutputStream s) throws IOException { + munger.write(s); + } + + public ConcreteTypeMunger reify(World world, ResolvedTypeX aspectType) { + return world.concreteTypeMunger(munger, aspectType); + } + } + + public static class WeaverState extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.WeaverState"; + + public String getNameString() { + return AttributeName; + } + private WeaverStateKind kind; + public WeaverState(WeaverStateKind kind) { + this.kind = kind; + } + public void write(DataOutputStream s) throws IOException { + kind.write(s); + } + + public WeaverStateKind reify() { + return kind; + } + } + + public static class SourceContextAttribute extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.SourceContext"; + + public String getNameString() { + return AttributeName; + } + + private String sourceFileName; + private int[] lineBreaks; + + public SourceContextAttribute(String sourceFileName, int[] lineBreaks) { + this.sourceFileName = sourceFileName; + this.lineBreaks = lineBreaks; + } + public void write(DataOutputStream s) throws IOException { + s.writeUTF(sourceFileName); + FileUtil.writeIntArray(s, lineBreaks); + } + + public static SourceContextAttribute read(DataInputStream s) throws IOException { + return new SourceContextAttribute(s.readUTF(), FileUtil.readIntArray(s)); + } + public int[] getLineBreaks() { + return lineBreaks; + } + + public String getSourceFileName() { + return sourceFileName; + } + } + + public static class PointcutDeclarationAttribute extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.PointcutDeclaration"; + + public String getNameString() { + return AttributeName; + } + + private ResolvedPointcutDefinition pointcutDef; + public PointcutDeclarationAttribute(ResolvedPointcutDefinition pointcutDef) { + this.pointcutDef = pointcutDef; + } + public void write(DataOutputStream s) throws IOException { + pointcutDef.write(s); + } + + public ResolvedPointcutDefinition reify() { + return pointcutDef; + } + } + + public static class DeclareAttribute extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.Declare"; + + public String getNameString() { + return AttributeName; + } + + private Declare declare; + public DeclareAttribute(Declare declare) { + this.declare = declare; + } + public void write(DataOutputStream s) throws IOException { + declare.write(s); + } + + public Declare getDeclare() { + return declare; + } + } + + public static class AdviceAttribute extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.Advice"; + + public String getNameString() { + return AttributeName; + } + + private AdviceKind kind; + private Pointcut pointcut; + private int extraArgumentFlags; + private int start; + private int end; + private ISourceContext sourceContext; + + /** + * @param lexicalPosition must be greater than the lexicalPosition + * of any advice declared before this one in an aspect, otherwise, + * it can be any value. + */ + public AdviceAttribute(AdviceKind kind, Pointcut pointcut, int extraArgumentFlags, int start, int end, ISourceContext sourceContext) { + this.kind = kind; + this.pointcut = pointcut; + this.extraArgumentFlags = extraArgumentFlags; + this.start = start; + this.end = end; + this.sourceContext = sourceContext; + } + + public static AdviceAttribute read(DataInputStream s, ISourceContext context) throws IOException { + return new AdviceAttribute( + AdviceKind.read(s), + Pointcut.read(s, context), + s.readByte(), + s.readInt(), s.readInt(), context); + } + + public void write(DataOutputStream s) throws IOException { + kind.write(s); + pointcut.write(s); + s.writeByte(extraArgumentFlags); + s.writeInt(start); + s.writeInt(end); + } + public Advice reify(Member signature, World world) { + return world.concreteAdvice(kind, pointcut, signature, extraArgumentFlags, start, end, sourceContext); + } + + public String toString() { + return "AdviceAttribute(" + kind + ", " + pointcut + ", " + + extraArgumentFlags + ", " + start+")"; + } + + public int getExtraArgumentFlags() { + return extraArgumentFlags; + } + + public AdviceKind getKind() { + return kind; + } + + public Pointcut getPointcut() { + return pointcut; + } + + } + + public static class Aspect extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.Aspect"; + public String getNameString() { + return AttributeName; + } + private PerClause perClause; + + public Aspect(PerClause perClause) { + this.perClause = perClause; + } + + public PerClause reify(ResolvedTypeX inAspect) { + //XXXperClause.concretize(inAspect); + return perClause; + } + + public void write(DataOutputStream s) throws IOException { + perClause.write(s); + } + } + + public static class PrivilegedAttribute extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.Privileged"; + + public String getNameString() { + return AttributeName; + } + + private ResolvedMember[] accessedMembers; + public PrivilegedAttribute(ResolvedMember[] accessedMembers) { + this.accessedMembers = accessedMembers; + } + public void write(DataOutputStream s) throws IOException { + s.writeInt(accessedMembers.length); + for (int i = 0, len = accessedMembers.length; i < len; i++) { + accessedMembers[i].write(s); + } + } + + public ResolvedMember[] getAccessedMembers() { + return accessedMembers; + } + + public static PrivilegedAttribute read(DataInputStream s, ISourceContext context) throws IOException { + int len = s.readInt(); + ResolvedMember[] members = new ResolvedMember[len]; + for (int i=0; i < len; i++) { + members[i] = ResolvedMember.readResolvedMember(s, context); + } + return new PrivilegedAttribute(members); + } + } + + + public static class EffectiveSignatureAttribute extends AjAttribute { + public static final String AttributeName = "org.aspectj.weaver.EffectiveSignature"; + + public String getNameString() { + return AttributeName; + } + + private ResolvedMember effectiveSignature; + private Shadow.Kind shadowKind; + private boolean weaveBody; + public EffectiveSignatureAttribute(ResolvedMember effectiveSignature, Shadow.Kind shadowKind, boolean weaveBody) { + this.effectiveSignature = effectiveSignature; + this.shadowKind = shadowKind; + this.weaveBody = weaveBody; + } + public void write(DataOutputStream s) throws IOException { + effectiveSignature.write(s); + shadowKind.write(s); + s.writeBoolean(weaveBody); + } + + public static EffectiveSignatureAttribute read(DataInputStream s, ISourceContext context) throws IOException { + return new EffectiveSignatureAttribute( + ResolvedMember.readResolvedMember(s, context), + Shadow.Kind.read(s), + s.readBoolean()); + } + + public ResolvedMember getEffectiveSignature() { + return effectiveSignature; + } + + public String toString() { + return "EffectiveSignatureAttribute(" + effectiveSignature + ", " + shadowKind + ")"; + } + + public Shadow.Kind getShadowKind() { + return shadowKind; + } + + public boolean isWeaveBody() { + return weaveBody; + } + + } + + + +} diff --git a/weaver/src/org/aspectj/weaver/AjcMemberMaker.java b/weaver/src/org/aspectj/weaver/AjcMemberMaker.java new file mode 100644 index 000000000..7996af37f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/AjcMemberMaker.java @@ -0,0 +1,508 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.lang.reflect.Modifier; + + +public class AjcMemberMaker { + private static final int PUBLIC_STATIC_FINAL = + Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL; + + private static final int PRIVATE_STATIC = + Modifier.PRIVATE | Modifier.STATIC; + + private static final int PUBLIC_STATIC = + Modifier.PUBLIC | Modifier.STATIC; + + private static final int VISIBILITY = + Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; + + public static final TypeX CFLOW_STACK_TYPE = + TypeX.forName(NameMangler.CFLOW_STACK_TYPE); + public static final TypeX AROUND_CLOSURE_TYPE = + TypeX.forName("org.aspectj.runtime.internal.AroundClosure"); + + public static final TypeX CONVERSIONS_TYPE = + TypeX.forName("org.aspectj.runtime.internal.Conversions"); + + public static final TypeX NO_ASPECT_BOUND_EXCEPTION = + TypeX.forName("org.aspectj.lang.NoAspectBoundException"); + + public static ResolvedMember ajcClinitMethod(TypeX declaringType) { + return new ResolvedMember( + Member.METHOD, + declaringType, + PRIVATE_STATIC, + NameMangler.AJC_CLINIT_NAME, + "()V"); + } + + public static Member noAspectBoundExceptionInit() { + return new ResolvedMember( + Member.METHOD, + NO_ASPECT_BOUND_EXCEPTION, + Modifier.PUBLIC, + "<init>", + "()V"); + } + + + public static ResolvedMember perCflowPush(TypeX declaringType) { + return new ResolvedMember( + Member.METHOD, + declaringType, + PUBLIC_STATIC, + NameMangler.PERCFLOW_PUSH_METHOD, + "()V"); + } + + public static ResolvedMember perCflowField(TypeX declaringType) { + return new ResolvedMember( + Member.FIELD, + declaringType, + PUBLIC_STATIC_FINAL, + NameMangler.PERCFLOW_FIELD_NAME, + CFLOW_STACK_TYPE.getSignature()); + } + + public static ResolvedMember perSingletonField(TypeX declaringType) { + return new ResolvedMember( + Member.FIELD, + declaringType, + PUBLIC_STATIC_FINAL, + NameMangler.PERSINGLETON_FIELD_NAME, + declaringType.getSignature()); + } + + + public static ResolvedMember perObjectField(TypeX declaringType, ResolvedTypeX aspectType) { + int modifiers = Modifier.PRIVATE; + if (!TypeX.SERIALIZABLE.isAssignableFrom(aspectType, aspectType.getWorld())) { + modifiers |= Modifier.TRANSIENT; + } + return new ResolvedMember( + Member.FIELD, + declaringType, + modifiers, + aspectType, + NameMangler.perObjectInterfaceField(aspectType), + TypeX.NONE); + } + + + public static ResolvedMember perObjectBind(TypeX declaringType) { + return new ResolvedMember( + Member.METHOD, + declaringType, + PUBLIC_STATIC, + NameMangler.PEROBJECT_BIND_METHOD, + "(Ljava/lang/Object;)V"); + } + + + public static TypeX perObjectInterfaceType(TypeX aspectType) { + return TypeX.forName(aspectType.getName()+"$ajcMightHaveAspect"); + } + + public static ResolvedMember perObjectInterfaceGet(TypeX aspectType) { + return new ResolvedMember( + Member.METHOD, + perObjectInterfaceType(aspectType), + Modifier.PUBLIC | Modifier.ABSTRACT, + NameMangler.perObjectInterfaceGet(aspectType), + "()" + aspectType.getSignature()); + } + + public static ResolvedMember perObjectInterfaceSet(TypeX aspectType) { + return new ResolvedMember( + Member.METHOD, + perObjectInterfaceType(aspectType), + Modifier.PUBLIC | Modifier.ABSTRACT, + NameMangler.perObjectInterfaceSet(aspectType), + "(" + aspectType.getSignature() + ")V"); + } + + + + + public static ResolvedMember perSingletonAspectOfMethod(TypeX declaringType) { + return new ResolvedMember(Member.METHOD, + declaringType, PUBLIC_STATIC, "aspectOf", + "()" + declaringType.getSignature()); + } + + public static ResolvedMember perSingletonHasAspectMethod(TypeX declaringType) { + return new ResolvedMember(Member.METHOD, + declaringType, PUBLIC_STATIC, "hasAspect", + "()Z"); + }; + + public static ResolvedMember perCflowAspectOfMethod(TypeX declaringType) { + return perSingletonAspectOfMethod(declaringType); + } + + public static ResolvedMember perCflowHasAspectMethod(TypeX declaringType) { + return perSingletonHasAspectMethod(declaringType); + }; + + public static ResolvedMember perObjectAspectOfMethod(TypeX declaringType) { + return new ResolvedMember(Member.METHOD, + declaringType, PUBLIC_STATIC, "aspectOf", + "(Ljava/lang/Object;)" + declaringType.getSignature()); + } + + public static ResolvedMember perObjectHasAspectMethod(TypeX declaringType) { + return new ResolvedMember(Member.METHOD, + declaringType, PUBLIC_STATIC, "hasAspect", + "(Ljava/lang/Object;)Z"); + }; + + // -- privileged accessors + + public static ResolvedMember privilegedAccessMethodForMethod(TypeX aspectType, ResolvedMember method) { + String sig; + sig = method.getSignature(); + return new ResolvedMember(Member.METHOD, + method.getDeclaringType(), + Modifier.PUBLIC | (method.isStatic() ? Modifier.STATIC : 0), + NameMangler.privilegedAccessMethodForMethod(method.getName(), + method.getDeclaringType(), aspectType), + sig); + //XXX needs thrown exceptions to be correct + } + + public static ResolvedMember privilegedAccessMethodForFieldGet(TypeX aspectType, Member field) { + String sig; + if (field.isStatic()) { + sig = "()" + field.getSignature(); + } else { + sig = "(" + field.getDeclaringType().getSignature() + ")" + field.getSignature(); + } + + return new ResolvedMember(Member.METHOD, + field.getDeclaringType(), + PUBLIC_STATIC, //Modifier.PUBLIC | (field.isStatic() ? Modifier.STATIC : 0), + NameMangler.privilegedAccessMethodForFieldGet(field.getName(), + field.getDeclaringType(), aspectType), + sig); + } + + public static ResolvedMember privilegedAccessMethodForFieldSet(TypeX aspectType, Member field) { + String sig; + if (field.isStatic()) { + sig = "(" + field.getSignature() + ")V"; + } else { + sig = "(" + field.getDeclaringType().getSignature() + field.getSignature() + ")V"; + } + + return new ResolvedMember(Member.METHOD, + field.getDeclaringType(), + PUBLIC_STATIC, //Modifier.PUBLIC | (field.isStatic() ? Modifier.STATIC : 0), + NameMangler.privilegedAccessMethodForFieldSet(field.getName(), + field.getDeclaringType(), aspectType), + sig); + } + + + + // --- runtimeLibrary api stuff + + public static Member cflowStackPeekInstance() { + return new Member( + Member.METHOD, + CFLOW_STACK_TYPE, + 0, + "peekInstance", + "()Ljava/lang/Object;"); + } + + public static Member cflowStackPushInstance() { + return new Member( + Member.METHOD, + CFLOW_STACK_TYPE, + 0, + "pushInstance", + "(Ljava/lang/Object;)V"); + } + + public static Member cflowStackIsValid() { + return new Member( + Member.METHOD, + CFLOW_STACK_TYPE, + 0, + "isValid", + "()Z"); + } + public static Member cflowStackInit() { + return new Member( + Member.CONSTRUCTOR, + CFLOW_STACK_TYPE, + 0, + "<init>", + "()V"); + } + public static Member aroundClosurePreInitializationField() { + return new Member( + Member.FIELD, + AROUND_CLOSURE_TYPE, + 0, + "preInitializationState", + "[Ljava/lang/Object;"); + } + public static Member aroundClosurePreInitializationGetter() { + return new Member( + Member.METHOD, + AROUND_CLOSURE_TYPE, + 0, + "getPreInitializationState", + "()[Ljava/lang/Object;"); + } + + + public static ResolvedMember preIntroducedConstructor( + TypeX aspectType, + TypeX targetType, + TypeX[] paramTypes) + { + return new ResolvedMember( + Member.METHOD, + aspectType, + PUBLIC_STATIC_FINAL, + TypeX.OBJECTARRAY, + NameMangler.preIntroducedConstructor(aspectType, targetType), + paramTypes); + } + + public static ResolvedMember postIntroducedConstructor( + TypeX aspectType, + TypeX targetType, + TypeX[] paramTypes) + { + return new ResolvedMember( + Member.METHOD, + aspectType, + PUBLIC_STATIC_FINAL, + ResolvedTypeX.VOID, + NameMangler.postIntroducedConstructor(aspectType, targetType), + TypeX.insert(targetType, paramTypes)); + } + + public static ResolvedMember interConstructor(ResolvedTypeX targetType, ResolvedMember constructor, TypeX aspectType) { +// +// ResolvedTypeX targetType, +// TypeX[] argTypes, +// int modifiers) +// { + ResolvedMember ret = + new ResolvedMember( + Member.CONSTRUCTOR, + targetType, + Modifier.PUBLIC, + ResolvedTypeX.VOID, + "<init>", + constructor.getParameterTypes()); + //System.out.println("ret: " + ret + " mods: " + Modifier.toString(modifiers)); + if (Modifier.isPublic(constructor.getModifiers())) + return ret; + int i = 0; + while (true) { + ret = addCookieTo(ret, aspectType); + if (targetType.lookupMemberNoSupers(ret) == null) + return ret; + } + } + + public static ResolvedMember interFieldInitializer(ResolvedMember field, TypeX aspectType) { + return new ResolvedMember(Member.METHOD, aspectType, PUBLIC_STATIC, + NameMangler.interFieldInitializer(aspectType, field.getDeclaringType(), field.getName()), + field.isStatic() ? "()V" : "(" + field.getDeclaringType().getSignature() + ")V" + ); + } + + + + private static int makePublic(int modifiers) { + return (modifiers & ~VISIBILITY) | Modifier.PUBLIC; + } + + + /** + * This static method goes on the aspect that declares the inter-type field + */ + public static ResolvedMember interFieldSetDispatcher(ResolvedMember field, TypeX aspectType) { + return new ResolvedMember(Member.METHOD, aspectType, PUBLIC_STATIC, + ResolvedTypeX.VOID, + NameMangler.interFieldSetDispatcher(aspectType, field.getDeclaringType(), field.getName()), + field.isStatic() ? new TypeX[] {field.getReturnType()} + : new TypeX[] {field.getDeclaringType(), field.getReturnType()} + ); + } + + /** + * This static method goes on the aspect that declares the inter-type field + */ + public static ResolvedMember interFieldGetDispatcher(ResolvedMember field, TypeX aspectType) { + return new ResolvedMember(Member.METHOD, aspectType, PUBLIC_STATIC, + field.getReturnType(), + NameMangler.interFieldGetDispatcher(aspectType, field.getDeclaringType(), field.getName()), + field.isStatic() ? TypeX.NONE : new TypeX[] {field.getDeclaringType()} + ); + } + + /** + * This field goes on the class the field + * is declared onto + */ + public static ResolvedMember interFieldClassField(ResolvedMember field, TypeX aspectType) { + return new ResolvedMember(Member.FIELD, field.getDeclaringType(), makePublic(field.getModifiers()), + field.getReturnType(), + NameMangler.interFieldClassField(field.getModifiers(), aspectType, field.getDeclaringType(), field.getName()), + TypeX.NONE + ); + } + + + /** + * This field goes on top-most implementers of the interface the field + * is declared onto + */ + public static ResolvedMember interFieldInterfaceField(ResolvedMember field, TypeX onClass, TypeX aspectType) { + return new ResolvedMember(Member.FIELD, onClass, Modifier.PUBLIC, + field.getReturnType(), + NameMangler.interFieldInterfaceField(aspectType, field.getDeclaringType(), field.getName()), + TypeX.NONE + ); + } + + /** + * This instance method goes on the interface the field is declared onto + * as well as its top-most implementors + */ + public static ResolvedMember interFieldInterfaceSetter(ResolvedMember field, ResolvedTypeX onType, TypeX aspectType) { + int modifiers = Modifier.PUBLIC; + if (onType.isInterface()) modifiers |= Modifier.ABSTRACT; + return new ResolvedMember(Member.METHOD, onType, modifiers, + ResolvedTypeX.VOID, + NameMangler.interFieldInterfaceSetter(aspectType, field.getDeclaringType(), field.getName()), + new TypeX[] {field.getReturnType()} + ); + } + + /** + * This instance method goes on the interface the field is declared onto + * as well as its top-most implementors + */ + public static ResolvedMember interFieldInterfaceGetter(ResolvedMember field, ResolvedTypeX onType, TypeX aspectType) { + int modifiers = Modifier.PUBLIC; + if (onType.isInterface()) modifiers |= Modifier.ABSTRACT; + return new ResolvedMember(Member.METHOD, onType, modifiers, + field.getReturnType(), + NameMangler.interFieldInterfaceGetter(aspectType, field.getDeclaringType(), field.getName()), + TypeX.NONE + ); + } + + + + + /** + * This method goes on the target type of the inter-type method. (and possibly the topmost-implemeters, + * if the target type is an interface) + */ + public static ResolvedMember interMethod(ResolvedMember meth, TypeX aspectType, boolean onInterface) + { + if (Modifier.isPublic(meth.getModifiers()) && !onInterface) return meth; + + int modifiers = makePublic(meth.getModifiers()); + if (onInterface) modifiers |= Modifier.ABSTRACT; + + return new ResolvedMember(Member.METHOD, meth.getDeclaringType(), + modifiers, + meth.getReturnType(), + NameMangler.interMethod(meth.getModifiers(), aspectType, meth.getDeclaringType(), meth.getName()), + meth.getParameterTypes()); + } + + /** + * This static method goes on the declaring aspect of the inter-type method. + */ + public static ResolvedMember interMethodDispatcher(ResolvedMember meth, TypeX aspectType) + { + TypeX[] paramTypes = meth.getParameterTypes(); + if (!meth.isStatic()) { + paramTypes = TypeX.insert(meth.getDeclaringType(), paramTypes); + } + + return new ResolvedMember(Member.METHOD, aspectType, PUBLIC_STATIC, + meth.getReturnType(), + NameMangler.interMethodDispatcher(aspectType, meth.getDeclaringType(), meth.getName()), + paramTypes); + } + + /** + * This static method goes on the declaring aspect of the inter-type method. + */ + public static ResolvedMember interMethodBody(ResolvedMember meth, TypeX aspectType) + { + TypeX[] paramTypes = meth.getParameterTypes(); + if (!meth.isStatic()) { + paramTypes = TypeX.insert(meth.getDeclaringType(), paramTypes); + } + + return new ResolvedMember(Member.METHOD, aspectType, PUBLIC_STATIC, + meth.getReturnType(), + NameMangler.interMethodBody(aspectType, meth.getDeclaringType(), meth.getName()), + paramTypes); + } + + + + + private static ResolvedMember addCookieTo(ResolvedMember ret, TypeX aspectType) { + TypeX[] params = ret.getParameterTypes(); + + TypeX[] freshParams = TypeX.add(params, aspectType); + return new ResolvedMember( + ret.getKind(), + ret.getDeclaringType(), + ret.getModifiers(), + ret.getReturnType(), + ret.getName(), + freshParams); + } + + public static ResolvedMember toObjectConversionMethod(TypeX fromType) { + if (fromType.isPrimitive()) { + String name = fromType.toString() + "Object"; + return new ResolvedMember( + Member.METHOD, + CONVERSIONS_TYPE, + PUBLIC_STATIC, + TypeX.OBJECT, + name, + new TypeX[] { fromType }); + } else { + return null; + } + } + public static Member interfaceConstructor(ResolvedTypeX resolvedTypeX) { + return new ResolvedMember( + Member.CONSTRUCTOR, + resolvedTypeX, + Modifier.PUBLIC, + "<init>", + "()V"); + } +} diff --git a/weaver/src/org/aspectj/weaver/AsmAdaptor.java b/weaver/src/org/aspectj/weaver/AsmAdaptor.java new file mode 100644 index 000000000..6830ab2bb --- /dev/null +++ b/weaver/src/org/aspectj/weaver/AsmAdaptor.java @@ -0,0 +1,157 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.util.*; +import java.util.Iterator; + +import org.aspectj.asm.*; +import org.aspectj.asm.StructureModel; +import org.aspectj.bridge.*; +import org.aspectj.bridge.SourceLocation; + +public class AsmAdaptor { + public static void noteMunger(StructureModel model, Shadow shadow, ShadowMunger munger) { + if (munger instanceof Advice) { + Advice a = (Advice)munger; + if (a.getKind().isPerEntry() || a.getKind().isCflow()) { + // ??? might want to show these in the future + return; + } + +// System.out.println("--------------------------"); + ProgramElementNode targetNode = getNode(model, shadow); + ProgramElementNode adviceNode = getNode(model, a); +// System.out.println("> target: " + targetNode + ", advice: " + adviceNode); + createAppropriateLinks(targetNode, adviceNode); + } + } + + private static void createAppropriateLinks( + ProgramElementNode target, + ProgramElementNode advice) + { + if (target == null || advice == null) return; + addLink(target, new LinkNode(advice), org.aspectj.asm.AdviceAssociation.METHOD_RELATION, true); + addLink(advice, new LinkNode(target), org.aspectj.asm.AdviceAssociation.METHOD_RELATION, false); +// System.out.println(">> added target: " + target + ", advice: " + advice); + } + + private static void addLink( + ProgramElementNode onNode, + LinkNode linkNode, + Relation relation, + boolean isBack) + { + RelationNode node = null; + String relationName = isBack ? relation.getBackNavigationName() : relation.getForwardNavigationName(); + + //System.err.println("on: " + onNode + " relationName: " + relationName + " existin: " + onNode.getRelations()); + + for (Iterator i = onNode.getRelations().iterator(); i.hasNext();) { + RelationNode relationNode = (RelationNode) i.next(); + if (relationName.equals(relationNode.getName())) { + node = relationNode; + break; + } + } + if (node == null) { + node = new RelationNode(relation, relationName, new ArrayList()); + onNode.getRelations().add(node); + } + node.getChildren().add(linkNode); + + } + + private static ProgramElementNode getNode(StructureModel model, Advice a) { + //ResolvedTypeX inAspect = a.getConcreteAspect(); + Member member = a.getSignature(); + return lookupMember(model, member); + } + + private static ProgramElementNode getNode(StructureModel model, Shadow shadow) { + Member enclosingMember = shadow.getEnclosingCodeSignature(); + + ProgramElementNode enclosingNode = lookupMember(model, enclosingMember); + + Member shadowSig = shadow.getSignature(); + if (!shadowSig.equals(enclosingMember)) { + ProgramElementNode bodyNode = findOrCreateBodyNode(enclosingNode, shadowSig, shadow); + return bodyNode; + } else { + return enclosingNode; + } + } + + private static ProgramElementNode findOrCreateBodyNode( + ProgramElementNode enclosingNode, + Member shadowSig, Shadow shadow) + { + for (Iterator it = enclosingNode.getChildren().iterator(); it.hasNext(); ) { + ProgramElementNode node = (ProgramElementNode)it.next(); + if (shadowSig.getName().equals(node.getBytecodeName()) && + shadowSig.getSignature().equals(node.getBytecodeSignature())) + { + return node; + } + } + + ISourceLocation sl = shadow.getSourceLocation(); + + ProgramElementNode peNode = new ProgramElementNode( + shadow.toString(), + ProgramElementNode.Kind.CODE, + new SourceLocation(enclosingNode.getSourceLocation().getSourceFile(), sl.getLine()), + 0, + "", + new ArrayList()); + + System.err.println(peNode.getSourceLocation()); + peNode.setBytecodeName(shadowSig.getName()); + peNode.setBytecodeSignature(shadowSig.getSignature()); + enclosingNode.addChild(peNode); + return peNode; + } + + + + + + public static ProgramElementNode lookupMember(StructureModel model, Member member) { + TypeX declaringType = member.getDeclaringType(); + ProgramElementNode classNode = + model.findNodeForClass(declaringType.getPackageName(), declaringType.getClassName()); + return findMemberInClass(classNode, member); + } + + private static ProgramElementNode findMemberInClass( + ProgramElementNode classNode, + Member member) + { + if (classNode == null) return null; // XXX remove this check + for (Iterator it = classNode.getChildren().iterator(); it.hasNext(); ) { + ProgramElementNode node = (ProgramElementNode)it.next(); + if (member.getName().equals(node.getBytecodeName()) && + member.getSignature().equals(node.getBytecodeSignature())) + { + return node; + } + } + return null; + } + + + + +} diff --git a/weaver/src/org/aspectj/weaver/BCException.java b/weaver/src/org/aspectj/weaver/BCException.java new file mode 100644 index 000000000..35ec52780 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/BCException.java @@ -0,0 +1,29 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +/** + * Exception to use inside the bcweaver. + */ +public class BCException extends RuntimeException { + + public BCException() { + super(); + } + + public BCException(String s) { + super(s); + } + +} diff --git a/weaver/src/org/aspectj/weaver/BetaException.java b/weaver/src/org/aspectj/weaver/BetaException.java new file mode 100644 index 000000000..9cf85fceb --- /dev/null +++ b/weaver/src/org/aspectj/weaver/BetaException.java @@ -0,0 +1,29 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +/** + * Exception to use inside the bcweaver. + */ +public class BetaException extends RuntimeException { + + public BetaException() { + super(); + } + + public BetaException(String s) { + super(s); + } + +} diff --git a/weaver/src/org/aspectj/weaver/Checker.java b/weaver/src/org/aspectj/weaver/Checker.java new file mode 100644 index 000000000..eec7d05af --- /dev/null +++ b/weaver/src/org/aspectj/weaver/Checker.java @@ -0,0 +1,61 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import org.aspectj.weaver.patterns.*; +import org.aspectj.weaver.patterns.PerClause; +import org.aspectj.bridge.*; + + +public class Checker extends ShadowMunger { + + private String msg; + private boolean isError; + + public Checker(DeclareErrorOrWarning deow) { + super(deow.getPointcut(), deow.getStart(), deow.getEnd(), deow.getSourceContext()); + this.msg = deow.getMessage(); + this.isError = deow.isError(); + } + + public ShadowMunger concretize(ResolvedTypeX fromType, World world, PerClause clause) { + pointcut = pointcut.concretize(fromType, 0); + return this; + } + + public void specializeOn(Shadow shadow) { + throw new RuntimeException("illegal state"); + } + + public void implementOn(Shadow shadow) { + throw new RuntimeException("illegal state"); + } + + public boolean match(Shadow shadow, World world) { + if (super.match(shadow, world)) { + world.getMessageHandler().handleMessage( + new Message(msg, + isError ? IMessage.ERROR : IMessage.WARNING, + null, + shadow.getSourceLocation())); + } + return false; + } + + + public int compareTo(Object other) { + return 0; + } + +} diff --git a/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java b/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java new file mode 100644 index 000000000..9f55b28e9 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ConcreteTypeMunger.java @@ -0,0 +1,76 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.util.PartialOrder; + +public abstract class ConcreteTypeMunger implements PartialOrder.PartialComparable { + protected ResolvedTypeMunger munger; + protected ResolvedTypeX aspectType; + + public ConcreteTypeMunger(ResolvedTypeMunger munger, ResolvedTypeX aspectType) { + this.munger = munger; + this.aspectType = aspectType; + } + + //public abstract boolean munge(LazyClassGen gen); + + public ResolvedTypeMunger getMunger() { + return munger; + } + + public ResolvedTypeX getAspectType() { + return aspectType; + } + + public ResolvedMember getSignature() { + return munger.getSignature(); + } + + public ISourceLocation getSourceLocation() { + return null; //XXX + } + + public boolean matches(ResolvedTypeX onType) { + if (munger == null) throw new RuntimeException("huh: " + this); + return munger.matches(onType); + } + + public ResolvedMember getMatchingSyntheticMember(Member member) { + return munger.getMatchingSyntheticMember(member, aspectType); + } + + public int compareTo(Object other) { + ConcreteTypeMunger o = (ConcreteTypeMunger) other; + + ResolvedTypeX otherAspect = o.aspectType; + + if (aspectType.equals(otherAspect)) { + return getSignature().getStart() < o.getSignature().getStart() ? -1: +1; + } else if (aspectType.isAssignableFrom(o.aspectType)) { + return +1; + } else if (o.aspectType.isAssignableFrom(aspectType)) { + return -1; + } else { + return 0; + } + } + + public int fallbackCompareTo(Object other) { + ConcreteTypeMunger o = (ConcreteTypeMunger) other; + return 0; + } + +} diff --git a/weaver/src/org/aspectj/weaver/CrosscuttingMembers.java b/weaver/src/org/aspectj/weaver/CrosscuttingMembers.java new file mode 100644 index 000000000..8635cdaf6 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/CrosscuttingMembers.java @@ -0,0 +1,201 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.util.*; + +import org.aspectj.weaver.patterns.*; +import org.aspectj.weaver.patterns.PerClause; +import org.aspectj.bridge.*; + + +/** + * This holds on to all members that have an invasive effect outside of + * there own compilation unit. These members need to be all gathered up and in + * a world before any weaving can take place. + * + * They are also important in the compilation process and need to be gathered + * up before the inter-type declaration weaving stage (unsurprisingly). + * + * All members are concrete. + */ + +public class CrosscuttingMembers { + private ResolvedTypeX inAspect; + private World world; + + private PerClause perClause; + + private List shadowMungers = new ArrayList(4); + private List typeMungers = new ArrayList(4); + + private List declareParents = new ArrayList(4); + private List declareSofts = new ArrayList(0); + private List declareDominates = new ArrayList(4); + + + public CrosscuttingMembers(ResolvedTypeX inAspect) { + this.inAspect = inAspect; + this.world = inAspect.getWorld(); + } + +// public void addConcreteShadowMungers(Collection c) { +// shadowMungers.addAll(c); +// } + + public void addConcreteShadowMunger(ShadowMunger m) { + // assert m is concrete + shadowMungers.add(m); + } + + public void addShadowMungers(Collection c) { + for (Iterator i = c.iterator(); i.hasNext(); ) { + addShadowMunger( (ShadowMunger)i.next() ); + } + } + + private void addShadowMunger(ShadowMunger m) { + //if (inAspect.isAbstract()) return; // we don't do mungers for abstract aspects + addConcreteShadowMunger(m.concretize(inAspect, world, perClause)); + } + + public void addTypeMungers(Collection c) { + typeMungers.addAll(c); + } + + public void addTypeMunger(ConcreteTypeMunger m) { + if (m == null) return; //??? + typeMungers.add(m); + } + + public void addDeclares(Collection c) { + for (Iterator i = c.iterator(); i.hasNext(); ) { + addDeclare( (Declare)i.next() ); + } + } + + + + public void addDeclare(Declare declare) { + // this is not extensible, oh well + if (declare instanceof DeclareErrorOrWarning) { + ShadowMunger m = new Checker((DeclareErrorOrWarning)declare); + addShadowMunger(m); + } else if (declare instanceof DeclareDominates) { + declareDominates.add(declare); + } else if (declare instanceof DeclareParents) { + declareParents.add(declare); + } else if (declare instanceof DeclareSoft) { + DeclareSoft d = (DeclareSoft)declare; + Pointcut concretePointcut = d.getPointcut().concretize(inAspect, 0); + declareSofts.add(new DeclareSoft(d.getException(), concretePointcut)); + ShadowMunger m = Advice.makeSoftener(world, concretePointcut, d.getException()); + addConcreteShadowMunger(m); + } else { + throw new RuntimeException("unimplemented"); + } + } + + public void addPrivilegedAccesses(Collection accessedMembers) { + for (Iterator i = accessedMembers.iterator(); i.hasNext(); ) { + addPrivilegedAccess( (ResolvedMember)i.next() ); + } + } + + private void addPrivilegedAccess(ResolvedMember member) { + //System.err.println("add priv access: " + member); + addTypeMunger(world.concreteTypeMunger(new PrivilegedAccessMunger(member), inAspect)); + } + + + + public Collection getCflowEntries() { + ArrayList ret = new ArrayList(); + for (Iterator i = shadowMungers.iterator(); i.hasNext(); ) { + ShadowMunger m = (ShadowMunger)i.next(); + if (m instanceof Advice) { + Advice a = (Advice)m; + if (a.getKind().isCflow()) { + ret.add(a); + } + } + } + return ret; + } + + public boolean replaceWith(CrosscuttingMembers other) { + boolean changed = false; + if (!perClause.equals(other.perClause)) { + changed = true; + perClause = other.perClause; + } + + //XXX all of the below should be set equality rather than list equality + if (!shadowMungers.equals(other.shadowMungers)) { + changed = true; + shadowMungers = other.shadowMungers; + } + + if (!typeMungers.equals(other.typeMungers)) { + changed = true; + typeMungers = other.typeMungers; + } + + if (!declareDominates.equals(other.declareDominates)) { + changed = true; + declareDominates = other.declareDominates; + } + + if (!declareParents.equals(other.declareParents)) { + changed = true; + declareParents = other.declareParents; + } + + if (!declareSofts.equals(other.declareSofts)) { + changed = true; + declareSofts = other.declareSofts; + } + + return changed; + } + + public PerClause getPerClause() { + return perClause; + } + + public void setPerClause(PerClause perClause) { + this.perClause = perClause.concretize(inAspect); + } + + public List getDeclareDominates() { + return declareDominates; + } + + public List getDeclareParents() { + return declareParents; + } + + public List getDeclareSofts() { + return declareSofts; + } + + public List getShadowMungers() { + return shadowMungers; + } + + public List getTypeMungers() { + return typeMungers; + } + +} diff --git a/weaver/src/org/aspectj/weaver/CrosscuttingMembersSet.java b/weaver/src/org/aspectj/weaver/CrosscuttingMembersSet.java new file mode 100644 index 000000000..ceebbfeb6 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/CrosscuttingMembersSet.java @@ -0,0 +1,140 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.util.*; + +import org.aspectj.weaver.patterns.*; +import org.aspectj.weaver.patterns.PerClause; +import org.aspectj.bridge.*; + + +/** + * This holds on to all CrosscuttingMembers for a world. It handles + * management of change. + */ + +public class CrosscuttingMembersSet { + private World world; + private Map members = new HashMap(); + + private List shadowMungers = null; + private List typeMungers = null; + private List declareSofts = null; + private List declareParents = null; + private List declareDominates = null; + + public CrosscuttingMembersSet(World world) { + this.world = world; + } + + /** + * @return whether or not that was a change to the global signature + * XXX for efficiency we will need a richer representation than this + */ + public boolean addOrReplaceAspect(ResolvedTypeX aspectType) { + CrosscuttingMembers xcut = (CrosscuttingMembers)members.get(aspectType); + if (xcut == null) { + members.put(aspectType, aspectType.collectCrosscuttingMembers()); + clearCaches(); + return true; + } else { + if (xcut.replaceWith(aspectType.collectCrosscuttingMembers())) { + clearCaches(); + return true; + } else { + return false; + } + } + } + + public void deleteAspect(TypeX aspectType) { + members.remove(aspectType); + clearCaches(); + } + + //XXX only for testing + public void addFixedCrosscuttingMembers(ResolvedTypeX aspectType) { + members.put(aspectType, aspectType.crosscuttingMembers); + clearCaches(); + } + + + private void clearCaches() { + shadowMungers = null; + typeMungers = null; + declareSofts = null; + declareParents = null; + declareDominates = null; + } + + + public List getShadowMungers() { + if (shadowMungers == null) { + ArrayList ret = new ArrayList(); + for (Iterator i = members.values().iterator(); i.hasNext(); ) { + ret.addAll(((CrosscuttingMembers)i.next()).getShadowMungers()); + } + shadowMungers = ret; + } + return shadowMungers; + } + + public List getTypeMungers() { + if (typeMungers == null) { + ArrayList ret = new ArrayList(); + for (Iterator i = members.values().iterator(); i.hasNext(); ) { + ret.addAll(((CrosscuttingMembers)i.next()).getTypeMungers()); + } + typeMungers = ret; + } + return typeMungers; + } + + public List getDeclareSofts() { + if (declareSofts == null) { + ArrayList ret = new ArrayList(); + for (Iterator i = members.values().iterator(); i.hasNext(); ) { + ret.addAll(((CrosscuttingMembers)i.next()).getDeclareSofts()); + } + declareSofts = ret; + } + return declareSofts; + } + + public List getDeclareParents() { + if (declareParents == null) { + ArrayList ret = new ArrayList(); + for (Iterator i = members.values().iterator(); i.hasNext(); ) { + ret.addAll(((CrosscuttingMembers)i.next()).getDeclareParents()); + } + declareParents = ret; + } + return declareParents; + } + + public List getDeclareDominates() { + if (declareDominates == null) { + ArrayList ret = new ArrayList(); + for (Iterator i = members.values().iterator(); i.hasNext(); ) { + ret.addAll(((CrosscuttingMembers)i.next()).getDeclareDominates()); + } + declareDominates = ret; + } + return declareDominates; + } + + + +} diff --git a/weaver/src/org/aspectj/weaver/IClassWeaver.java b/weaver/src/org/aspectj/weaver/IClassWeaver.java new file mode 100644 index 000000000..3dd152e8d --- /dev/null +++ b/weaver/src/org/aspectj/weaver/IClassWeaver.java @@ -0,0 +1,29 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +/** + * An IClassWeaver is initialized with a class (a type, really, but let's ignore that for now) + * and a world, and has one method that actually weaves the contents of the world into the class + * implementation. + */ + +public interface IClassWeaver { + + /** perform the weaving. + * + * @return <code>true</code> if the class is changed by the weaving, <code>false</code> otherwise. + */ + boolean weave(); +} diff --git a/weaver/src/org/aspectj/weaver/IHasPosition.java b/weaver/src/org/aspectj/weaver/IHasPosition.java new file mode 100644 index 000000000..8fb5688a7 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/IHasPosition.java @@ -0,0 +1,33 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +public interface IHasPosition { + /** + * The starting index of this location in the character stream. + */ + int getStart(); + + /** + * The ending index of this location in the character stream + * + * This points to the last character in this token. + * + * If a location truly had no contents, then start == end + 1. We don't recommend this. + */ + int getEnd(); +// +// String getFileName(); + +} diff --git a/weaver/src/org/aspectj/weaver/IHasSourceLocation.java b/weaver/src/org/aspectj/weaver/IHasSourceLocation.java new file mode 100644 index 000000000..2ca7a01c8 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/IHasSourceLocation.java @@ -0,0 +1,21 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import org.aspectj.bridge.ISourceLocation; + +public interface IHasSourceLocation extends IHasPosition { + ISourceContext getSourceContext(); + ISourceLocation getSourceLocation(); +} diff --git a/weaver/src/org/aspectj/weaver/ISourceContext.java b/weaver/src/org/aspectj/weaver/ISourceContext.java new file mode 100644 index 000000000..c5cf2620f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ISourceContext.java @@ -0,0 +1,20 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import org.aspectj.bridge.ISourceLocation; + +public interface ISourceContext { + public ISourceLocation makeSourceLocation(IHasPosition position); +} diff --git a/weaver/src/org/aspectj/weaver/IWeaver.java b/weaver/src/org/aspectj/weaver/IWeaver.java new file mode 100644 index 000000000..4c38424ac --- /dev/null +++ b/weaver/src/org/aspectj/weaver/IWeaver.java @@ -0,0 +1,24 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +/** + * A weaver is given all the aspects it will weave. It should create an appropriate kind of + * IWorld. It then should be given a bunch of classes (types with implementation), creates an + * appropriate IClassWeaver for each such class, and weaves. The IWeaver is responsible for + * IO. + */ +public interface IWeaver { + +} diff --git a/weaver/src/org/aspectj/weaver/IntMap.java b/weaver/src/org/aspectj/weaver/IntMap.java new file mode 100644 index 000000000..712a64637 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/IntMap.java @@ -0,0 +1,134 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.util.*; + +public class IntMap { + public static final IntMap EMPTY = new IntMap(0) { + public boolean directlyInAdvice() { return true; } + public Advice getEnclosingAdvice() { return null; } //XXX possible + }; + + + // XXX begin hack to avoid a signature refactoring in Pointcut + private Advice enclosingAdvice; + private List/*ResolvedPointcutDefinition*/ enclosingDefinition = new ArrayList(); + + public void pushEnclosingDefinition(ResolvedPointcutDefinition def) { + enclosingDefinition.add(def); + } + + public void popEnclosingDefinitition() { + enclosingDefinition.remove(enclosingDefinition.size()-1); + } + + + public ResolvedPointcutDefinition peekEnclosingDefinitition() { + return (ResolvedPointcutDefinition)enclosingDefinition.get(enclosingDefinition.size()-1); + } + + + public boolean directlyInAdvice() { + return enclosingDefinition.isEmpty(); + } + + public Advice getEnclosingAdvice() { + return enclosingAdvice; + } + + public void setEnclosingAdvice(Advice advice) { + this.enclosingAdvice = advice; + } + + public Member getAdviceSignature() { + return getEnclosingAdvice().signature; + } + + public void copyContext(IntMap bindings) { + this.enclosingAdvice = bindings.enclosingAdvice; + this.enclosingDefinition = bindings.enclosingDefinition; + } + + // XXX end hack to avoid a signature refactoring in Pointcut + + + private static final int MISSING = -1; + + private int[] map; + + private IntMap(int[] map) { + this.map = map; + } + public IntMap() { + map = new int[0]; + } + public IntMap(int initialCapacity) { + map = new int[initialCapacity]; + for (int i = 0; i < initialCapacity; i++) { + map[i] = MISSING; + } + } + + public void put(int key, int val) { + /* assert (val >= 0 && key >= 0) */ + if (key >= map.length) { + int[] tmp = new int[key * 2 + 1]; //??? better expansion function + System.arraycopy(map, 0, tmp, 0, map.length); + for (int i = map.length, len = tmp.length; i < len; i++) tmp[i] = MISSING; + map = tmp; + } + map[key] = val; + } + + public int get(int key) { + return map[key]; + } + + public boolean hasKey(int key) { + return (key < map.length && map[key] != MISSING); + } + + // ---- factory methods + + public static IntMap idMap(int size) { + int[] map = new int[size]; + for (int i = 0; i < size; i++) { + map[i] = i; + } + return new IntMap(map); + } + + // ---- from object + + public String toString() { + StringBuffer buf = new StringBuffer("["); + boolean seenFirst = false; + for (int i = 0, len = map.length; i < len; i++) { + if (map[i] != MISSING) { + if (seenFirst) { + buf.append(", "); + } + seenFirst = true; + buf.append(i); + buf.append(" -> "); + buf.append(map[i]); + } + } + buf.append("]"); + return buf.toString(); + } + + +} diff --git a/weaver/src/org/aspectj/weaver/Iterators.java b/weaver/src/org/aspectj/weaver/Iterators.java new file mode 100644 index 000000000..2685ba92f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/Iterators.java @@ -0,0 +1,215 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.util.*; + +public final class Iterators { + + /** + * Private constructor, nobody should ever make one of these + */ + private Iterators() { + super(); + } + + /** + * A getter represents a mapping function from Object to Iterator + */ + public interface Getter { + Iterator get(Object target); + } + + /** + * A filter represents a mapping function from Iterator to Iterator + */ + public interface Filter { + Iterator filter(Iterator in); + } + + /** + * Create a new filter F that, when wrapped around another iterator I, + * creates a new iterator I' that will return only those values of I + * that have not yet been returned by I', discarding duplicates. + */ + public static Filter dupFilter() { + return new Filter() { + final Set seen = new HashSet(); // should have weak ptrs? + public Iterator filter(final Iterator in) { + return new Iterator() { + boolean fresh = false; + Object peek; + public boolean hasNext() { + if (fresh) return true; + while (true) { + if (! in.hasNext()) return false; + peek = in.next(); + if (! seen.contains(peek)) { + return fresh = true; + } else { + peek = null; // garbage collection + } + } + } + public Object next() { + if (! hasNext()) throw new NoSuchElementException(); + Object ret = peek; + peek = null; + fresh = false; + return ret; + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + }; + } + + /** + * Creates an iterator that will return the elements of a specified array, + * in order. Like Arrays.asList(o).iterator(), without all that pesky safety. + */ + + public static Iterator array(final Object[] o) { + return new Iterator() { + int i = 0; + int len = o.length; + public boolean hasNext() { + return i < len; + } + public Object next() { + if (i < len) { + return o[i++]; + } else { + throw new NoSuchElementException(); + } + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } + + /** creates an iterator I based on a base iterator A and a getter G. + * I returns, in order, forall (i in I), G(i). + */ + public static Iterator mapOver(final Iterator a, final Getter g) { + return new Iterator() { + Iterator delegate = + new Iterator() { + public boolean hasNext() { + if (! a.hasNext()) return false; + Object o = a.next(); + delegate = append1(g.get(o), this); + return delegate.hasNext(); + } + public Object next() { + if (! hasNext()) throw new UnsupportedOperationException(); + return delegate.next(); + } + public void remove() { throw new UnsupportedOperationException(); } + }; + public boolean hasNext() { + return delegate.hasNext(); + } + public Object next() { + return delegate.next(); + } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + + /** creates an iterator I based on a base iterator A and a getter G. + * I returns, in order, forall (i in I) i :: forall (i' in g(i)) recur(i', g) + */ + public static Iterator recur(final Object a, final Getter g) { + return new Iterator() { + Iterator delegate = one(a); + public boolean hasNext() { + return delegate.hasNext(); + } + public Object next() { + Object next = delegate.next(); + delegate = append(g.get(next), delegate); + return next; + } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + /** creates an iterator I based on base iterators A and B. Returns + * the elements returned by A followed by those returned by B. If + * B is empty, simply returns A, and if A is empty, simply returns B. + * Do NOT USE if b.hasNext() is not idempotent. + */ + public static Iterator append(final Iterator a, final Iterator b) { + if (! b.hasNext()) return a; + return append1(a, b); + } + /** creates an iterator I based on base iterators A and B. Returns + * the elements returned by A followed by those returned by B. If A + * is empty, simply returns B. Guaranteed not to call B.hasNext() until + * A is empty. + */ + public static Iterator append1(final Iterator a, final Iterator b) { + if (! a.hasNext()) return b; + return new Iterator() { + public boolean hasNext() { return a.hasNext() || b.hasNext(); } + public Object next() { + if (a.hasNext()) return a.next(); + if (b.hasNext()) return b.next(); + throw new NoSuchElementException(); + } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + /** creates an iterator I based on a base iterator A and an object O. Returns + * the elements returned by A, followed by O. + */ + public static Iterator snoc(final Iterator first, final Object last) { + return new Iterator() { + Object last1 = last; + public boolean hasNext() { return first.hasNext() || last1 != null; } + public Object next() { + if (first.hasNext()) return first.next(); + else if (last1 == null) throw new NoSuchElementException(); + Object ret = last1; + last1 = null; + return ret; + } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + /** creates an iterator I based on an object O. Returns O, once. + */ + public static Iterator one(final Object it) { + return new Iterator() { + boolean avail = true; + public boolean hasNext() { return avail; } + public Object next() { + if (! avail) throw new NoSuchElementException(); + avail = false; + return it; + } + public void remove() { throw new UnsupportedOperationException(); } + }; + } + /** creates an empty iterator. + */ + public static final Iterator EMPTY = new Iterator() { + public boolean hasNext() { return false; } + public Object next() { throw new NoSuchElementException(); } + public void remove() { throw new UnsupportedOperationException(); } + }; +} diff --git a/weaver/src/org/aspectj/weaver/Lint.java b/weaver/src/org/aspectj/weaver/Lint.java new file mode 100644 index 000000000..82135a1df --- /dev/null +++ b/weaver/src/org/aspectj/weaver/Lint.java @@ -0,0 +1,141 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.io.File; +import java.text.MessageFormat; +import java.util.*; + +import org.aspectj.bridge.*; +import org.aspectj.bridge.IMessage.Kind; + +public class Lint { + private Map kinds = new HashMap(); + private World world; + + public final Kind invalidAbsoluteTypeName = + new Kind("invalidAbsoluteTypeName", "no match for this type name: {0}"); + + public final Kind invalidWildcardTypeName = + new Kind("invalidWildcardTypeName", "no match for this type pattern: {0}"); + + public final Kind unresolvableMember = + new Kind("unresolvableMember", "can not resolve this member: {0}"); + + + public Lint(World world) { + this.world = world; + } + + + public void setAll(String messageKind) { + setAll(getMessageKind(messageKind)); + } + + private void setAll(IMessage.Kind messageKind) { + for (Iterator i = kinds.values().iterator(); i.hasNext(); ) { + Kind kind = (Kind)i.next(); + kind.setKind(messageKind); + } + } + + public void setFromProperties(File file) { + try { + InputStream s = new FileInputStream(file); + setFromProperties(s); + } catch (IOException ioe) { + MessageUtil.error(world.getMessageHandler(), "problem loading Xlint properties file: " + + file.getPath() + ", " + ioe.getMessage()); + } + } + + public void loadDefaultProperties() { + InputStream s = getClass().getResourceAsStream("XlintDefault.properties"); + if (s == null) { + MessageUtil.warn(world.getMessageHandler(), "couldn't load XlintDefault.properties"); + return; + } + try { + setFromProperties(s); + } catch (IOException ioe) { + MessageUtil.error(world.getMessageHandler(), "problem loading XlintDefault.properties, " + + ioe.getMessage()); + } + + } + + + private void setFromProperties(InputStream s) throws IOException { + Properties p = new Properties(); + p.load(s); + setFromProperties(p); + } + + + public void setFromProperties(Properties properties) { + for (Iterator i = properties.entrySet().iterator(); i.hasNext(); ) { + Map.Entry entry = (Map.Entry)i.next(); + Kind kind = (Kind)kinds.get(entry.getKey()); + if (kind == null) { + MessageUtil.error(world.getMessageHandler(), "invalid Xlint key: " + entry.getKey()); + } else { + kind.setKind(getMessageKind((String)entry.getValue())); + } + } + } + + private IMessage.Kind getMessageKind(String v) { + if (v.equals("ignore")) return null; + else if (v.equals("warning")) return IMessage.WARNING; + else if (v.equals("error")) return IMessage.ERROR; + + MessageUtil.error(world.getMessageHandler(), + "invalid Xlint message kind (must be one of ignore, warning, error): " + v); + return null; + } + + + + public class Kind { + private String name; + private String message; + private IMessage.Kind kind = IMessage.WARNING; + public Kind(String name, String message) { + this.name = name; + this.message = message; + kinds.put(this.name, this); + } + + public boolean isEnabled() { + return kind != null; + } + + public IMessage.Kind getKind() { + return kind; + } + + public void setKind(IMessage.Kind kind) { + this.kind = kind; + } + + public void signal(String info, ISourceLocation location) { + if (kind == null) return; + + String text = MessageFormat.format(message, new Object[] {info} ); + text += " [Xlint:" + name + "]"; + world.getMessageHandler().handleMessage(new Message(text, kind, null, location)); + } + } +} diff --git a/weaver/src/org/aspectj/weaver/Member.java b/weaver/src/org/aspectj/weaver/Member.java new file mode 100644 index 000000000..284454fdf --- /dev/null +++ b/weaver/src/org/aspectj/weaver/Member.java @@ -0,0 +1,745 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; + +import org.aspectj.util.TypeSafeEnum; + +public class Member implements Comparable { + + private final Kind kind; + private final TypeX declaringType; + protected final int modifiers; // protected because ResolvedMember uses it + private final TypeX returnType; + private final String name; + private final TypeX[] parameterTypes; + private final String signature; + + public Member( + Kind kind, + TypeX declaringType, + int modifiers, + String name, + String signature) + { + this.kind = kind; + this.declaringType = declaringType; + this.modifiers = modifiers; + this.name = name; + this.signature = signature; + if (kind == FIELD) { + this.returnType = TypeX.forSignature(signature); + this.parameterTypes = TypeX.NONE; + } else { + Object[] returnAndParams = signatureToTypes(signature); + this.returnType = (TypeX) returnAndParams[0]; + this.parameterTypes = (TypeX[]) returnAndParams[1]; + } + } + + public Member( + Kind kind, + TypeX declaringType, + int modifiers, + TypeX returnType, + String name, + TypeX[] parameterTypes) + { + super(); + this.kind = kind; + this.declaringType = declaringType; + this.modifiers = modifiers; + this.returnType = returnType; + this.name = name; + this.parameterTypes = parameterTypes; + if (kind == FIELD) { + this.signature = returnType.getSignature(); + } else { + this.signature = typesToSignature(returnType, parameterTypes); + } + } + + public ResolvedMember resolve(World world) { + return world.resolve(this); + } + + // ---- utility methods + + /** returns an Object[] pair of TypeX, TypeX[] representing return type, + * argument types parsed from the JVM bytecode signature of a method. Yes, + * this should actually return a nice statically-typed pair object, but we + * don't have one of those. + * + * <blockquote><pre> + * TypeX.signatureToTypes("()[Z")[0].equals(Type.forSignature("[Z")) + * TypeX.signatureToTypes("(JJ)I")[1] + * .equals(TypeX.forSignatures(new String[] {"J", "J"})) + * </pre></blockquote> + * + * @param signature the JVM bytecode method signature string we want to break apart + * @return a pair of TypeX, TypeX[] representing the return types and parameter types. + */ + public static String typesToSignature(TypeX returnType, TypeX[] paramTypes) { + StringBuffer buf = new StringBuffer(); + buf.append("("); + for (int i = 0, len = paramTypes.length; i < len; i++) { + buf.append(paramTypes[i].getSignature()); + } + buf.append(")"); + buf.append(returnType.getSignature()); + return buf.toString(); + } + + /** returns an Object[] pair of TypeX, TypeX[] representing return type, + * argument types parsed from the JVM bytecode signature of a method. Yes, + * this should actually return a nice statically-typed pair object, but we + * don't have one of those. + * + * <blockquote><pre> + * TypeX.signatureToTypes("()[Z")[0].equals(Type.forSignature("[Z")) + * TypeX.signatureToTypes("(JJ)I")[1] + * .equals(TypeX.forSignatures(new String[] {"J", "J"})) + * </pre></blockquote> + * + * @param signature the JVM bytecode method signature string we want to break apart + * @return a pair of TypeX, TypeX[] representing the return types and parameter types. + */ + private static Object[] signatureToTypes(String sig) { + List l = new ArrayList(); + int i = 1; + while (true) { + char c = sig.charAt(i); + if (c == ')') break; + int start = i; + while (c == '[') c = sig.charAt(++i); + if (c == 'L') { + i = sig.indexOf(';', start) + 1; + l.add(TypeX.forSignature(sig.substring(start, i))); + } else { + l.add(TypeX.forSignature(sig.substring(start, ++i))); + } + } + TypeX[] paramTypes = (TypeX[]) l.toArray(new TypeX[l.size()]); + TypeX returnType = TypeX.forSignature(sig.substring(i+1, sig.length())); + return new Object[] { returnType, paramTypes }; + } + + // ---- factory methods + public static Member field(String declaring, int mods, String name, String signature) { + return field(declaring, mods, TypeX.forSignature(signature), name); + } + public static Member field(TypeX declaring, int mods, String name, TypeX type) { + return new Member(FIELD, declaring, mods, type, name, TypeX.NONE); + } + public static Member method(TypeX declaring, int mods, String name, String signature) { + Object[] pair = signatureToTypes(signature); + return method(declaring, mods, (TypeX) pair[0], name, (TypeX[]) pair[1]); + } + public static Member pointcut(TypeX declaring, String name, String signature) { + Object[] pair = signatureToTypes(signature); + return pointcut(declaring, 0, (TypeX) pair[0], name, (TypeX[]) pair[1]); + } + + + private static Member field(String declaring, int mods, TypeX ty, String name) { + return new Member( + FIELD, + TypeX.forName(declaring), + mods, + ty, + name, + TypeX.NONE); + } + + public static Member method(TypeX declTy, int mods, TypeX rTy, String name, TypeX[] paramTys) { + return new Member( + //??? this calls <clinit> a method + name.equals("<init>") ? CONSTRUCTOR : METHOD, + declTy, + mods, + rTy, + name, + paramTys); + } + private static Member pointcut(TypeX declTy, int mods, TypeX rTy, String name, TypeX[] paramTys) { + return new Member( + POINTCUT, + declTy, + mods, + rTy, + name, + paramTys); + } + + public static Member makeExceptionHandlerSignature(TypeX inType, TypeX catchType) { + return new Member( + HANDLER, + inType, + Modifier.STATIC, + "<catch>", + "(" + catchType.getSignature() + ")V"); + } + + // ---- parsing methods + + /** Takes a string in this form: + * + * <blockquote><pre> + * static? TypeName TypeName.Id + * </pre></blockquote> + * Pretty much just for testing, and as such should perhaps be moved. + */ + + public static Member fieldFromString(String str) { + str = str.trim(); + final int len = str.length(); + int i = 0; + int mods = 0; + if (str.startsWith("static", i)) { + mods = Modifier.STATIC; + i += 6; + while (Character.isWhitespace(str.charAt(i))) i++; + } + int start = i; + while (! Character.isWhitespace(str.charAt(i))) i++; + TypeX retTy = TypeX.forName(str.substring(start, i)); + + start = i; + i = str.lastIndexOf('.'); + TypeX declaringTy = TypeX.forName(str.substring(start, i).trim()); + start = ++i; + String name = str.substring(start, len).trim(); + return new Member( + FIELD, + declaringTy, + mods, + retTy, + name, + TypeX.NONE); + } + + /** Takes a string in this form: + * + * <blockquote><pre> + * (static|interface|private)? TypeName TypeName . Id ( TypeName , ...) + * </pre></blockquote> + * Pretty much just for testing, and as such should perhaps be moved. + */ + + public static Member methodFromString(String str) { + str = str.trim(); + final int len = str.length(); + int i = 0; + + int mods = 0; + if (str.startsWith("static", i)) { + mods = Modifier.STATIC; + i += 6; + } else if (str.startsWith("interface", i)) { + mods = Modifier.INTERFACE; + i += 9; + } else if (str.startsWith("private", i)) { + mods = Modifier.PRIVATE; + i += 7; + } + while (Character.isWhitespace(str.charAt(i))) i++; + + int start = i; + while (! Character.isWhitespace(str.charAt(i))) i++; + TypeX returnTy = TypeX.forName(str.substring(start, i)); + + start = i; + i = str.indexOf('(', i); + i = str.lastIndexOf('.', i); + TypeX declaringTy = TypeX.forName(str.substring(start, i).trim()); + + start = ++i; + i = str.indexOf('(', i); + String name = str.substring(start, i).trim(); + start = ++i; + i = str.indexOf(')', i); + + String[] paramTypeNames = parseIds(str.substring(start, i).trim()); + + return method(declaringTy, mods, returnTy, name, TypeX.forNames(paramTypeNames)); + } + + private static String[] parseIds(String str) { + if (str.length() == 0) return ZERO_STRINGS; + List l = new ArrayList(); + int start = 0; + while (true) { + int i = str.indexOf(',', start); + if (i == -1) { + l.add(str.substring(start).trim()); + break; + } + l.add(str.substring(start, i).trim()); + start = i+1; + } + return (String[]) l.toArray(new String[l.size()]); + } + + private static final String[] ZERO_STRINGS = new String[0]; + + // ---- things we know without resolution + + public boolean equals(Object other) { + if (! (other instanceof Member)) return false; + Member o = (Member) other; + + return (kind == o.kind + && name.equals(o.name) + && signature.equals(o.signature) + && declaringType.equals(o.declaringType)); + } + + public int compareTo(Object other) { + Member o = (Member) other; + + int i = getName().compareTo(o.getName()); + if (i != 0) return i; + return getSignature().compareTo(o.getSignature()); + } + + /** + * Equality is checked based on the underlying signature, so the hash code + * of a member is based on its kind, name, signature, and declaring type. The + * algorithm for this was taken from page 38 of effective java. + */ + private volatile int hashCode = 0; + public int hashCode() { + if (hashCode == 0) { + int result = 17; + result = 37*result + kind.hashCode(); + result = 37*result + name.hashCode(); + result = 37*result + signature.hashCode(); + result = 37*result + declaringType.hashCode(); + hashCode = result; + } + return hashCode; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append(returnType); + buf.append(' '); + buf.append(declaringType); + buf.append('.'); + buf.append(name); + if (kind != FIELD) { + buf.append("("); + if (parameterTypes.length != 0) { + buf.append(parameterTypes[0]); + for (int i=1, len = parameterTypes.length; i < len; i++) { + buf.append(", "); + buf.append(parameterTypes[i]); + } + } + buf.append(")"); + } + return buf.toString(); + } + + public String toLongString() { + StringBuffer buf = new StringBuffer(); + buf.append(kind); + buf.append(' '); + if (modifiers != 0) { + buf.append(Modifier.toString(modifiers)); + buf.append(' '); + } + buf.append(toString()); + buf.append(" <"); + buf.append(signature); + buf.append(" >"); + return buf.toString(); + } + + public Kind getKind() { return kind; } + public TypeX getDeclaringType() { return declaringType; } + public TypeX getReturnType() { return returnType; } + public TypeX getType() { return returnType; } + public String getName() { return name; } + public TypeX[] getParameterTypes() { return parameterTypes; } + public String getSignature() { return signature; } + public int getArity() { return parameterTypes.length; } + + public boolean isCompatibleWith(Member am) { + if (kind != METHOD || am.getKind() != METHOD) return true; + if (! name.equals(am.getName())) return true; + if (! equalTypes(getParameterTypes(), am.getParameterTypes())) return true; + return getReturnType().equals(am.getReturnType()); + } + + private static boolean equalTypes(TypeX[] a, TypeX[] b) { + int len = a.length; + if (len != b.length) return false; + for (int i = 0; i < len; i++) { + if (!a[i].equals(b[i])) return false; + } + return true; + } + + // ---- things we know only with resolution + + public int getModifiers(World world) { + return world.getModifiers(this); + } + + public TypeX[] getExceptions(World world) { + return world.getExceptions(this); + } + + public final boolean isProtected(World world) { + return Modifier.isProtected(world.getModifiers(this)); + } + public final boolean isStatic(World world) { + return Modifier.isStatic(world.getModifiers(this)); + } + public final boolean isStrict(World world) { + return Modifier.isStrict(world.getModifiers(this)); + } + + public final boolean isStatic() { + return Modifier.isStatic(modifiers); + } + + public final boolean isInterface() { + return Modifier.isInterface(modifiers); // this is kinda weird + } + + public final boolean isPrivate() { + return Modifier.isPrivate(modifiers); + } + + public final int getCallsiteModifiers() { + return modifiers & ~ Modifier.INTERFACE; + } + + public final String getExtractableName() { + if (name.equals("<init>")) return "init$"; + else if (name.equals("<clinit>")) return "clinit$"; + else return name; + } + + // ---- fields 'n' stuff + + public static final Member[] NONE = new Member[0]; + + public static class Kind extends TypeSafeEnum { + public Kind(String name, int key) { super(name, key); } + + public static Kind read(DataInputStream s) throws IOException { + int key = s.readByte(); + switch(key) { + case 1: return METHOD; + case 2: return FIELD; + case 3: return CONSTRUCTOR; + case 4: return STATIC_INITIALIZATION; + case 5: return POINTCUT; + case 6: return ADVICE; + case 7: return HANDLER; + } + throw new BCException("weird kind " + key); + } + } + + public static final Kind METHOD = new Kind("METHOD", 1); + public static final Kind FIELD = new Kind("FIELD", 2); + public static final Kind CONSTRUCTOR = new Kind("CONSTRUCTOR", 3); + public static final Kind STATIC_INITIALIZATION = new Kind("STATIC_INITIALIZATION", 4); + public static final Kind POINTCUT = new Kind("POINTCUT", 5); + public static final Kind ADVICE = new Kind("ADVICE", 6); + public static final Kind HANDLER = new Kind("HANDLER", 7); + + + + + public Collection/*ResolvedTypeX*/ getDeclaringTypes(World world) { + ResolvedTypeX myType = getDeclaringType().resolve(world); + Collection ret = new HashSet(); + if (kind == CONSTRUCTOR) { + // this is wrong if the member doesn't exist, but that doesn't matter + ret.add(myType); + } else if (isStatic() || kind == FIELD) { + walkUpStatic(ret, myType); + } else { + walkUp(ret, myType); + } + + return ret; + } + + private boolean walkUp(Collection acc, ResolvedTypeX curr) { + if (acc.contains(curr)) return true; + + boolean b = false; + for (Iterator i = curr.getDirectSupertypes(); i.hasNext(); ) { + b |= walkUp(acc, (ResolvedTypeX)i.next()); + } + + if (!b) { + b = curr.lookupMemberNoSupers(this) != null; + } + if (b) acc.add(curr); + return b; + } + + private boolean walkUpStatic(Collection acc, ResolvedTypeX curr) { + if (curr.lookupMemberNoSupers(this) != null) { + acc.add(curr); + return true; + } else { + boolean b = false; + for (Iterator i = curr.getDirectSupertypes(); i.hasNext(); ) { + b |= walkUp(acc, (ResolvedTypeX)i.next()); + } + if (b) acc.add(curr); + return b; + } + } + + // ---- reflective thisJoinPoint stuff + public String getSignatureMakerName() { + Kind kind = getKind(); + if (kind == METHOD) { + return "makeMethodSig"; + } else if (kind == CONSTRUCTOR) { + return "makeConstructorSig"; + } else if (kind == FIELD) { + return "makeFieldSig"; + } else if (kind == HANDLER) { + return "makeCatchClauseSig"; + } else if (kind == STATIC_INITIALIZATION) { + return "makeInitializerSig"; + } else if (kind == ADVICE) { + return "makeAdviceSig"; + } else { + throw new RuntimeException("unimplemented"); + } + } + + + + + public String getSignatureType() { + Kind kind = getKind(); + if (kind == METHOD) { + return "org.aspectj.lang.reflect.MethodSignature"; + } else if (kind == CONSTRUCTOR) { + return "org.aspectj.lang.reflect.ConstructorSignature"; + } else if (kind == FIELD) { + return "org.aspectj.lang.reflect.FieldSignature"; + } else if (kind == HANDLER) { + return "org.aspectj.lang.reflect.CatchClauseSignature"; + } else if (kind == STATIC_INITIALIZATION) { + return "org.aspectj.lang.reflect.InitializerSignature"; + } else if (kind == ADVICE) { + return "org.aspectj.lang.reflect.AdviceSignature"; + } else { + throw new RuntimeException("unimplemented"); + } + } + + public String getSignatureString(World world) { + Kind kind = getKind(); + if (kind == METHOD) { + return getMethodSignatureString(world); + } else if (kind == CONSTRUCTOR) { + return getConstructorSignatureString(world); + } else if (kind == FIELD) { + return getFieldSignatureString(world); + } else if (kind == HANDLER) { + return getHandlerSignatureString(world); + } else if (kind == STATIC_INITIALIZATION) { + return getStaticInitializationSignatureString(world); + } else if (kind == ADVICE) { + return getAdviceSignatureString(world); + } else { + throw new RuntimeException("unimplemented"); + } + } + + private String getHandlerSignatureString(World world) { + StringBuffer buf = new StringBuffer(); + buf.append(makeString(0)); + buf.append('-'); + //buf.append(getName()); + buf.append('-'); + buf.append(makeString(getDeclaringType())); + buf.append('-'); + buf.append(makeString(getParameterTypes()[0])); + buf.append('-'); + //XXX we don't actually try to find the handler parameter name + //XXX it probably wouldn't be too hard + String pName = "<missing>"; + //String[] pNames = getParameterNames(world); + //if (pNames != null) pName = pNames[0]; + buf.append(pName); + buf.append('-'); + return buf.toString(); + } + + private String getStaticInitializationSignatureString(World world) { + StringBuffer buf = new StringBuffer(); + buf.append(makeString(getModifiers(world))); + buf.append('-'); + //buf.append(getName()); + buf.append('-'); + buf.append(makeString(getDeclaringType())); + buf.append('-'); + return buf.toString(); + } + + + + protected String getAdviceSignatureString(World world) { + StringBuffer buf = new StringBuffer(); + buf.append(makeString(getModifiers(world))); + buf.append('-'); + buf.append(getName()); + buf.append('-'); + buf.append(makeString(getDeclaringType())); + buf.append('-'); + buf.append(makeString(getParameterTypes())); + buf.append('-'); + buf.append(makeString(getParameterNames(world))); + buf.append('-'); + buf.append(makeString(getExceptions(world))); + buf.append('-'); + buf.append(makeString(getReturnType())); + buf.append('-'); + return buf.toString(); + } + + + protected String getMethodSignatureString(World world) { + StringBuffer buf = new StringBuffer(); + buf.append(makeString(getModifiers(world))); + buf.append('-'); + buf.append(getName()); + buf.append('-'); + buf.append(makeString(getDeclaringType())); + buf.append('-'); + buf.append(makeString(getParameterTypes())); + buf.append('-'); + buf.append(makeString(getParameterNames(world))); + buf.append('-'); + buf.append(makeString(getExceptions(world))); + buf.append('-'); + buf.append(makeString(getReturnType())); + buf.append('-'); + return buf.toString(); + } + + + + protected String getConstructorSignatureString(World world) { + StringBuffer buf = new StringBuffer(); + buf.append(makeString(getModifiers(world))); + buf.append('-'); + buf.append('-'); + buf.append(makeString(getDeclaringType())); + buf.append('-'); + buf.append(makeString(getParameterTypes())); + buf.append('-'); + buf.append(makeString(getParameterNames(world))); + buf.append('-'); + buf.append(makeString(getExceptions(world))); + buf.append('-'); + return buf.toString(); + } + + + + + protected String getFieldSignatureString(World world) { + StringBuffer buf = new StringBuffer(); + buf.append(makeString(getModifiers(world))); + buf.append('-'); + buf.append(getName()); + buf.append('-'); + buf.append(makeString(getDeclaringType())); + buf.append('-'); + buf.append(makeString(getReturnType())); + buf.append('-'); + return buf.toString(); + } + + protected String makeString(int i) { + return Integer.toString(i, 16); //??? expensive + } + + + + + protected String makeString(TypeX t) { + // this is the inverse of the odd behavior for Class.forName w/ arrays + if (t.isArray()) { + return t.getSignature(); + } else { + return t.getName(); + } + } + + + + protected String makeString(TypeX[] types) { + if (types == null) return ""; + StringBuffer buf = new StringBuffer(); + for (int i = 0, len=types.length; i < len; i++) { + buf.append(makeString(types[i])); + buf.append(':'); + } + return buf.toString(); + } + + + + protected String makeString(String[] names) { + if (names == null) return ""; + StringBuffer buf = new StringBuffer(); + for (int i = 0, len=names.length; i < len; i++) { + buf.append(names[i]); + buf.append(':'); + } + return buf.toString(); + } + + public String[] getParameterNames(World world) { + return world.getParameterNames(this); + } + + + + + + + // ---- + + + + + + + + + + +} + diff --git a/weaver/src/org/aspectj/weaver/NameMangler.java b/weaver/src/org/aspectj/weaver/NameMangler.java new file mode 100644 index 000000000..69a3271fa --- /dev/null +++ b/weaver/src/org/aspectj/weaver/NameMangler.java @@ -0,0 +1,300 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.lang.reflect.Modifier; + +import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.bcel.BcelObjectType; + +public class NameMangler { + private NameMangler() { + throw new RuntimeException("static"); + } + + public static final String PREFIX = "ajc$"; + + + public static final String CFLOW_STACK_TYPE = "org.aspectj.runtime.internal.CFlowStack"; + public static final String SOFT_EXCEPTION_TYPE = "org.aspectj.lang.SoftException"; + + public static final String PERSINGLETON_FIELD_NAME = PREFIX + "perSingletonInstance"; + public static final String PERCFLOW_FIELD_NAME = PREFIX + "perCflowStack"; + //public static final String PERTHIS_FIELD_NAME = PREFIX + "perSingletonInstance"; + + // ----- + public static final String PERCFLOW_PUSH_METHOD = PREFIX + "perCflowPush"; + + public static final String PEROBJECT_BIND_METHOD = PREFIX + "perObjectBind"; + + public static final String AJC_CLINIT_NAME = PREFIX + "clinit"; + + + + public static String perObjectInterfaceGet(TypeX aspectType) { + return makeName(aspectType.getNameAsIdentifier(), "perObjectGet"); + } + + public static String perObjectInterfaceSet(TypeX aspectType) { + return makeName(aspectType.getNameAsIdentifier(), "perObjectSet"); + } + + public static String perObjectInterfaceField(TypeX aspectType) { + return makeName(aspectType.getNameAsIdentifier(), "perObjectField"); + } + + + + public static String privilegedAccessMethodForMethod(String name, TypeX objectType, TypeX aspectType) { + return makeName("privMethod", aspectType.getNameAsIdentifier(), + objectType.getNameAsIdentifier(), name); + } + + public static String privilegedAccessMethodForFieldGet(String name, TypeX objectType, TypeX aspectType) { + return makeName("privFieldGet", aspectType.getNameAsIdentifier(), + objectType.getNameAsIdentifier(), name); + } + + public static String privilegedAccessMethodForFieldSet(String name, TypeX objectType, TypeX aspectType) { + return makeName("privFieldSet", aspectType.getNameAsIdentifier(), + objectType.getNameAsIdentifier(), name); + } + + + + /** + * The name of methods corresponding to advice declarations + */ + public static String adviceName(TypeX aspectType, AdviceKind kind, int position) { + return makeName(kind.getName(), aspectType.getNameAsIdentifier(), + Integer.toHexString(position)); + } + + /** + * This field goes on top-most implementers of the interface the field + * is declared onto + */ + public static String interFieldInterfaceField(TypeX aspectType, TypeX interfaceType, String name) { + return makeName("interField", aspectType.getNameAsIdentifier(), + interfaceType.getNameAsIdentifier(), name); + } + + /** + * This instance method goes on the interface the field is declared onto + * as well as its top-most implementors + */ + public static String interFieldInterfaceSetter(TypeX aspectType, TypeX interfaceType, String name) { + return makeName("interFieldSet", aspectType.getNameAsIdentifier(), + interfaceType.getNameAsIdentifier(), name); + } + + + /** + * This instance method goes on the interface the field is declared onto + * as well as its top-most implementors + */ + public static String interFieldInterfaceGetter(TypeX aspectType, TypeX interfaceType, String name) { + return makeName("interFieldGet", aspectType.getNameAsIdentifier(), + interfaceType.getNameAsIdentifier(), name); + } + + + /** + * This static method goes on the aspect that declares the inter-type field + */ + public static String interFieldSetDispatcher(TypeX aspectType, TypeX onType, String name) { + return makeName("interFieldSetDispatch", aspectType.getNameAsIdentifier(), + onType.getNameAsIdentifier(), name); + } + + /** + * This static method goes on the aspect that declares the inter-type field + */ + public static String interFieldGetDispatcher(TypeX aspectType, TypeX onType, String name) { + return makeName("interFieldGetDispatch", aspectType.getNameAsIdentifier(), + onType.getNameAsIdentifier(), name); + } + + + /** + * This field goes on the class the field + * is declared onto + */ + public static String interFieldClassField(int modifiers, TypeX aspectType, TypeX classType, String name) { + if (Modifier.isPublic(modifiers)) return name; + //??? might want to handle case where aspect and class are in same package similar to public + return makeName("interField", makeVisibilityName(modifiers, aspectType), name); + } + +// /** +// * This static method goes on the aspect that declares the inter-type field +// */ +// public static String classFieldSetDispatcher(TypeX aspectType, TypeX classType, String name) { +// return makeName("interFieldSetDispatch", aspectType.getNameAsIdentifier(), +// classType.getNameAsIdentifier(), name); +// } +// +// /** +// * This static method goes on the aspect that declares the inter-type field +// */ +// public static String classFieldGetDispatcher(TypeX aspectType, TypeX classType, String name) +// { +// return makeName( +// "interFieldGetDispatch", +// aspectType.getNameAsIdentifier(), +// classType.getNameAsIdentifier(), +// name); +// } + + /** + * This static void method goes on the aspect that declares the inter-type field and is called + * from the appropriate place (target's initializer, or clinit, or topmost implementer's inits), + * to initialize the field; + */ + + public static String interFieldInitializer(TypeX aspectType, TypeX classType, String name) + { + return makeName( + "interFieldInit", + aspectType.getNameAsIdentifier(), + classType.getNameAsIdentifier(), + name); + } + + + // ---- + + /** + * This method goes on the target type of the inter-type method. (and possibly the topmost-implemeters, + * if the target type is an interface) + */ + public static String interMethod(int modifiers, TypeX aspectType, TypeX classType, String name) + { + if (Modifier.isPublic(modifiers)) return name; + //??? might want to handle case where aspect and class are in same package similar to public + return makeName("interMethodDispatch2", makeVisibilityName(modifiers, aspectType), name); + } + + /** + * This static method goes on the declaring aspect of the inter-type method. + */ + public static String interMethodDispatcher(TypeX aspectType, TypeX classType, String name) + { + return makeName("interMethodDispatch1", aspectType.getNameAsIdentifier(), + classType.getNameAsIdentifier(), name); + } + + /** + * This static method goes on the declaring aspect of the inter-type method. + */ + public static String interMethodBody(TypeX aspectType, TypeX classType, String name) + { + return makeName("interMethod", aspectType.getNameAsIdentifier(), + classType.getNameAsIdentifier(), name); + } + + // ---- + + /** + * This static method goes on the declaring aspect of the inter-type constructor. + */ + public static String preIntroducedConstructor( + TypeX aspectType, + TypeX targetType) + { + return makeName("preInterConstructor", aspectType.getNameAsIdentifier(), + targetType.getNameAsIdentifier()); + } + + /** + * This static method goes on the declaring aspect of the inter-type constructor. + */ + public static String postIntroducedConstructor( + TypeX aspectType, + TypeX targetType) + { + return makeName("postInterConstructor", aspectType.getNameAsIdentifier(), + targetType.getNameAsIdentifier()); + } + // ---- + + /** + * This static method goes on the declaring aspect of the inter-type method. + */ + public static String superDispatcher(TypeX classType, String name) + { + return makeName("superDispatch", + classType.getNameAsIdentifier(), name); + } + + // ---- + + private static TypeX getOutermostType(TypeX type) { + TypeX outerType = type.getDeclaringType(); + if (outerType == null) return type; + return getOutermostType(outerType); + } + + + private static String makeVisibilityName(int modifiers, TypeX aspectType) { + if (Modifier.isPrivate(modifiers)) { + return getOutermostType(aspectType).getNameAsIdentifier(); + } else if (Modifier.isProtected(modifiers)) { + throw new RuntimeException("protected inter-types not allowed"); + } else if (Modifier.isPublic(modifiers)) { + return ""; + } else { + return aspectType.getPackageNameAsIdentifier(); + } + } + + private static String makeName(String s1, String s2) { + return "ajc$" + s1 + "$" + s2; + } + public static String makeName(String s1, String s2, String s3) { + return "ajc$" + s1 + "$" + s2 + "$" + s3; + } + public static String makeName(String s1, String s2, String s3, String s4) { + return "ajc$" + s1 + "$" + s2 + "$" + s3 + "$" + s4; + } + public static String cflowStack(CrosscuttingMembers xcut) { + return makeName("cflowStack", Integer.toHexString(xcut.getCflowEntries().size())); + } + + + + public static String makeClosureClassName( + BcelObjectType enclosingType, + int index) + { + return enclosingType.getName() + "$AjcClosure" + index; + } + + public static String aroundCallbackMethodName( + Member shadowSig, + LazyClassGen enclosingType) + { + String ret = + shadowSig.getExtractableName() + + "_aroundBody" + + enclosingType.getNewGeneratedNameTag(); + return ret; + } + + public static String proceedMethodName(String adviceMethodName) { + return adviceMethodName + "proceed"; + } + +} diff --git a/weaver/src/org/aspectj/weaver/NewConstructorTypeMunger.java b/weaver/src/org/aspectj/weaver/NewConstructorTypeMunger.java new file mode 100644 index 000000000..5940d4789 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/NewConstructorTypeMunger.java @@ -0,0 +1,78 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.util.Set; + +import org.aspectj.weaver.ResolvedTypeMunger.Kind; + +public class NewConstructorTypeMunger extends ResolvedTypeMunger { + private ResolvedMember syntheticConstructor; + private ResolvedMember explicitConstructor; + + + public NewConstructorTypeMunger( + ResolvedMember signature, + ResolvedMember syntheticConstructor, + ResolvedMember explicitConstructor, + Set superMethodsCalled) + { + super(Constructor, signature); + this.syntheticConstructor = syntheticConstructor; + this.explicitConstructor = explicitConstructor; + this.setSuperMethodsCalled(superMethodsCalled); + + } + + //XXX horrible name clash here + public ResolvedMember getDispatchMethod(TypeX aspectType) { + return AjcMemberMaker.interMethodBody(signature, aspectType); + } + + public void write(DataOutputStream s) throws IOException { + kind.write(s); + signature.write(s); + syntheticConstructor.write(s); + explicitConstructor.write(s); + writeSuperMethodsCalled(s); + } + + public static ResolvedTypeMunger readConstructor(DataInputStream s, ISourceContext context) throws IOException { + return new NewConstructorTypeMunger( + ResolvedMember.readResolvedMember(s, context), + ResolvedMember.readResolvedMember(s, context), + ResolvedMember.readResolvedMember(s, context), + readSuperMethodsCalled(s)); + } + + public ResolvedMember getExplicitConstructor() { + return explicitConstructor; + } + + public ResolvedMember getSyntheticConstructor() { + return syntheticConstructor; + } + + public void setExplicitConstructor(ResolvedMember explicitConstructor) { + this.explicitConstructor = explicitConstructor; + } + + public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedTypeX aspectType) { + ResolvedMember ret = getSyntheticConstructor(); + if (ResolvedTypeX.matches(ret, member)) return getSignature(); + return null; + } + +} diff --git a/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java b/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java new file mode 100644 index 000000000..f30db0970 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/NewFieldTypeMunger.java @@ -0,0 +1,43 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.Set; + +import org.aspectj.weaver.ResolvedTypeMunger.Kind; + +public class NewFieldTypeMunger extends ResolvedTypeMunger { + public NewFieldTypeMunger(ResolvedMember signature, Set superMethodsCalled) { + super(Field, signature); + this.setSuperMethodsCalled(superMethodsCalled); + } + + public ResolvedMember getInitMethod(TypeX aspectType) { + return AjcMemberMaker.interFieldInitializer(signature, aspectType); + } + + public void write(DataOutputStream s) throws IOException { + kind.write(s); + signature.write(s); + writeSuperMethodsCalled(s); + } + + public static ResolvedTypeMunger readField(DataInputStream s, ISourceContext context) throws IOException { + return new NewFieldTypeMunger( + ResolvedMember.readResolvedMember(s, context), + readSuperMethodsCalled(s)); + } +} diff --git a/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java b/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java new file mode 100644 index 000000000..32d77aea6 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/NewMethodTypeMunger.java @@ -0,0 +1,53 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.util.Set; + +import org.aspectj.weaver.ResolvedTypeMunger.Kind; + +public class NewMethodTypeMunger extends ResolvedTypeMunger { + public NewMethodTypeMunger( + ResolvedMember signature, + Set superMethodsCalled) + { + super(Method, signature); + this.setSuperMethodsCalled(superMethodsCalled); + + } + + //XXX horrible name clash here + public ResolvedMember getDispatchMethod(TypeX aspectType) { + return AjcMemberMaker.interMethodBody(signature, aspectType); + } + + public void write(DataOutputStream s) throws IOException { + kind.write(s); + signature.write(s); + writeSuperMethodsCalled(s); + } + + public static ResolvedTypeMunger readMethod(DataInputStream s, ISourceContext context) throws IOException { + return new NewMethodTypeMunger( + ResolvedMember.readResolvedMember(s, context), + readSuperMethodsCalled(s)); + } + + public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedTypeX aspectType) { + ResolvedMember ret = AjcMemberMaker.interMethodDispatcher(getSignature(), aspectType); + if (ResolvedTypeX.matches(ret, member)) return getSignature(); + return null; + } +} diff --git a/weaver/src/org/aspectj/weaver/PerObjectInterfaceTypeMunger.java b/weaver/src/org/aspectj/weaver/PerObjectInterfaceTypeMunger.java new file mode 100644 index 000000000..7f5096882 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/PerObjectInterfaceTypeMunger.java @@ -0,0 +1,68 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.util.Set; + +import org.aspectj.weaver.ResolvedTypeMunger.Kind; +import org.aspectj.weaver.patterns.Pointcut; + +public class PerObjectInterfaceTypeMunger extends ResolvedTypeMunger { + private ResolvedMember getMethod; + private ResolvedMember setMethod; + private TypeX aspectType; + private TypeX interfaceType; + private Pointcut testPointcut; + + + public PerObjectInterfaceTypeMunger(TypeX aspectType, Pointcut testPointcut) { + super(PerObjectInterface, null); + this.aspectType = aspectType; + this.testPointcut = testPointcut; + this.interfaceType = AjcMemberMaker.perObjectInterfaceType(aspectType); + this.getMethod = AjcMemberMaker.perObjectInterfaceGet(aspectType); + this.setMethod = AjcMemberMaker.perObjectInterfaceSet(aspectType); + } + + + public void write(DataOutputStream s) throws IOException { + throw new RuntimeException("shouldn't be serialized"); + } + public TypeX getAspectType() { + return aspectType; + } + + public ResolvedMember getGetMethod() { + return getMethod; + } + + public TypeX getInterfaceType() { + return interfaceType; + } + + public ResolvedMember getSetMethod() { + return setMethod; + } + + public Pointcut getTestPointcut() { + return testPointcut; + } + + public boolean matches(ResolvedTypeX matchType) { + //??? this matches many more types than are needed + return !matchType.isInterface(); + } + +} diff --git a/weaver/src/org/aspectj/weaver/PrivilegedAccessMunger.java b/weaver/src/org/aspectj/weaver/PrivilegedAccessMunger.java new file mode 100644 index 000000000..c957a5656 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/PrivilegedAccessMunger.java @@ -0,0 +1,36 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.util.Set; + +import org.aspectj.weaver.ResolvedTypeMunger.Kind; +import org.aspectj.weaver.patterns.Pointcut; + +public class PrivilegedAccessMunger extends ResolvedTypeMunger { + public PrivilegedAccessMunger(ResolvedMember member) { + super(PrivilegedAccess, member); + } + + + public void write(DataOutputStream s) throws IOException { + throw new RuntimeException("shouldn't be serialized"); + } + + public ResolvedMember getMember() { + return getSignature(); + } + +} diff --git a/weaver/src/org/aspectj/weaver/ResolvedMember.java b/weaver/src/org/aspectj/weaver/ResolvedMember.java new file mode 100644 index 000000000..e7d007cde --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ResolvedMember.java @@ -0,0 +1,156 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; + +import org.aspectj.bridge.ISourceLocation; + +/** + * This is the declared member, i.e. it will always correspond to an + * actual method/... declaration + */ +public class ResolvedMember extends Member implements IHasPosition { + + protected String[] parameterNames = null; + protected TypeX[] checkedExceptions = TypeX.NONE; + + + // these three fields hold the source location of this member + protected int start, end; + protected ISourceContext sourceContext = null; + + // ---- + + public ResolvedMember( + Kind kind, + TypeX declaringType, + int modifiers, + TypeX returnType, + String name, + TypeX[] parameterTypes) + { + super(kind, declaringType, modifiers, returnType, name, parameterTypes); + } + + public ResolvedMember( + Kind kind, + TypeX declaringType, + int modifiers, + String name, + String signature) + { + super(kind, declaringType, modifiers, name, signature); + } + + public static final ResolvedMember[] NONE = new ResolvedMember[0]; + + // ---- + + public final int getModifiers(World world) { + return modifiers; + } + public final int getModifiers() { + return modifiers; + } + + // ---- + + + public final TypeX[] getExceptions(World world) { + return getExceptions(); + } + + public TypeX[] getExceptions() { + return checkedExceptions; + } + + public ShadowMunger getAssociatedShadowMunger() { + return null; + } + + // ??? true or false? + public boolean isAjSynthetic() { + return true; + } + + public void write(DataOutputStream s) throws IOException { + getKind().write(s); + getDeclaringType().write(s); + s.writeInt(modifiers); + s.writeUTF(getName()); + s.writeUTF(getSignature()); + TypeX.write(getExceptions(), s); + + s.writeInt(getStart()); + s.writeInt(getEnd()); + + } + + public static ResolvedMember readResolvedMember(DataInputStream s, ISourceContext sourceContext) throws IOException { + ResolvedMember m = new ResolvedMember(Kind.read(s), TypeX.read(s), s.readInt(), s.readUTF(), s.readUTF()); + m.checkedExceptions = TypeX.readArray(s); + m.start = s.readInt(); + m.end = s.readInt(); + m.sourceContext = sourceContext; + return m; + } + + public ResolvedMember resolve(World world) { + return this; + } + + public ISourceContext getSourceContext(World world) { + return getDeclaringType().resolve(world).getSourceContext(); + } + + public final String[] getParameterNames() { + return parameterNames; + } + public final String[] getParameterNames(World world) { + return getParameterNames(); + } + + public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() { + return null; + } + + public ISourceLocation getSourceLocation() { + //System.out.println("get context: " + this + " is " + sourceContext); + if (sourceContext == null) { + //System.err.println("no context: " + this); + return null; + } + return sourceContext.makeSourceLocation(this); + } + + public int getEnd() { + return end; + } + + public ISourceContext getSourceContext() { + return sourceContext; + } + + public int getStart() { + return start; + } + + public void setPosition(int sourceStart, int sourceEnd) { + this.start = sourceStart; + this.end = sourceEnd; + } + +} + diff --git a/weaver/src/org/aspectj/weaver/ResolvedPointcutDefinition.java b/weaver/src/org/aspectj/weaver/ResolvedPointcutDefinition.java new file mode 100644 index 000000000..8c38d6a99 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ResolvedPointcutDefinition.java @@ -0,0 +1,91 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; + +import org.aspectj.weaver.patterns.Pointcut; + + +public class ResolvedPointcutDefinition extends ResolvedMember { + private Pointcut pointcut; + + public ResolvedPointcutDefinition( + TypeX declaringType, + int modifiers, + String name, + TypeX[] parameterTypes, + Pointcut pointcut) + { + super( + POINTCUT, + declaringType, + modifiers, + ResolvedTypeX.VOID, + name, + parameterTypes); + this.pointcut = pointcut; + //XXXpointcut.assertState(Pointcut.RESOLVED); + checkedExceptions = TypeX.NONE; + } + + // ---- + + public void write(DataOutputStream s) throws IOException { + getDeclaringType().write(s); + s.writeInt(getModifiers()); + s.writeUTF(getName()); + TypeX.write(getParameterTypes(), s); + pointcut.write(s); + } + + public static ResolvedPointcutDefinition read(DataInputStream s, ISourceContext context) throws IOException { + return new ResolvedPointcutDefinition( + TypeX.read(s), + s.readInt(), + s.readUTF(), + TypeX.readArray(s), + Pointcut.read(s, context)); + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("poincut "); + buf.append(getName()); + buf.append("("); + for (int i=0; i < getParameterTypes().length; i++) { + if (i > 0) buf.append(", "); + buf.append(getParameterTypes()[i].toString()); + } + buf.append("): "); + buf.append(pointcut); + + return buf.toString(); + } + + public Pointcut getPointcut() { + return pointcut; + } + + public boolean isAjSynthetic() { + return true; + } + + // for testing + public static final ResolvedPointcutDefinition DUMMY = + new ResolvedPointcutDefinition(TypeX.OBJECT, 0, "missing", + TypeX.NONE, Pointcut.makeMatchesNothing(Pointcut.RESOLVED)); + + +} diff --git a/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java b/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java new file mode 100644 index 000000000..27c0435b7 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ResolvedTypeMunger.java @@ -0,0 +1,162 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.util.*; +import java.util.Set; + +import org.aspectj.util.TypeSafeEnum; + +/** This is an abstraction over method/field introduction. It might not have the chops + * to handle other inter-type declarations. This is the thing that is used on the + * eclipse side and serialized into a ConcreteTypeMunger. + */ +public abstract class ResolvedTypeMunger { + protected Kind kind; + protected ResolvedMember signature; + + private Set /* resolvedMembers */ superMethodsCalled = Collections.EMPTY_SET; + + public ResolvedTypeMunger(Kind kind, ResolvedMember signature) { + this.kind = kind; + this.signature = signature; + } + + // ---- + + // fromType is guaranteed to be a non-abstract aspect + public ConcreteTypeMunger concretize(World world, ResolvedTypeX aspectType) { + ConcreteTypeMunger munger = world.concreteTypeMunger(this, aspectType); + return munger; + } + + + public boolean matches(ResolvedTypeX matchType) { + ResolvedTypeX onType = matchType.getWorld().resolve(signature.getDeclaringType()); + if (matchType.equals(onType)) return true; + + if (onType.isInterface()) { + return matchType.isTopmostImplementor(onType); + } else { + return false; + } + } + + // ---- + + public String toString() { + return "ResolvedTypeMunger(" + getKind() + ", " + getSignature() +")"; + //.superMethodsCalled + ")"; + } + + // ---- + + public static ResolvedTypeMunger read(DataInputStream s, ISourceContext context) throws IOException { + Kind kind = Kind.read(s); + if (kind == Field) { + return NewFieldTypeMunger.readField(s, context); + } else if (kind == Method) { + return NewMethodTypeMunger.readMethod(s, context); + + } else if (kind == Constructor) { + return NewConstructorTypeMunger.readConstructor(s, context); + } else { + throw new RuntimeException("unimplemented"); + } + } + + protected static Set readSuperMethodsCalled(DataInputStream s) throws IOException { + Set ret = new HashSet(); + int n = s.readInt(); + for (int i=0; i < n; i++) { + ret.add(ResolvedMember.readResolvedMember(s, null)); + } + return ret; + } + + protected void writeSuperMethodsCalled(DataOutputStream s) throws IOException { + if (superMethodsCalled == null) { + s.writeInt(0); + return; + } + + List ret = new ArrayList(superMethodsCalled); + Collections.sort(ret); + int n = ret.size(); + s.writeInt(n); + for (Iterator i = ret.iterator(); i.hasNext(); ) { + ResolvedMember m = (ResolvedMember)i.next(); + m.write(s); + } + } + + + public abstract void write(DataOutputStream s) throws IOException; + + public Kind getKind() { + return kind; + } + + + + public static class Kind extends TypeSafeEnum { + private Kind(String name, int key) { + super(name, key); + } + + public static Kind read(DataInputStream s) throws IOException { + int key = s.readByte(); + switch(key) { + case 1: return Field; + case 2: return Method; + case 5: return Constructor; + } + throw new BCException("bad kind: " + key); + } + } + + // ---- fields + + public static final Kind Field = new Kind("Field", 1); + public static final Kind Method = new Kind("Method", 2); + public static final Kind Constructor = new Kind("Constructor", 5); + + // not serialized, only created during concretization of aspects + public static final Kind PerObjectInterface = new Kind("PerObjectInterface", 3); + public static final Kind PrivilegedAccess = new Kind("PrivilegedAccess", 4); + + public static final String SUPER_DISPATCH_NAME = "superDispatch"; + + + public void setSuperMethodsCalled(Set c) { + this.superMethodsCalled = c; + } + + public Set getSuperMethodsCalled() { + return superMethodsCalled; + } + + + public ResolvedMember getSignature() { + return signature; + } + + // ---- + + public ResolvedMember getMatchingSyntheticMember(Member member, ResolvedTypeX aspectType) { + return null; + } + +} diff --git a/weaver/src/org/aspectj/weaver/ResolvedTypeX.java b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java new file mode 100644 index 000000000..b23dbe58f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ResolvedTypeX.java @@ -0,0 +1,975 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.lang.reflect.Modifier; +import java.util.*; + +import org.aspectj.bridge.MessageUtil; +import org.aspectj.weaver.bcel.BcelObjectType; +import org.aspectj.weaver.patterns.*; +import org.aspectj.weaver.patterns.PerClause; + +public abstract class ResolvedTypeX extends TypeX { + + protected World world; + + ResolvedTypeX(String signature, World world) { + super(signature); + this.world = world; + } + + // ---- things that don't require a world + + + /** returns Iterator<ResolvedTypeX> + */ + public final Iterator getDirectSupertypes() { + Iterator ifacesIterator = Iterators.array(getDeclaredInterfaces()); + ResolvedTypeX superclass = getSuperclass(); + if (superclass == null) { + return ifacesIterator; + } else { + return Iterators.snoc(ifacesIterator, superclass); + } + } + + public abstract ResolvedMember[] getDeclaredFields(); + public abstract ResolvedMember[] getDeclaredMethods(); + public abstract ResolvedTypeX[] getDeclaredInterfaces(); + public abstract ResolvedMember[] getDeclaredPointcuts(); + public abstract ResolvedTypeX getSuperclass(); + public abstract int getModifiers(); + + + public abstract boolean needsNoConversionFrom(TypeX other); + public abstract boolean isCoerceableFrom(TypeX other); + public abstract boolean isAssignableFrom(TypeX other); + + // ---- things that would require a world if I weren't resolved + public final Iterator getDirectSupertypes(World world) { + return getDirectSupertypes(); + } + + public final ResolvedMember[] getDeclaredFields(World world) { + return getDeclaredFields(); + } + public final ResolvedMember[] getDeclaredMethods(World world) { + return getDeclaredMethods(); + } + public final TypeX[] getDeclaredInterfaces(World world) { + return getDeclaredInterfaces(); + } + public final ResolvedMember[] getDeclaredPointcuts(World world) { + return getDeclaredPointcuts(); + } + + public final int getModifiers(World world) { + return getModifiers(); + } + public final TypeX getSuperclass(World world) { + return getSuperclass(); + } + + // conversions + public final boolean isAssignableFrom(TypeX other, World world) { + return isAssignableFrom(other); + } + public final boolean isCoerceableFrom(TypeX other, World world) { + return isCoerceableFrom(other); + } + public boolean needsNoConversionFrom(TypeX other, World world) { + return needsNoConversionFrom(other); + } + public final boolean isConvertableFrom(TypeX other) { + if (this.equals(OBJECT) || other.equals(OBJECT)) return true; + return this.isCoerceableFrom(other); + } + + // utilities + public ResolvedTypeX getResolvedComponentType() { + return null; + } + public ResolvedTypeX resolve(World world) { + return this; + } + public World getWorld() { + return world; + } + + // ---- things from object + + public final boolean equals(Object other) { + if (other instanceof ResolvedTypeX) { + return this == other; + } else { + return super.equals(other); + } + } + + // ---- difficult things + + /** + * returns an iterator through all of the fields of this type, in order + * for checking from JVM spec 2ed 5.4.3.2. This means that the order is + * + * <ul><li> fields from current class </li> + * <li> recur into direct superinterfaces </li> + * <li> recur into superclass </li> + * </ul> + * + * We keep a hashSet of interfaces that we've visited so we don't spiral + * out into 2^n land. + */ + public Iterator getFields() { + final Iterators.Filter dupFilter = Iterators.dupFilter(); + Iterators.Getter typeGetter = new Iterators.Getter() { + public Iterator get(Object o) { + return + dupFilter.filter( + ((ResolvedTypeX)o).getDirectSupertypes()); + } + }; + Iterators.Getter fieldGetter = new Iterators.Getter() { + public Iterator get(Object o) { + return Iterators.array(((ResolvedTypeX)o).getDeclaredFields()); + } + }; + return + Iterators.mapOver( + Iterators.recur(this, typeGetter), + fieldGetter); + } + + /** + * returns an iterator through all of the methods of this type, in order + * for checking from JVM spec 2ed 5.4.3.3. This means that the order is + * + * <ul><li> methods from current class </li> + * <li> recur into superclass, all the way up, not touching interfaces </li> + * <li> recur into all superinterfaces, in some unspecified order </li> + * </ul> + * + * We keep a hashSet of interfaces that we've visited so we don't spiral + * out into 2^n land. + */ + public Iterator getMethods() { + final Iterators.Filter dupFilter = Iterators.dupFilter(); + Iterators.Getter ifaceGetter = new Iterators.Getter() { + public Iterator get(Object o) { + return + dupFilter.filter( + Iterators.array(((ResolvedTypeX)o).getDeclaredInterfaces()) + ); + } + }; + Iterators.Getter methodGetter = new Iterators.Getter() { + public Iterator get(Object o) { + return Iterators.array(((ResolvedTypeX)o).getDeclaredMethods()); + } + }; + return + Iterators.mapOver( + Iterators.append( + new Iterator() { + ResolvedTypeX curr = ResolvedTypeX.this; + public boolean hasNext() { + return curr != null; + } + public Object next() { + ResolvedTypeX ret = curr; + curr = curr.getSuperclass(); + return ret; + } + public void remove() { + throw new UnsupportedOperationException(); + } + }, + Iterators.recur(this, ifaceGetter)), + methodGetter); + } + + /** + * described in JVM spec 2ed 5.4.3.2 + */ + public ResolvedMember lookupField(Member m) { + return lookupMember(m, getFields()); + } + + /** + * described in JVM spec 2ed 5.4.3.3 + */ + public ResolvedMember lookupMethod(Member m) { + return lookupMember(m, getMethods()); + } + + /** return null if not found */ + private ResolvedMember lookupMember(Member m, Iterator i) { + while (i.hasNext()) { + ResolvedMember f = (ResolvedMember) i.next(); + if (matches(f, m)) return f; + } + return null; //ResolvedMember.Missing; + //throw new BCException("can't find " + m); + } + + /** return null if not found */ + private ResolvedMember lookupMember(Member m, ResolvedMember[] a) { + for (int i = 0; i < a.length; i++) { + ResolvedMember f = a[i]; + if (matches(f, m)) return f; + } + return null; + } + + + public static boolean matches(Member m1, Member m2) { + return m1.getName().equals(m2.getName()) && m1.getSignature().equals(m2.getSignature()); + } + + + public static boolean conflictingSignature(Member m1, Member m2) { + if (m1 == null || m2 == null) return false; + + if (!m1.getName().equals(m2.getName())) { return false; } + if (m1.getKind() != m2.getKind()) { return false; } + + if (m1.getKind() == Member.FIELD) { + return m1.getDeclaringType().equals(m2.getDeclaringType()); + } + + TypeX[] p1 = m1.getParameterTypes(); + TypeX[] p2 = m2.getParameterTypes(); + int n = p1.length; + if (n != p2.length) return false; + + for (int i=0; i < n; i++) { + if (!p1[i].equals(p2[i])) return false; + } + return true; + } + + + /** + * returns an iterator through all of the pointcuts of this type, in order + * for checking from JVM spec 2ed 5.4.3.2 (as for fields). This means that the order is + * + * <ul><li> pointcuts from current class </li> + * <li> recur into direct superinterfaces </li> + * <li> recur into superclass </li> + * </ul> + * + * We keep a hashSet of interfaces that we've visited so we don't spiral + * out into 2^n land. + */ + private Iterator getPointcuts() { + final Iterators.Filter dupFilter = Iterators.dupFilter(); + // same order as fields + Iterators.Getter typeGetter = new Iterators.Getter() { + public Iterator get(Object o) { + return + dupFilter.filter( + ((ResolvedTypeX)o).getDirectSupertypes()); + } + }; + Iterators.Getter pointcutGetter = new Iterators.Getter() { + public Iterator get(Object o) { + //System.err.println("getting for " + o); + return Iterators.array(((ResolvedTypeX)o).getDeclaredPointcuts()); + } + }; + return + Iterators.mapOver( + Iterators.recur(this, typeGetter), + pointcutGetter); + } + + public ResolvedPointcutDefinition findPointcut(String name) { + //System.err.println("looking for pointcuts " + this); + for (Iterator i = getPointcuts(); i.hasNext(); ) { + ResolvedPointcutDefinition f = (ResolvedPointcutDefinition) i.next(); + //System.err.println(f); + if (name.equals(f.getName())) { + return f; + } + } + return null; // should we throw an exception here? + } + + + // all about collecting CrosscuttingMembers + + //??? collecting data-structure, shouldn't really be a field + public CrosscuttingMembers crosscuttingMembers; + +// +// private List extraConcreteShadowMungers = new ArrayList(); //XXX makes testing easier... +// public void addExtraConcreteShadowMunger(ShadowMunger munger) { +// munger.pointcut.assertState(Pointcut.CONCRETE); +// extraConcreteShadowMungers.add(munger); +// } +// public List getExtraConcreteShadowMungers() { +// return extraConcreteShadowMungers; +// } +// +// private List extraConcreteTypeMungers = new ArrayList(); //XXX makes testing easier...Collections.EMPTY_LIST; +// public void addExtraConcreteTypeMunger(ConcreteTypeMunger munger) { +// //munger.pointcut.assertState(Pointcut.CONCRETE); +// extraConcreteTypeMungers.add(munger); +// } +// public List getExtraConcreteTypeMungers() { +// return extraConcreteTypeMungers; +// } + + + public CrosscuttingMembers collectCrosscuttingMembers() { + crosscuttingMembers = new CrosscuttingMembers(this); + crosscuttingMembers.setPerClause(getPerClause()); + crosscuttingMembers.addShadowMungers(collectShadowMungers()); + crosscuttingMembers.addTypeMungers(getTypeMungers()); + crosscuttingMembers.addDeclares(collectDeclares()); + crosscuttingMembers.addPrivilegedAccesses(getPrivilegedAccesses()); + + //System.err.println("collected cc members: " + this + ", " + collectDeclares()); + return crosscuttingMembers; + } + + private final Collection collectDeclares() { + if (! this.isAspect() ) return Collections.EMPTY_LIST; + + ArrayList ret = new ArrayList(); + //if (this.isAbstract()) { + for (Iterator i = getDeclares().iterator(); i.hasNext();) { + Declare dec = (Declare) i.next(); + if (!dec.isAdviceLike()) ret.add(dec); + } + if (!this.isAbstract()) { + //ret.addAll(getDeclares()); + final Iterators.Filter dupFilter = Iterators.dupFilter(); + Iterators.Getter typeGetter = new Iterators.Getter() { + public Iterator get(Object o) { + return + dupFilter.filter( + ((ResolvedTypeX)o).getDirectSupertypes()); + } + }; + Iterator typeIterator = Iterators.recur(this, typeGetter); + + while (typeIterator.hasNext()) { + ResolvedTypeX ty = (ResolvedTypeX) typeIterator.next(); + //System.out.println("super: " + ty + ", " + ); + for (Iterator i = ty.getDeclares().iterator(); i.hasNext();) { + Declare dec = (Declare) i.next(); + if (dec.isAdviceLike()) ret.add(dec); + } + } + } + + return ret; + } + + + + + private final Collection collectShadowMungers() { + if (! this.isAspect() || this.isAbstract()) return Collections.EMPTY_LIST; + + ArrayList acc = new ArrayList(); + final Iterators.Filter dupFilter = Iterators.dupFilter(); + Iterators.Getter typeGetter = new Iterators.Getter() { + public Iterator get(Object o) { + return + dupFilter.filter( + ((ResolvedTypeX)o).getDirectSupertypes()); + } + }; + Iterator typeIterator = Iterators.recur(this, typeGetter); + + while (typeIterator.hasNext()) { + ResolvedTypeX ty = (ResolvedTypeX) typeIterator.next(); + acc.addAll(ty.getDeclaredShadowMungers()); + } + + return acc; + } + + public PerClause getPerClause() { return null; } + protected Collection getDeclares() { + return Collections.EMPTY_LIST; + } + protected Collection getTypeMungers() { return Collections.EMPTY_LIST; } + + protected Collection getPrivilegedAccesses() { return Collections.EMPTY_LIST; } + + + + // ---- useful things + + public final boolean isInterface() { + return Modifier.isInterface(getModifiers()); + } + + public final boolean isAbstract() { + return Modifier.isAbstract(getModifiers()); + } + + public boolean isClass() { + return false; + } + + public boolean isAspect() { + return false; + } + + + public final boolean isFinal() { + return Modifier.isFinal(getModifiers()); + } + + public Collection getDeclaredAdvice() { + List l = new ArrayList(); + ResolvedMember[] methods = getDeclaredMethods(); + for (int i=0, len = methods.length; i < len; i++) { + ShadowMunger munger = methods[i].getAssociatedShadowMunger(); + if (munger != null) l.add(munger); + } + return l; + } + + private List shadowMungers = new ArrayList(0); + + public Collection getDeclaredShadowMungers() { + Collection c = getDeclaredAdvice(); + c.addAll(shadowMungers); + return c; + } + + + public void addShadowMunger(ShadowMunger munger) { + shadowMungers.add(munger); + } + + + // ---- only for testing! + + + public ResolvedMember[] getDeclaredJavaFields() { + return filterInJavaVisible(getDeclaredFields()); + } + public ResolvedMember[] getDeclaredJavaMethods() { + return filterInJavaVisible(getDeclaredMethods()); + } + public ShadowMunger[] getDeclaredShadowMungersArray() { + List l = (List) getDeclaredShadowMungers(); + return (ShadowMunger[]) l.toArray(new ShadowMunger[l.size()]); + } + private ResolvedMember[] filterInJavaVisible(ResolvedMember[] ms) { + List l = new ArrayList(); + for (int i=0, len = ms.length; i < len; i++) { + if (! ms[i].isAjSynthetic() && ms[i].getAssociatedShadowMunger() == null) { + l.add(ms[i]); + } + } + return (ResolvedMember[]) l.toArray(new ResolvedMember[l.size()]); + } + + public abstract ISourceContext getSourceContext(); + + + // ---- fields + + public static final ResolvedTypeX[] NONE = new ResolvedTypeX[0]; + + public static final Primitive BYTE = new Primitive("B", 1, 0); + public static final Primitive CHAR = new Primitive("C", 1, 1); + public static final Primitive DOUBLE = new Primitive("D", 2, 2); + public static final Primitive FLOAT = new Primitive("F", 1, 3); + public static final Primitive INT = new Primitive("I", 1, 4); + public static final Primitive LONG = new Primitive("J", 2, 5); + public static final Primitive SHORT = new Primitive("S", 1, 6); + public static final Primitive VOID = new Primitive("V", 0, 8); + public static final Primitive BOOLEAN = new Primitive("Z", 1, 7); + public static final Missing MISSING = new Missing(); + + // ---- types + + public static abstract class Name extends ResolvedTypeX { + protected ISourceContext sourceContext; + + public Name(String signature, World world) { + super(signature, world); + } + + public final boolean isClass() { + return !isAspect() && !isInterface(); + } + + public abstract boolean isAspect(); + public final boolean isAssignableFrom(TypeX o) { + if (o.isPrimitive()) return false; + ResolvedTypeX other = o.resolve(world); + + return isAssignableFrom(other); + } + private boolean isAssignableFrom(ResolvedTypeX other) { + if (this == other) return true; + for(Iterator i = other.getDirectSupertypes(); i.hasNext(); ) { + if (this.isAssignableFrom((ResolvedTypeX) i.next())) return true; + } + return false; + } + public final boolean isCoerceableFrom(TypeX o) { + ResolvedTypeX other = o.resolve(world); + + if (this.isAssignableFrom(other) || other.isAssignableFrom(this)) { + return true; + } + if (!this.isInterface() && !other.isInterface()) { + return false; + } + if (this.isFinal() || other.isFinal()) { + return false; + } + // ??? needs to be Methods, not just declared methods? JLS 5.5 unclear + ResolvedMember[] a = getDeclaredMethods(); + ResolvedMember[] b = ((Name)other).getDeclaredMethods(); + for (int ai = 0, alen = a.length; ai < alen; ai++) { + for (int bi = 0, blen = b.length; bi < blen; bi++) { + if (! b[bi].isCompatibleWith(a[ai])) return false; + } + } + return true; + } + public final boolean needsNoConversionFrom(TypeX o) { + return isAssignableFrom(o); + } + + public ResolvedMember addPerSingletonField() { + throw new RuntimeException("unimplemented"); + } + + public ISourceContext getSourceContext() { + return sourceContext; + } + + } + + static class Array extends ResolvedTypeX { + ResolvedTypeX componentType; + Array(String s, World world, ResolvedTypeX componentType) { + super(s, world); + this.componentType = componentType; + } + public final ResolvedMember[] getDeclaredFields() { + return ResolvedMember.NONE; + } + public final ResolvedMember[] getDeclaredMethods() { + // ??? should this return clone? Probably not... + return ResolvedMember.NONE; + } + public final ResolvedTypeX[] getDeclaredInterfaces() { + return + new ResolvedTypeX[] { + world.resolve(CLONEABLE), + world.resolve(SERIALIZABLE) + }; + } + public final ResolvedMember[] getDeclaredPointcuts() { + return ResolvedMember.NONE; + } + + public final ResolvedTypeX getSuperclass() { + return world.resolve(OBJECT); + } + public final boolean isAssignableFrom(TypeX o) { + if (! o.isArray()) return false; + if (o.getComponentType().isPrimitive()) { + return o.equals(this); + } else { + return getComponentType().isAssignableFrom(o.getComponentType(), world); + } + } + public final boolean isCoerceableFrom(TypeX o) { + if (o.equals(TypeX.OBJECT) || + o.equals(TypeX.SERIALIZABLE) || + o.equals(TypeX.CLONEABLE)) { + return true; + } + if (! o.isArray()) return false; + if (o.getComponentType().isPrimitive()) { + return o.equals(this); + } else { + return getComponentType().isCoerceableFrom(o.getComponentType(), world); + } + } + public final boolean needsNoConversionFrom(TypeX o) { + return isAssignableFrom(o); + } + public final int getModifiers() { + int mask = Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED; + return (componentType.getModifiers() & mask) | Modifier.FINAL; + } + public TypeX getComponentType() { + return componentType; + } + public ResolvedTypeX getResolvedComponentType() { + return componentType; + } + public ISourceContext getSourceContext() { + return getResolvedComponentType().getSourceContext(); + } + } + + static class Primitive extends ResolvedTypeX { + private int size; + private int index; + Primitive(String signature, int size, int index) { + super(signature, null); + this.size = size; + this.index = index; + } + public final int getSize() { + return size; + } + public final int getModifiers() { + return Modifier.PUBLIC | Modifier.FINAL; + } + public final boolean isPrimitive() { + return true; + } + public final boolean isAssignableFrom(TypeX other) { + if (! other.isPrimitive()) return false; + return assignTable[((Primitive)other).index][index]; + } + public final boolean isCoerceableFrom(TypeX other) { + if (this == other) return true; + if (! other.isPrimitive()) return false; + if (index > 6 || ((Primitive)other).index > 6) return false; + return true; + } + public final boolean needsNoConversionFrom(TypeX other) { + if (! other.isPrimitive()) return false; + return noConvertTable[((Primitive)other).index][index]; + } + private static final boolean[][] assignTable = + {// to: B C D F I J S V Z from + { true , true , true , true , true , true , true , false, false }, // B + { false, true , true , true , true , true , false, false, false }, // C + { false, false, true , false, false, false, false, false, false }, // D + { false, false, true , true , false, false, false, false, false }, // F + { false, false, true , true , true , true , false, false, false }, // I + { false, false, true , true , false, true , false, false, false }, // J + { false, false, true , true , true , true , true , false, false }, // S + { false, false, false, false, false, false, false, true , false }, // V + { false, false, false, false, false, false, false, false, true }, // Z + }; + private static final boolean[][] noConvertTable = + {// to: B C D F I J S V Z from + { true , true , false, false, true , false, true , false, false }, // B + { false, true , false, false, true , false, false, false, false }, // C + { false, false, true , false, false, false, false, false, false }, // D + { false, false, false, true , false, false, false, false, false }, // F + { false, false, false, false, true , false, false, false, false }, // I + { false, false, false, false, false, true , false, false, false }, // J + { false, false, false, false, true , false, true , false, false }, // S + { false, false, false, false, false, false, false, true , false }, // V + { false, false, false, false, false, false, false, false, true }, // Z + }; + + // ---- + + public final ResolvedMember[] getDeclaredFields() { + return ResolvedMember.NONE; + } + public final ResolvedMember[] getDeclaredMethods() { + return ResolvedMember.NONE; + } + public final ResolvedTypeX[] getDeclaredInterfaces() { + return ResolvedTypeX.NONE; + } + public final ResolvedMember[] getDeclaredPointcuts() { + return ResolvedMember.NONE; + } + + public final ResolvedTypeX getSuperclass() { + return null; + } + + public ISourceContext getSourceContext() { + return null; + } + + } + + static class Missing extends ResolvedTypeX { + Missing() { + super(MISSING_NAME, null); + } +// public final String toString() { +// return "<missing>"; +// } + public final String getName() { + return MISSING_NAME; + } + public final ResolvedMember[] getDeclaredFields() { + return ResolvedMember.NONE; + } + public final ResolvedMember[] getDeclaredMethods() { + return ResolvedMember.NONE; + } + public final ResolvedTypeX[] getDeclaredInterfaces() { + return ResolvedTypeX.NONE; + } + + public final ResolvedMember[] getDeclaredPointcuts() { + return ResolvedMember.NONE; + } + public final ResolvedTypeX getSuperclass() { + return null; + } + public final int getModifiers() { + return 0; + } + public final boolean isAssignableFrom(TypeX other) { + return false; + } + public final boolean isCoerceableFrom(TypeX other) { + return false; + } + public boolean needsNoConversionFrom(TypeX other) { + return false; + } + public ISourceContext getSourceContext() { + return null; + } + + } + + /** return null if not found */ + public ResolvedMember lookupMemberNoSupers(Member member) { + if (member.getKind() == Member.FIELD) { + return lookupMember(member, getDeclaredFields()); + } else { + // assert member.getKind() == Member.METHOD || member.getKind() == Member.CONSTRUCTOR + return lookupMember(member, getDeclaredMethods()); + } + } + + protected List interTypeMungers = new ArrayList(0); + + public List getInterTypeMungers() { + return interTypeMungers; + } + + private static ResolvedTypeX getOutermostType(ResolvedTypeX t) { + TypeX dec = t.getDeclaringType(); + if (dec == null) return t; + return getOutermostType(dec.resolve(t.getWorld())); + } + + public static boolean isVisible(int modifiers, ResolvedTypeX targetType, ResolvedTypeX fromType) { + //System.err.println("mod: " + modifiers + ", " + targetType + " and " + fromType); + + if (Modifier.isPublic(modifiers)) { + return true; + } else if (Modifier.isPrivate(modifiers)) { + return getOutermostType(targetType).equals(getOutermostType(fromType)); + } else if (Modifier.isProtected(modifiers)) { + return samePackage(targetType, fromType) || targetType.isAssignableFrom(fromType); + } else { // package-visible + return samePackage(targetType, fromType); + } + } + + private static boolean samePackage( + ResolvedTypeX targetType, + ResolvedTypeX fromType) + { + String p1 = targetType.getPackageName(); + String p2 = fromType.getPackageName(); + if (p1 == null) return p2 == null; + if (p2 == null) return false; + return p1.equals(p2); + } + + public void addInterTypeMunger(ConcreteTypeMunger munger) { + ResolvedMember sig = munger.getSignature(); + if (sig == null) { + interTypeMungers.add(munger); + return; + } + + //System.err.println("add: " + munger + " to " + this.getClassName() + " with " + interTypeMungers); + if (sig.getKind() == Member.METHOD) { + if (!compareToExistingMembers(munger, getMethods())) return; + if (this.isInterface()) { + if (!compareToExistingMembers(munger, + Arrays.asList(world.resolve(OBJECT).getDeclaredMethods()).iterator())) return; + } + } else if (sig.getKind() == Member.FIELD) { + if (!compareToExistingMembers(munger, Arrays.asList(getDeclaredFields()).iterator())) return; + } else { + if (!compareToExistingMembers(munger, Arrays.asList(getDeclaredMethods()).iterator())) return; + } + + + // now compare to existingMungers + for (Iterator i = interTypeMungers.iterator(); i.hasNext(); ) { + ConcreteTypeMunger existingMunger = (ConcreteTypeMunger)i.next(); + if (conflictingSignature(existingMunger.getSignature(), munger.getSignature())) { + //System.err.println("match " + munger + " with " + existingMunger); + if (isVisible(munger.getSignature().getModifiers(), + munger.getAspectType(), existingMunger.getAspectType())) + { + //System.err.println(" is visible"); + int c = compareMemberPrecedence(sig, existingMunger.getSignature()); + if (c == 0) { + c = getWorld().comparePrecedence(munger.getAspectType(), existingMunger.getAspectType()); + } + //System.err.println(" compare: " + c); + if (c < 0) { + // the existing munger dominates the new munger + return; + } else if (c > 0) { + // the new munger dominates the existing one + i.remove(); + break; + } else { + interTypeConflictError(munger, existingMunger); + interTypeConflictError(existingMunger, munger); + return; + } + } + } + } + //System.err.println("adding: " + munger + " to " + this); + interTypeMungers.add(munger); + } + + + //??? returning too soon + private boolean compareToExistingMembers(ConcreteTypeMunger munger, Iterator existingMembers) { + ResolvedMember sig = munger.getSignature(); + while (existingMembers.hasNext()) { + ResolvedMember existingMember = (ResolvedMember)existingMembers.next(); + + if (conflictingSignature(existingMember, munger.getSignature())) { + //System.err.println("conflict: " + existingMember + " with " + munger); + if (isVisible(existingMember.getModifiers(), this, munger.getAspectType())) { + int c = compareMemberPrecedence(sig, existingMember); + //System.err.println(" c: " + c); + if (c < 0) return false; + else if (c > 0) { + //interTypeMungers.add(munger); + //??? might need list of these overridden abstracts + continue; + } else { + if (this instanceof BcelObjectType) return false; //XXX ignores separate comp + getWorld().getMessageHandler().handleMessage( + MessageUtil.error("inter-type declaration from " + munger.getAspectType() + + " conflicts with existing member: " + existingMember, + munger.getSourceLocation()) + ); + } + } else { + //interTypeMungers.add(munger); + } + //return; + } + } + return true; + } + + + + + private int compareMemberPrecedence(ResolvedMember m1, ResolvedMember m2) { + if (!m1.getReturnType().equals(m2.getReturnType())) return 0; + + if (Modifier.isAbstract(m1.getModifiers())) return -1; + if (Modifier.isAbstract(m2.getModifiers())) return +1; + + if (m1.getDeclaringType().equals(m2.getDeclaringType())) return 0; + + ResolvedTypeX t1 = m1.getDeclaringType().resolve(world); + ResolvedTypeX t2 = m2.getDeclaringType().resolve(world); + if (t1.isAssignableFrom(t2)) { + checkVisibility(m1.getModifiers(), m2.getModifiers()); //XXX needs to be before abstract + return -1; + } + if (t2.isAssignableFrom(t1)) { + checkVisibility(m2.getModifiers(), m1.getModifiers()); + return +1; + } + return 0; + } + + + private void checkVisibility(int parentMods, int childMods) { + //childMods must be equal to or greater than parentMods visibility + + } + + + + private void interTypeConflictError( + ConcreteTypeMunger m1, + ConcreteTypeMunger m2) + { + //XXX this works only if we ignore separate compilation issues + if (this instanceof BcelObjectType) return; + + //System.err.println("conflict at " + m2.getSourceLocation()); + getWorld().getMessageHandler().handleMessage(MessageUtil.error( + "intertype declaration from " + + m1.getAspectType().getClassName() + + " conflicts with intertype declaration: " + + m2.getSignature() + + " from " + + m2.getAspectType().getClassName(), + m2.getSourceLocation())); + } + + + public ResolvedMember lookupSyntheticMember(Member member) { + //??? horribly inefficient + //for (Iterator i = + //System.err.println("lookup " + member + " in " + interTypeMungers); + for (Iterator i = interTypeMungers.iterator(); i.hasNext(); ) { + ConcreteTypeMunger m = (ConcreteTypeMunger)i.next(); + ResolvedMember ret = m.getMatchingSyntheticMember(member); + if (ret != null) { + //System.err.println(" found: " + ret); + return ret; + } + } + return null; + } + + public void clearInterTypeMungers() { + interTypeMungers = new ArrayList(); + } + + + public boolean isTopmostImplementor(ResolvedTypeX interfaceType) { + if (isInterface()) return false; + if (!interfaceType.isAssignableFrom(this)) return false; + // check that I'm truly the topmost implementor + if (interfaceType.isAssignableFrom(this.getSuperclass())) { + return false; + } + return true; + } + +} diff --git a/weaver/src/org/aspectj/weaver/Shadow.java b/weaver/src/org/aspectj/weaver/Shadow.java new file mode 100644 index 000000000..22f86deb9 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/Shadow.java @@ -0,0 +1,233 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Field; +import org.aspectj.weaver.ast.Var; +import org.aspectj.weaver.patterns.IScope; +import org.aspectj.bridge.*; +import org.aspectj.bridge.SourceLocation; +import org.aspectj.lang.JoinPoint; +import org.aspectj.util.*; + +/* + * The superclass of anything representing a the shadow of a join point. A shadow represents + * some bit of code, and encompasses both entry and exit from that code. All shadows have a kind + * and a signature. + */ + +public abstract class Shadow { + private final Kind kind; + private final Member signature; + protected List mungers = new ArrayList(1); + + // ---- + + protected Shadow(Kind kind, Member signature) { + this.kind = kind; + this.signature = signature; + } + + // ---- + + public abstract World getIWorld(); + + public final boolean hasTarget() { + return !(getSignature().isStatic() || (getKind() == ConstructorCall) + || (getKind() == PreInitialization)); + } + + public final TypeX getTargetType() { + if (!hasTarget()) return ResolvedTypeX.MISSING; + return getSignature().getDeclaringType(); + } + public TypeX getArgType(int arg) { + if (getKind() == FieldSet) return getSignature().getReturnType(); + return getSignature().getParameterTypes()[arg]; + } + + public int getArgCount() { + if (getKind() == FieldSet) return 1; + return getSignature() + .getParameterTypes().length; + } + + public abstract boolean hasThis(); + public abstract TypeX getThisType(); + public abstract TypeX getEnclosingType(); + public abstract Var getThisVar(); + public abstract Var getTargetVar(); + public abstract Var getArgVar(int i); + + public abstract Var getThisJoinPointVar(); + public abstract Var getThisJoinPointStaticPartVar(); + public abstract Var getThisEnclosingJoinPointStaticPartVar(); + + public abstract Member getEnclosingCodeSignature(); + + + /** returns the kind of shadow this is, representing what happens under this shadow + */ + public Kind getKind() { + return kind; + } + + /** returns the signature of the thing under this shadow + */ + public Member getSignature() { + return signature; + } + + + public TypeX getReturnType() { + if (kind == ConstructorCall) return getSignature().getDeclaringType(); + return getSignature().getReturnType(); + } + + + /** + * These names are the ones that will be returned by thisJoinPoint.getKind() + * Those need to be documented somewhere + */ + public static final Kind MethodCall = new Kind(JoinPoint.METHOD_CALL, 1, true); + public static final Kind ConstructorCall = new Kind(JoinPoint.CONSTRUCTOR_CALL, 2, true); + public static final Kind MethodExecution = new Kind(JoinPoint.METHOD_EXECUTION, 3, false); + public static final Kind ConstructorExecution = new Kind(JoinPoint.CONSTRUCTOR_EXECUTION, 4, false); + public static final Kind FieldGet = new Kind(JoinPoint.FIELD_GET, 5, true); + public static final Kind FieldSet = new Kind(JoinPoint.FIELD_SET, 6, true); + public static final Kind StaticInitialization = new Kind(JoinPoint.STATICINITIALIZATION, 7, false); + public static final Kind PreInitialization = new Kind(JoinPoint.PREINTIALIZATION, 8, false); + public static final Kind AdviceExecution = new Kind(JoinPoint.ADVICE_EXECUTION, 9, false); + public static final Kind Initialization = new Kind(JoinPoint.INITIALIZATION, 10, false); + public static final Kind ExceptionHandler = new Kind(JoinPoint.EXCEPTION_HANDLER, 11, true); + + + /** A type-safe enum representing the kind of shadows + */ + public static final class Kind extends TypeSafeEnum { + private boolean argsOnStack; + + public Kind(String name, int key, boolean argsOnStack) { + super(name, key); + this.argsOnStack = argsOnStack; + } + + public String toLegalJavaIdentifier() { + return getName().replace('-', '_'); + } + + public boolean argsOnStack() { + return argsOnStack; + } + + // !!! this is false for handlers! + public boolean allowsExtraction() { + return true; + } + + public String getSimpleName() { + int dash = getName().lastIndexOf('-'); + if (dash == -1) return getName(); + else return getName().substring(dash+1); + } + + public static Kind read(DataInputStream s) throws IOException { + int key = s.readByte(); + switch(key) { + case 1: return MethodCall; + case 2: return ConstructorCall; + case 3: return MethodExecution; + case 4: return ConstructorExecution; + case 5: return FieldGet; + case 6: return FieldSet; + case 7: return StaticInitialization; + case 8: return PreInitialization; + case 9: return AdviceExecution; + case 10: return Initialization; + case 11: return ExceptionHandler; + } + throw new BCException("unknown kind: " + key); + } + } + + public void addMunger(ShadowMunger munger) { + this.mungers.add(munger); + } + + public final void implement() { + sortMungers(); + if (mungers == null) return; + prepareForMungers(); + implementMungers(); + } + + private void sortMungers() { + List sorted = PartialOrder.sort(mungers); + if (sorted == null) { + // this means that we have circular dependencies + for (Iterator i = mungers.iterator(); i.hasNext(); ) { + ShadowMunger m = (ShadowMunger)i.next(); + getIWorld().getMessageHandler().handleMessage( + MessageUtil.error("circular dependency at " + this, m.getSourceLocation())); + } + } + mungers = sorted; + } + + /** Prepare the shadow for implementation. After this is done, the shadow + * should be in such a position that each munger simply needs to be implemented. + */ + protected void prepareForMungers() { + throw new RuntimeException("Generic shadows cannot be prepared"); + } + + /** Actually implement the (non-empty) mungers associated with this shadow */ + private void implementMungers() { + World world = getIWorld(); + for (Iterator iter = mungers.iterator(); iter.hasNext();) { + ShadowMunger munger = (ShadowMunger) iter.next(); + munger.implementOn(this); + if (world.getModel() != null) { + System.err.println("munger: " + munger + " on " + this); + AsmAdaptor.noteMunger(world.getModel(), this, munger); + } + } + } + + public String makeReflectiveFactoryString() { + return null; //XXX + } + + public abstract SourceLocation getSourceLocation(); + + // ---- utility + + public String toString() { + return getKind() + "(" + getSignature() + ")"; // + getSourceLines(); + } + + + + + + // ---- type access methods + + + +} diff --git a/weaver/src/org/aspectj/weaver/ShadowMunger.java b/weaver/src/org/aspectj/weaver/ShadowMunger.java new file mode 100644 index 000000000..4cce6743b --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ShadowMunger.java @@ -0,0 +1,87 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.util.PartialOrder; +import org.aspectj.weaver.patterns.*; +import org.aspectj.weaver.patterns.PerClause; + +/** + * For every shadow munger, nothing can be done with it until it is concretized. Then... + * + * (Then we call fast match.) + * + * For every shadow munger, for every shadow, + * first match is called, + * then (if match returned true) the shadow munger is specialized for the shadow, + * which may modify state. + * Then implement is called. + */ + +public abstract class ShadowMunger implements PartialOrder.PartialComparable, IHasPosition { + protected Pointcut pointcut; + + // these three fields hold the source location of this munger + protected int start, end; + protected ISourceContext sourceContext; + + + public ShadowMunger(Pointcut pointcut, int start, int end, ISourceContext sourceContext) { + this.pointcut = pointcut; + this.start = start; + this.end = end; + this.sourceContext = sourceContext; + } + + public abstract ShadowMunger concretize(ResolvedTypeX fromType, World world, PerClause clause); + + public abstract void specializeOn(Shadow shadow); + public abstract void implementOn(Shadow shadow); + + /** + * All overriding methods should call super + */ + public boolean match(Shadow shadow, World world) { + return pointcut.match(shadow).maybeTrue(); + } + + public int fallbackCompareTo(Object other) { + return toString().compareTo(toString()); + } + + public int getEnd() { + return end; + } + + public int getStart() { + return start; + } + + public ISourceLocation getSourceLocation() { + //System.out.println("get context: " + this + " is " + sourceContext); + if (sourceContext == null) { + //System.err.println("no context: " + this); + return null; + } + return sourceContext.makeSourceLocation(this); + } + + // ---- fields + + public static final ShadowMunger[] NONE = new ShadowMunger[0]; + + + +} diff --git a/weaver/src/org/aspectj/weaver/StaticJoinPointFactory.java b/weaver/src/org/aspectj/weaver/StaticJoinPointFactory.java new file mode 100644 index 000000000..d0f5ab4f1 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/StaticJoinPointFactory.java @@ -0,0 +1,58 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.StringReader; +import java.util.*; + +public class StaticJoinPointFactory { +// int usedKeys; +// +// List/*String*/ strings = new ArrayList(); +// Map/*String,Integer*/ keysForStrings = new HashMap(); +// +// public StaticJoinPointFactory() { +// super(); +// } +// +// static char[] encoding = new char[] { +// '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',//10 +// 'a', 'b', 'z', //36 +// 'A', 'B', 'Z', //62 +// '%', '$', //64 +// }; +// +// static int TWO_WORDS = 64*64-1; +// static int WORD_MASK = 63; +// +// public void write(String s, StringBuffer result) { +// int i = getIndex(s); +// encode(i, result); +// } +// +// void encode(int i, StringBuffer result) { +// if (i > TWO_WORDS) { +// throw new RuntimeException("unimplemented"); +// } else { +// result.append( encoding[(i >> 6) & WORD_MASK] ); +// result.append( encoding[i & WORD_MASK] ); +// } +// } +// +// public String read(StringReader reader) { +// int i = reader.read(); +// +// } + +} diff --git a/weaver/src/org/aspectj/weaver/TypeX.java b/weaver/src/org/aspectj/weaver/TypeX.java new file mode 100644 index 000000000..94c86201c --- /dev/null +++ b/weaver/src/org/aspectj/weaver/TypeX.java @@ -0,0 +1,683 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.Iterator; + +import org.aspectj.weaver.patterns.PerClause; + +public class TypeX { + /** + * This is the bytecode string representation of this Type + */ + protected String signature; + + /** + * @param signature the bytecode string representation of this Type + */ + protected TypeX(String signature) { + super(); + this.signature = signature; + } + + // ---- Things we can do without a world + + /** + * This is the size of this type as used in JVM. + */ + public int getSize() { + return 1; + } + + /** + * Equality is checked based on the underlying signature. + * {@link ResolvedType} objects' equals is by reference. + */ + public boolean equals(Object other) { + if (! (other instanceof TypeX)) return false; + return signature.equals(((TypeX) other).signature); + } + + /** + * Equality is checked based on the underlying signature, so the hash code + * of a particular type is the hash code of its signature string. + */ + public final int hashCode() { + return signature.hashCode(); + } + + /** + * Constructs a TypeX for a java language type name. For example: + * + * <blockquote><pre> + * TypeX.forName("java.lang.Thread[]") + * TypeX.forName("int") + * </pre></blockquote> + * + * Types may equivalently be produced by this or by {@link #forSignature(String)}. + * + * <blockquote><pre> + * TypeX.forName("java.lang.Thread[]").equals(Type.forSignature("[Ljava/lang/Thread;") + * TypeX.forName("int").equals(Type.forSignature("I")) + * </pre></blockquote> + * + * @param name the java language type name in question. + * @return a type object representing that java language type. + */ + public static TypeX forName(String name) { + return forSignature(nameToSignature(name)); + } + + /** Constructs a TypeX for each java language type name in an incoming array. + * + * @param names an array of java language type names. + * @return an array of TypeX objects. + * @see #forName(String) + */ + public static TypeX[] forNames(String[] names) { + TypeX[] ret = new TypeX[names.length]; + for (int i = 0, len = names.length; i < len; i++) { + ret[i] = TypeX.forName(names[i]); + } + return ret; + } + + /** + * Creates a new type array with a fresh type appended to the end. + * + * @param types the left hand side of the new array + * @param end the right hand side of the new array + */ + public static TypeX[] add(TypeX[] types, TypeX end) { + int len = types.length; + TypeX[] ret = new TypeX[len + 1]; + System.arraycopy(types, 0, ret, 0, len); + ret[len] = end; + return ret; + } + + /** + * Creates a new type array with a fresh type inserted at the beginning. + * + * + * @param start the left hand side of the new array + * @param types the right hand side of the new array + */ + public static TypeX[] insert(TypeX start, TypeX[] types) { + int len = types.length; + TypeX[] ret = new TypeX[len + 1]; + ret[0] = start; + System.arraycopy(types, 0, ret, 1, len); + return ret; + } + + /** + * Constructs a Type for a JVM bytecode signature string. For example: + * + * <blockquote><pre> + * TypeX.forSignature("[Ljava/lang/Thread;") + * TypeX.forSignature("I"); + * </pre></blockquote> + * + * Types may equivalently be produced by this or by {@link #forName(String)}. + * + * <blockquote><pre> + * TypeX.forName("java.lang.Thread[]").equals(Type.forSignature("[Ljava/lang/Thread;") + * TypeX.forName("int").equals(Type.forSignature("I")) + * </pre></blockquote> + * + * @param signature the JVM bytecode signature string for the desired type. + * @return a type object represnting that JVM bytecode signature. + */ + public static TypeX forSignature(String signature) { + switch (signature.charAt(0)) { + case 'B': return ResolvedTypeX.BYTE; + case 'C': return ResolvedTypeX.CHAR; + case 'D': return ResolvedTypeX.DOUBLE; + case 'F': return ResolvedTypeX.FLOAT; + case 'I': return ResolvedTypeX.INT; + case 'J': return ResolvedTypeX.LONG; + case 'L': + return new TypeX(signature); + case 'S': return ResolvedTypeX.SHORT; + case 'V': return ResolvedTypeX.VOID; + case 'Z': return ResolvedTypeX.BOOLEAN; + case '[': + return new TypeX(signature); + default: + throw new BCException("Bad type signature " + signature); + } + } + + /** Constructs a TypeX for each JVM bytecode type signature in an incoming array. + * + * @param names an array of JVM bytecode type signatures + * @return an array of TypeX objects. + * @see #forSignature(String) + */ + public static TypeX[] forSignatures(String[] sigs) { + TypeX[] ret = new TypeX[sigs.length]; + for (int i = 0, len = sigs.length; i < len; i++) { + ret[i] = TypeX.forSignature(sigs[i]); + } + return ret; + } + + /** + * Returns the name of this type in java language form. For all + * TypeX t: + * + * <blockquote><pre> + * TypeX.forName(t.getName()).equals(t) + * </pre></blockquote> + * + * and for all String s where s is a lexically valid java language typename: + * + * <blockquote><pre> + * TypeX.forName(s).getName().equals(s) + * </pre></blockquote> + * + * This produces a more esthetically pleasing string than + * {@link java.lang.Class#getName()}. + * + * @return the java language name of this type. + */ + public String getName() { + return signatureToName(signature); + } + + /** + * Returns an array of strings representing the java langauge names of + * an array of types. + * + * @param types an array of TypeX objects + * @return an array of Strings fo the java language names of types. + * @see #getName() + */ + public static String[] getNames(TypeX[] types) { + String[] ret = new String[types.length]; + for (int i = 0, len = types.length; i < len; i++) { + ret[i] = types[i].getName(); + } + return ret; + } + + /** + * Returns the name of this type in JVM signature form. For all + * TypeX t: + * + * <blockquote><pre> + * TypeX.forSignature(t.getSignature()).equals(t) + * </pre></blockquote> + * + * and for all String s where s is a lexically valid JVM type signature string: + * + * <blockquote><pre> + * TypeX.forSignature(s).getSignature().equals(s) + * </pre></blockquote> + * + * @return the java JVM signature string for this type. + */ + public String getSignature() { + return signature; + } + + /** + * Determins if this represents an array type. + * + * @return true iff this represents an array type. + */ + public final boolean isArray() { + return signature.startsWith("["); + } + + /** + * Returns a TypeX object representing the declaring type of this type, or + * null if this type does not represent a non-package-level-type. + * + * <strong>Warning</strong>: This is guaranteed to work for all member types. + * For anonymous/local types, the only guarantee is given in JLS 13.1, where + * it guarantees that if you call getDeclaringType() repeatedly, you will eventually + * get the top-level class, but it does not say anything about classes in between. + * + * @return the declaring TypeX object, or null. + */ + public TypeX getDeclaringType() { + if (isArray()) return null; + String name = getName(); + int lastDollar = name.lastIndexOf('$'); + if (lastDollar != -1) { + return TypeX.forName(name.substring(0, lastDollar)); + } else { + return null; + } + } + + /** + * Returns a TypeX object representing the component type of this array, or + * null if this type does not represent an array type. + * + * @return the component TypeX object, or null. + */ + public TypeX getComponentType() { + if (isArray()) { + return forSignature(signature.substring(1)); + } else { + return null; + } + } + + /** + * Determines if this represents a primitive type. A primitive type + * is one of nine predefined resolved types. + * + * @return true iff this type represents a primitive type + * + * @see ResolvedTypeX#Boolean + * @see ResolvedTypeX#Character + * @see ResolvedTypeX#Byte + * @see ResolvedTypeX#Short + * @see ResolvedTypeX#Integer + * @see ResolvedTypeX#Long + * @see ResolvedTypeX#Float + * @see ResolvedTypeX#Double + * @see ResolvedTypeX#Void + */ + public boolean isPrimitive() { + return false; + } + + + /** + * Returns a java language string representation of this type. + */ + public String toString() { + return getName(); + } + + // ---- requires worlds + + /** + * Types may have pointcuts just as they have methods and fields. + */ + public ResolvedPointcutDefinition findPointcut(String name, World world) { + return world.findPointcut(this, name); + } + + /** + * Determines if variables of this type could be assigned values of another + * with lots of help. This is the same as isCoercableFrom, but java.lang.Object + * is convertable from and to all types. + * + * @param other the other type + * @param world the {@link World} in which the possible assignment should be checked. + * @return true iff variables of this type could be assigned values of other with possible conversion + */ + public final boolean isConvertableFrom(TypeX other, World world) { + if (this.equals(OBJECT) || other.equals(OBJECT)) return true; + return this.isCoerceableFrom(other, world); + } + + /** + * Determines if variables of this type could be assigned values of another + * without any conversion computation of any kind. For primitive types + * this means equality, and for reference types it means assignability. + * + * @param other the other type + * @param world the {@link World} in which the possible assignment should be checked. + * @return true iff variables of this type could be assigned values of other without any conversion computation + */ + public boolean needsNoConversionFrom(TypeX other, World world) { + // primitives override this method, so we know we're not primitive. + // So if the other is primitive, don't bother asking the world anything. + if (other.isPrimitive()) return false; + return world.needsNoConversionFrom(this, other); + } + + /** + * Determines if the variables of this type could be assigned values + * of another type without casting. This still allows for assignment conversion + * as per JLS 2ed 5.2. + * + * @param other the other type + * @param world the {@link World} in which the possible assignment should be checked. + * @return true iff variables of this type could be assigned values of other without casting + * @exception NullPointerException if other is null + */ + public boolean isAssignableFrom(TypeX other, World world) { + // primitives override this method, so we know we're not primitive. + // So if the other is primitive, don't bother asking the world anything. + if (other.isPrimitive()) return false; + return world.isAssignableFrom(this, other); + } + + /** + * Determines if values of another type could possibly be cast to + * this type. The rules followed are from JLS 2ed 5.5, "Casting Conversion". + * + * <p> This method should be commutative, i.e., for all TypeX a, b and all World w: + * + * <blockquote><pre> + * a.isCoerceableFrom(b, w) == b.isCoerceableFrom(a, w) + * </pre></blockquote> + * + * @param other the other type + * @param world the {@link World} in which the possible coersion should be checked. + * @return true iff values of other could possibly be cast to this type. + * @exception NullPointerException if other is null. + */ + public boolean isCoerceableFrom(TypeX other, World world) { + // primitives override this method, so we know we're not primitive. + // So if the other is primitive, don't bother asking the world anything. + if (other.isPrimitive()) return false; + return world.isCoerceableFrom(this, other); + } + + /** + * Determines if this represents an interface type. + * + * @param world the {@link World} in which we should check. + * @return true iff this represents an interface type. + */ + public final boolean isInterface(World world) { + return world.resolve(this).isInterface(); + } + + /** + * Determines if this represents a class type. + * + * @param world the {@link World} in which we should check. + * @return true iff this represents a class type. + */ + public final boolean isClass(World world) { + return world.resolve(this).isClass(); + } + + + /** + * Determines if this represents an aspect type. + * + * @param world the {@link World} in which we should check. + * @return true iff this represents an aspect type. + */ + public final boolean isAspect(World world) { + return world.resolve(this).isAspect(); + } + + + /** + * Returns a TypeX object representing the superclass of this type, or null. + * If this represents a java.lang.Object, a primitive type, or void, this + * method returns null. + * + * <p> + * This differs from {@link java.lang.class#getSuperclass()} in that + * this returns a TypeX object representing java.lang.Object for interfaces instead + * of returning null. + * + * @param world the {@link World} in which the lookup should be made. + * @return this type's superclass, or null if none exists. + */ + public TypeX getSuperclass(World world) { + return world.getSuperclass(this); + } + + /** + * Returns an array of TypeX objects representing the declared interfaces + * of this type. + * + * <p> + * If this object represents a class, the declared interfaces are those it + * implements. If this object represents an interface, the declared interfaces + * are those it extends. If this object represents a primitive, an empty + * array is returned. If this object represents an array, an array + * containing types for java.lang.Cloneable and java.io.Serializable is returned. + * + * @param world the {@link World} in which the lookup should be made. + * @return an iterator through the declared interfaces of this type. + */ + public TypeX[] getDeclaredInterfaces(World world) { + return world.getDeclaredInterfaces(this); + } + + /** + * Returns an iterator through TypeX objects representing all the direct + * supertypes of this type. That is, through the superclass, if any, and + * all declared interfaces. + * + * @param world the {@link World} in which the lookup should be made. + * @return an iterator through the direct supertypes of this type. + */ + public Iterator getDirectSupertypes(World world) { + return world.resolve(this).getDirectSupertypes(); + } + + /** + * Returns the modifiers for this type. + * + * See {@link java.lang.Class#getModifiers()} for a description + * of the weirdness of this methods on primitives and arrays. + * + * @param world the {@link World} in which the lookup is made. + * @return an int representing the modifiers for this type + * @see java.lang.reflect.Modifier + */ + public int getModifiers(World world) { + return world.getModifiers(this); + } + + /** + * Returns an array representing the declared fields of this object. This may include + * non-user-visible fields. + * This method returns an + * empty array if it represents an array type or a primitive type, so + * the implicit length field of arrays is just that, implicit. + * + * @param world the {@link World} in which the lookup is done. + * @return the array representing the declared fields of this type + */ + public ResolvedMember[] getDeclaredFields(World world) { + return world.getDeclaredFields(this); + } + + /** + * Returns an array representing the declared methods of this object. This includes + * constructors and the static initialzation method. This also includes all + * shadowMungers in an aspect. So it may include more than the user-visible methods. + * This method returns an + * empty array if it represents an array type or a primitive type. + * + * @param world the {@link World} in which the lookup is done. + * @return the array representing the declared methods of this type + */ + public ResolvedMember[] getDeclaredMethods(World world) { + return world.getDeclaredMethods(this); + } + + + /** + * Returns an array representing the declared pointcuts of this object. + * This method returns an + * empty array if it represents an array type or a primitive type. + * + * @param world the {@link World} in which the lookup is done. + * @return the array representing the declared pointcuts of this type + */ + public ResolvedMember[] getDeclaredPointcuts(World world) { + return world.getDeclaredPointcuts(this); + } + + /** + * Returns a resolved version of this type according to a particular world. + * + * @param world thie {@link World} within which to resolve. + * @return a resolved type representing this type in the appropriate world. + */ + public ResolvedTypeX resolve(World world) { + return world.resolve(this); + } + + // ---- fields + + public static final TypeX[] NONE = new TypeX[0]; + public static final TypeX OBJECT = forSignature("Ljava/lang/Object;"); + public static final TypeX OBJECTARRAY = forSignature("[Ljava/lang/Object;"); + public static final TypeX CLONEABLE = forSignature("Ljava/lang/Cloneable;"); + public static final TypeX SERIALIZABLE = forSignature("Ljava/io/Serializable;"); + public static final TypeX THROWABLE = forSignature("Ljava/lang/Throwable;"); + + // ---- helpers + + private static String signatureToName(String signature) { + switch (signature.charAt(0)) { + case 'B': return "byte"; + case 'C': return "char"; + case 'D': return "double"; + case 'F': return "float"; + case 'I': return "int"; + case 'J': return "long"; + case 'L': + return signature.substring(1, signature.length() - 1).replace('/', '.'); + case 'S': return "short"; + case 'V': return "void"; + case 'Z': return "boolean"; + case '[': + return signatureToName(signature.substring(1, signature.length())) + "[]"; + default: + throw new BCException("Bad type signature: " + signature); + } + } + + private static String nameToSignature(String name) { + if (name.equals("byte")) return "B"; + if (name.equals("char")) return "C"; + if (name.equals("double")) return "D"; + if (name.equals("float")) return "F"; + if (name.equals("int")) return "I"; + if (name.equals("long")) return "J"; + if (name.equals("short")) return "S"; + if (name.equals("boolean")) return "Z"; + if (name.equals("void")) return "V"; + if (name.endsWith("[]")) + return "[" + nameToSignature(name.substring(0, name.length() - 2)); + if (name.length() != 0) // lots more tests could be made here... + return "L" + name.replace('.', '/') + ";"; + else + throw new BCException("Bad type name: " + name); + } + + public void write(DataOutputStream s) throws IOException { + s.writeUTF(signature); + } + + public static TypeX read(DataInputStream s) throws IOException { + String sig = s.readUTF(); + if (sig.equals(MISSING_NAME)) { + return ResolvedTypeX.MISSING; + } else { + return TypeX.forSignature(sig); + } + } + + public static void write(TypeX[] types, DataOutputStream s) throws IOException { + int len = types.length; + s.writeShort(len); + for (int i=0; i < len; i++) { + types[i].write(s); + } + } + + public static TypeX[] readArray(DataInputStream s) throws IOException { + int len = s.readShort(); + TypeX[] types = new TypeX[len]; + for (int i=0; i < len; i++) { + types[i] = TypeX.read(s); + } + return types; + } + + + /** + * For debugging purposes + */ + public void dump(World world) { + if (isAspect(world)) System.out.print("aspect "); + else if (isInterface(world)) System.out.print("interface "); + else if (isClass(world)) System.out.print("class "); + + System.out.println(toString()); + dumpResolvedMembers("fields", getDeclaredFields(world)); + dumpResolvedMembers("methods", getDeclaredMethods(world)); + dumpResolvedMembers("pointcuts", getDeclaredPointcuts(world)); + } + + private void dumpResolvedMembers(String label, ResolvedMember[] l) { + final String indent = " "; + System.out.println(label); + if (l == null) { + System.out.println(indent + "null"); + return; + } + + for (int i=0, len=l.length; i < len; i++) { + System.out.println(indent + l[i]); + } + } + + // ---- + + public String getNameAsIdentifier() { + return getName().replace('.', '_'); + } + + public String getPackageNameAsIdentifier() { + String name = getName(); + int index = name.lastIndexOf('.'); + if (index == -1) { + return ""; + } else { + return name.substring(0, index).replace('.', '_'); + } + } + + public String getPackageName() { + String name = getName(); + int index = name.lastIndexOf('.'); + if (index == -1) { + return null; + } else { + return name.substring(0, index); + } + } + + public String getClassName() { + String name = getName(); + int index = name.lastIndexOf('.'); + if (index == -1) { + return name; + } else { + return name.substring(index+1); + } + } + + + + + + public static final String MISSING_NAME = "<missing>"; + +} + diff --git a/weaver/src/org/aspectj/weaver/WeaverStateKind.java b/weaver/src/org/aspectj/weaver/WeaverStateKind.java new file mode 100644 index 000000000..da3fd35f3 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/WeaverStateKind.java @@ -0,0 +1,47 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.io.*; + +import org.aspectj.util.TypeSafeEnum; + +public class WeaverStateKind extends TypeSafeEnum { + private WeaverStateKind(String name, int key) { + super(name, key); + } + + public static final WeaverStateKind read(DataInputStream s) throws IOException { + byte b = s.readByte(); + switch(b) { + case 0: return Untouched; + case 2: return Woven; + } + throw new RuntimeException("bad WeaverState.Kind: " + b); + } + + + public static final WeaverStateKind Untouched = new WeaverStateKind("Untouched", 0); + public static final WeaverStateKind Woven = new WeaverStateKind("Woven", 2); + + + public byte[] getBytes() { + return new byte[] { getKey(), }; + } + + public boolean isWoven() { + return this == Woven; + } + +} diff --git a/weaver/src/org/aspectj/weaver/World.java b/weaver/src/org/aspectj/weaver/World.java new file mode 100644 index 000000000..c12acf985 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/World.java @@ -0,0 +1,320 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.util.*; + +import org.aspectj.weaver.patterns.*; +import org.aspectj.weaver.patterns.Pointcut; +import org.aspectj.asm.StructureModel; +import org.aspectj.bridge.*; +import org.aspectj.bridge.IMessageHandler; + +public abstract class World { + protected IMessageHandler messageHandler = IMessageHandler.SYSTEM_ERR; + + protected Map typeMap = new HashMap(); // Signature to ResolvedType + + protected CrosscuttingMembersSet crosscuttingMembersSet = new CrosscuttingMembersSet(this); + + protected StructureModel model = null; + + protected Lint lint = new Lint(this); + + protected World() { + super(); + typeMap.put("B", ResolvedTypeX.BYTE); + typeMap.put("S", ResolvedTypeX.SHORT); + typeMap.put("I", ResolvedTypeX.INT); + typeMap.put("J", ResolvedTypeX.LONG); + typeMap.put("F", ResolvedTypeX.FLOAT); + typeMap.put("D", ResolvedTypeX.DOUBLE); + typeMap.put("C", ResolvedTypeX.CHAR); + typeMap.put("Z", ResolvedTypeX.BOOLEAN); + typeMap.put("V", ResolvedTypeX.VOID); + } + + public ResolvedTypeX[] resolve(TypeX[] types) { + int len = types.length; + ResolvedTypeX[] ret = new ResolvedTypeX[len]; + for (int i=0; i<len; i++) { + ret[i] = resolve(types[i]); + } + return ret; + } + + public ResolvedTypeX resolve(TypeX ty) { + return resolve(ty, false); + } + + public ResolvedTypeX resolve(TypeX ty, boolean allowMissing) { + //System.out.println("resolve: " + ty + " world " + typeMap.keySet()); + String signature = ty.getSignature(); + ResolvedTypeX ret = (ResolvedTypeX)typeMap.get(signature); + if (ret != null) return ret; + + if (ty.isArray()) { + ret = new ResolvedTypeX.Array(signature, this, resolve(ty.getComponentType(), allowMissing)); + } else { + ret = resolveObjectType(ty); + if (!allowMissing && ret == ResolvedTypeX.MISSING) { + //Thread.currentThread().dumpStack(); + MessageUtil.error(messageHandler, "can't find type " + ty.getName()); + // + " on classpath " + classPath); + } + } + //System.out.println("ret: " + ret); + typeMap.put(signature, ret); + return ret; + } + + //XXX helper method might be bad + public ResolvedTypeX resolve(String name) { + return resolve(TypeX.forName(name)); + } + protected abstract ResolvedTypeX resolveObjectType(TypeX ty); + + protected final boolean isCoerceableFrom(TypeX type, TypeX other) { + return resolve(type).isCoerceableFrom(other); + } + + protected final boolean isAssignableFrom(TypeX type, TypeX other) { + return resolve(type).isAssignableFrom(other); + } + + public boolean needsNoConversionFrom(TypeX type, TypeX other) { + return resolve(type).needsNoConversionFrom(other); + } + + protected final boolean isInterface(TypeX type) { + return resolve(type).isInterface(); + } + + protected final ResolvedTypeX getSuperclass(TypeX type) { + return resolve(type).getSuperclass(); + } + + protected final TypeX[] getDeclaredInterfaces(TypeX type) { + return resolve(type).getDeclaredInterfaces(); + } + + protected final int getModifiers(TypeX type) { + return resolve(type).getModifiers(); + } + + protected final ResolvedMember[] getDeclaredFields(TypeX type) { + return resolve(type).getDeclaredFields(); + } + + protected final ResolvedMember[] getDeclaredMethods(TypeX type) { + return resolve(type).getDeclaredMethods(); + } + + protected final ResolvedMember[] getDeclaredPointcuts(TypeX type) { + return resolve(type).getDeclaredPointcuts(); + } + + // ---- members + + + // XXX should we worry about dealing with context and looking up access? + public ResolvedMember resolve(Member member) { + ResolvedTypeX declaring = member.getDeclaringType().resolve(this); + 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); + } + + protected int getModifiers(Member member) { + return resolve(member).getModifiers(); + } + + protected String[] getParameterNames(Member member) { + return resolve(member).getParameterNames(); + } + + protected TypeX[] getExceptions(Member member) { + return resolve(member).getExceptions(); + } + + // ---- pointcuts + + public ResolvedPointcutDefinition findPointcut(TypeX typeX, String name) { + throw new RuntimeException("not implemented yet"); + } + + /** + * Get the shadow mungers of this world. + * + * @return a list of {@link IShadowMunger}s appropriate for this world. + */ + //public abstract List getShadowMungers(); + + // ---- empty world + + public static final World EMPTY = new World() { + public List getShadowMungers() { return Collections.EMPTY_LIST; } + public ResolvedTypeX resolveObjectType(TypeX ty) { + return ResolvedTypeX.MISSING; + } + public Advice concreteAdvice(AdviceKind kind, Pointcut p, Member m, int extraMods, + int start, int end, ISourceContext context) { + throw new RuntimeException("unimplemented"); + } + public ConcreteTypeMunger concreteTypeMunger(ResolvedTypeMunger munger, ResolvedTypeX aspectType) { + throw new RuntimeException("unimplemented"); + } + }; + + + public abstract Advice concreteAdvice( + AdviceKind kind, + Pointcut p, + Member signature, + int extraParameterFlags, + int start, int end, ISourceContext context); + + public final Advice concreteAdvice( + AdviceKind kind, + Pointcut p, + Member signature, + int extraParameterFlags, + IHasSourceLocation loc) + { + return concreteAdvice(kind, p, signature, extraParameterFlags, loc.getStart(), loc.getEnd(), loc.getSourceContext()); + } + + + + public ConcreteTypeMunger makeCflowStackFieldAdder(ResolvedMember cflowField) { + throw new RuntimeException("unimplemented"); + } + + public abstract ConcreteTypeMunger concreteTypeMunger(ResolvedTypeMunger munger, ResolvedTypeX aspectType); + + /** + * 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) { + this.messageHandler = messageHandler; + } + +// public void addDeclare(ResolvedTypeX onType, Declare declare, boolean forWeaving) { +// // this is not extensible, oh well +// if (declare instanceof DeclareErrorOrWarning) { +// ShadowMunger m = new Checker((DeclareErrorOrWarning)declare); +// onType.addShadowMunger(m); +// } else if (declare instanceof DeclareDominates) { +// declareDominates.add(declare); +// } else if (declare instanceof DeclareParents) { +// declareParents.add(declare); +// } else if (declare instanceof DeclareSoft) { +// DeclareSoft d = (DeclareSoft)declare; +// declareSoft.add(d); +// if (forWeaving) { +// ShadowMunger m = Advice.makeSoftener(this, d.getPointcut().concretize(onType, 0), d.getException()); +// onType.addShadowMunger(m); +// } +// } else { +// throw new RuntimeException("unimplemented"); +// } +// } + + + /** + * Same signature as org.aspectj.util.PartialOrder.PartialComparable.compareTo + */ + public int compareByDominates(ResolvedTypeX aspect1, ResolvedTypeX aspect2) { + //System.out.println("dom compare: " + aspect1 + " with " + aspect2); + //System.out.println(crosscuttingMembersSet.getDeclareDominates()); + + //??? We probably want to cache this result. This is order N where N is the + //??? number of dominates declares in the whole system. + //??? This method can be called a large number of times. + int order = 0; + for (Iterator i = crosscuttingMembersSet.getDeclareDominates().iterator(); i.hasNext(); ) { + DeclareDominates d = (DeclareDominates)i.next(); + int thisOrder = d.compare(aspect1, aspect2); + //System.out.println("comparing: " + thisOrder + ": " + d); + if (thisOrder != 0) { + if (order != 0 && order != thisOrder) { + throw new BCException("conflicting dominates orders"); + } else { + order = thisOrder; + } + } + } + + + return order; + } + + + public int comparePrecedence(ResolvedTypeX aspect1, ResolvedTypeX aspect2) { + //System.err.println("compare precedence " + aspect1 + ", " + aspect2); + if (aspect1.equals(aspect2)) return 0; + + int ret = compareByDominates(aspect1, aspect2); + if (ret != 0) return ret; + + if (aspect1.isAssignableFrom(aspect2)) return -1; + else if (aspect2.isAssignableFrom(aspect1)) return +1; + + return 0; + } + + + + + public List getDeclareParents() { + return crosscuttingMembersSet.getDeclareParents(); + } + + public List getDeclareSoft() { + return crosscuttingMembersSet.getDeclareSofts(); + } + + public CrosscuttingMembersSet getCrosscuttingMembersSet() { + return crosscuttingMembersSet; + } + + public StructureModel getModel() { + return model; + } + + public void setModel(StructureModel model) { + this.model = model; + } + + public Lint getLint() { + return lint; + } + + public void setLint(Lint lint) { + this.lint = lint; + } + +} diff --git a/weaver/src/org/aspectj/weaver/XlintDefault.properties b/weaver/src/org/aspectj/weaver/XlintDefault.properties new file mode 100644 index 000000000..eb5944dfa --- /dev/null +++ b/weaver/src/org/aspectj/weaver/XlintDefault.properties @@ -0,0 +1,4 @@ +invalidAbsoluteTypeName = warning +invalidWildcardTypeName = ignore + +unresolvableMember = warning
\ No newline at end of file diff --git a/weaver/src/org/aspectj/weaver/ast/ASTNode.java b/weaver/src/org/aspectj/weaver/ast/ASTNode.java new file mode 100644 index 000000000..261605b10 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/ASTNode.java @@ -0,0 +1,22 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +public abstract class ASTNode { + + public ASTNode() { + super(); + } + +} diff --git a/weaver/src/org/aspectj/weaver/ast/And.java b/weaver/src/org/aspectj/weaver/ast/And.java new file mode 100644 index 000000000..1dc00be7f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/And.java @@ -0,0 +1,51 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + + +public class And extends Test { + Test left, right; + + public And(Test left, Test right) { + super(); + this.left = left; + this.right = right; + } + + public void accept(ITestVisitor v) { + v.visit(this); + } + + public String toString() { + return "(" + left + " && " + right + ")"; + } + + public boolean equals(Object other) { + if (other instanceof And) { + And o = (And) other; + return o.left.equals(left) && o.right.equals(right); + } else { + return false; + } + } + + public Test getLeft() { + return left; + } + + public Test getRight() { + return right; + } + +} diff --git a/weaver/src/org/aspectj/weaver/ast/Call.java b/weaver/src/org/aspectj/weaver/ast/Call.java new file mode 100644 index 000000000..b521c1199 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/Call.java @@ -0,0 +1,41 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +import org.aspectj.weaver.Member; + +public class Call extends Test { + // assert m.return value is boolean + private final Member method; + private final Expr[] args; + + public Call(Member m, Expr[] args) { + super(); + this.method = m; + this.args = args; + } + + public void accept(ITestVisitor v) { + v.visit(this); + } + + public Expr[] getArgs() { + return args; + } + + public Member getMethod() { + return method; + } + +} diff --git a/weaver/src/org/aspectj/weaver/ast/CallExpr.java b/weaver/src/org/aspectj/weaver/ast/CallExpr.java new file mode 100644 index 000000000..19fe73b6b --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/CallExpr.java @@ -0,0 +1,48 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.Member; + +public class CallExpr extends Expr { + // assert m.return value is boolean + private final Member method; + private final Expr[] args; + private final ResolvedTypeX returnType; // yes, stored in method as well, but that one isn't resolved + + public CallExpr(Member m, Expr[] args, ResolvedTypeX returnType) { + super(); + this.method = m; + this.args = args; + this.returnType = returnType; + } + + public void accept(IExprVisitor v) { + v.visit(this); + } + + public Expr[] getArgs() { + return args; + } + + public Member getMethod() { + return method; + } + + public ResolvedTypeX getType() { + return returnType; + } + +} diff --git a/weaver/src/org/aspectj/weaver/ast/Expr.java b/weaver/src/org/aspectj/weaver/ast/Expr.java new file mode 100644 index 000000000..372c88114 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/Expr.java @@ -0,0 +1,36 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +import org.aspectj.weaver.*; + +public abstract class Expr extends ASTNode { + + public Expr() { + super(); + } + + public static final Expr[] NONE = new Expr[0]; + + public abstract void accept(IExprVisitor v); + public abstract ResolvedTypeX getType(); + + public static FieldGet makeFieldGet(Member myField, ResolvedTypeX inAspect) { + return new FieldGet(myField, inAspect); + } + public static Expr makeCallExpr(Member member, Expr[] exprs, ResolvedTypeX returnType) { + return new CallExpr(member, exprs, returnType); + } + +} diff --git a/weaver/src/org/aspectj/weaver/ast/FieldGet.java b/weaver/src/org/aspectj/weaver/ast/FieldGet.java new file mode 100644 index 000000000..89253b103 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/FieldGet.java @@ -0,0 +1,48 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +import org.aspectj.weaver.*; + + +public class FieldGet extends Expr { + Member field; + ResolvedTypeX resolvedType; + + public FieldGet(Member field, ResolvedTypeX resolvedType) { + super(); + this.field = field; + this.resolvedType = resolvedType; + } + + public ResolvedTypeX getType() { + return resolvedType; + } + + public String toString() { + return "(FieldGet " + field + ")"; + } + + public void accept(IExprVisitor v) { + v.visit(this); + } + public Member getField() { + return field; + } + + public ResolvedTypeX getResolvedType() { + return resolvedType; + } + +} diff --git a/weaver/src/org/aspectj/weaver/ast/FieldGetCall.java b/weaver/src/org/aspectj/weaver/ast/FieldGetCall.java new file mode 100644 index 000000000..e3d19938b --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/FieldGetCall.java @@ -0,0 +1,47 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +import org.aspectj.weaver.Member; + +public class FieldGetCall extends Test { + // assert m.return value is boolean + private final Member field; + private final Member method; + private final Expr[] args; + + public FieldGetCall(Member f, Member m, Expr[] args) { + super(); + this.field = f; + this.method = m; + this.args = args; + } + + public void accept(ITestVisitor v) { + v.visit(this); + } + + public Expr[] getArgs() { + return args; + } + + public Member getMethod() { + return method; + } + + public Member getField() { + return field; + } + +} diff --git a/weaver/src/org/aspectj/weaver/ast/IExprVisitor.java b/weaver/src/org/aspectj/weaver/ast/IExprVisitor.java new file mode 100644 index 000000000..38b53ffb3 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/IExprVisitor.java @@ -0,0 +1,23 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + + +public interface IExprVisitor { + + void visit(Var i); + void visit(FieldGet fieldGet); + void visit(CallExpr callExpr); + +} diff --git a/weaver/src/org/aspectj/weaver/ast/ITestVisitor.java b/weaver/src/org/aspectj/weaver/ast/ITestVisitor.java new file mode 100644 index 000000000..1787ea62e --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/ITestVisitor.java @@ -0,0 +1,27 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + + +public interface ITestVisitor { + + void visit(And e); + void visit(Instanceof i); + void visit(Not not); + void visit(Or or); + void visit(Literal literal); + void visit(Call call); + void visit(FieldGetCall fieldGetCall); + +} diff --git a/weaver/src/org/aspectj/weaver/ast/Instanceof.java b/weaver/src/org/aspectj/weaver/ast/Instanceof.java new file mode 100644 index 000000000..ad2d85ecb --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/Instanceof.java @@ -0,0 +1,52 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +import org.aspectj.weaver.TypeX; + +public class Instanceof extends Test { + Var var; + TypeX type; + + public Instanceof(Var left, TypeX right) { + super(); + this.var = left; + this.type = right; + } + + public void accept(ITestVisitor v) { + v.visit(this); + } + + public String toString() { + return "(" + var + " instanceof " + type + ")"; + } + + public boolean equals(Object other) { + if (other instanceof Instanceof) { + Instanceof o = (Instanceof) other; + return o.var.equals(var) && o.type.equals(type); + } else { + return false; + } + } + + public Var getVar() { + return var; + } + + public TypeX getType() { + return type; + } +} diff --git a/weaver/src/org/aspectj/weaver/ast/Literal.java b/weaver/src/org/aspectj/weaver/ast/Literal.java new file mode 100644 index 000000000..ed7388fa2 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/Literal.java @@ -0,0 +1,39 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + + +public class Literal extends Test { + + boolean noTest; + boolean val; + + private Literal(boolean val, boolean noTest) { + super(); + this.val = val; + this.noTest = noTest; + } + + public void accept(ITestVisitor v) { + v.visit(this); + } + + public static final Literal TRUE = new Literal(true, false); + public static final Literal FALSE = new Literal(false, false); +// public static final Literal NO_TEST = new Literal(false, true); + + public String toString() { + return noTest ? "NO_TEST" : val ? "TRUE" : "FALSE"; + } +} diff --git a/weaver/src/org/aspectj/weaver/ast/Not.java b/weaver/src/org/aspectj/weaver/ast/Not.java new file mode 100644 index 000000000..7333e8a87 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/Not.java @@ -0,0 +1,45 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + + +public class Not extends Test { + Test body; + + public Not(Test left) { + super(); + this.body = left; + } + + public void accept(ITestVisitor v) { + v.visit(this); + } + + public Test getBody() { + return body; + } + + public String toString() { + return "!" + body; + } + + public boolean equals(Object other) { + if (other instanceof Not) { + Not o = (Not) other; + return o.body.equals(body); + } else { + return false; + } + } +} diff --git a/weaver/src/org/aspectj/weaver/ast/Or.java b/weaver/src/org/aspectj/weaver/ast/Or.java new file mode 100644 index 000000000..0f9575dbb --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/Or.java @@ -0,0 +1,49 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +public class Or extends Test { + Test left, right; + + public Or(Test left, Test right) { + super(); + this.left = left; + this.right = right; + } + + public void accept(ITestVisitor v) { + v.visit(this); + } + + public String toString() { + return "(" + left + " || " + right + ")"; + } + + public boolean equals(Object other) { + if (other instanceof Or) { + Or o = (Or) other; + return o.left.equals(left) && o.right.equals(right); + } else { + return false; + } + } + + public Test getLeft() { + return left; + } + + public Test getRight() { + return right; + } +} diff --git a/weaver/src/org/aspectj/weaver/ast/Test.java b/weaver/src/org/aspectj/weaver/ast/Test.java new file mode 100644 index 000000000..d7385a547 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/Test.java @@ -0,0 +1,91 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; + +public abstract class Test extends ASTNode { + + public Test() { + super(); + } + + public abstract void accept(ITestVisitor v); + + public static Test makeAnd(Test a, Test b) { +// if (a == Literal.NO_TEST) return b; +// if (b == Literal.NO_TEST) return a; + if (a == Literal.TRUE) { + if (b == Literal.TRUE) { + return a; + } else { + return b; + } + } else if (b == Literal.TRUE) { + return a; + } else if (a == Literal.FALSE || b == Literal.FALSE) { + return Literal.FALSE; + } else { + return new And(a, b); + } + } + + public static Test makeOr(Test a, Test b) { +// if (a == Literal.NO_TEST) return a; +// if (b == Literal.NO_TEST) return b; + if (a == Literal.FALSE) { + return b; + } else if (b == Literal.FALSE) { + return a; + } else if (a == Literal.TRUE || b == Literal.TRUE) { + return Literal.TRUE; + } else { + return new Or(a, b); + } + } + + public static Test makeNot(Test a) { + if (a instanceof Not) { + return ((Not) a).getBody(); + } else if (a == Literal.TRUE) { + return Literal.FALSE; + } else if (a == Literal.FALSE) { + return Literal.TRUE; +// } else if (a == Literal.NO_TEST) { +// return a; + } else { + return new Not(a); + } + } + + // uses our special rules that anything matches object + public static Test makeInstanceof(Var v, ResolvedTypeX ty) { + if (ty.equals(ResolvedTypeX.OBJECT)) return Literal.TRUE; + + Test e; + if (ty.isAssignableFrom(v.getType())) e = Literal.TRUE; + else if (! ty.isCoerceableFrom(v.getType())) e = Literal.FALSE; + else e = new Instanceof(v, ty); + return e; + } + + public static Test makeCall(Member m, Expr[] args) { + return new Call(m, args); + } + public static Test makeFieldGetCall(Member f, Member m, Expr[] args) { + return new FieldGetCall(f, m, args); + } + +} diff --git a/weaver/src/org/aspectj/weaver/ast/Var.java b/weaver/src/org/aspectj/weaver/ast/Var.java new file mode 100644 index 000000000..52246f3c6 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/ast/Var.java @@ -0,0 +1,38 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.ast; + +import org.aspectj.weaver.*; + + +public class Var extends Expr { + ResolvedTypeX type; + + public Var(ResolvedTypeX type) { + super(); + this.type = type; + } + + public ResolvedTypeX getType() { + return type; + } + + public String toString() { + return "(Var " + type + ")"; + } + + public void accept(IExprVisitor v) { + v.visit(this); + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java b/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java new file mode 100644 index 000000000..b3a42edf3 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelAdvice.java @@ -0,0 +1,312 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.weaver.patterns.*; + +/** + * Advice implemented for bcel. + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public class BcelAdvice extends Advice { + private Test pointcutTest; + private ExposedState exposedState; + + public BcelAdvice(AdviceKind kind, Pointcut pointcut, Member signature, + int extraArgumentFlags, + int start, int end, ISourceContext sourceContext, ResolvedTypeX concreteAspect) + { + super(kind, pointcut, signature, extraArgumentFlags, start, end, sourceContext); + this.concreteAspect = concreteAspect; + } + + // ---- implementations of ShadowMunger's methods + + public void specializeOn(Shadow shadow) { + if (getKind() == AdviceKind.Around) { + ((BcelShadow)shadow).initializeForAroundClosure(); + } + + //XXX this case is just here for supporting lazy test code + if (getKind() == null) { + exposedState = new ExposedState(0); + return; + } + if (getKind().isPerEntry()) { + exposedState = new ExposedState(0); + } else if (getKind().isCflow()) { + exposedState = new ExposedState(nFreeVars); + } else if (getSignature() != null) { + exposedState = new ExposedState(getSignature()); + } else { + exposedState = new ExposedState(0); + return; //XXX this case is just here for supporting lazy test code + } + pointcutTest = getPointcut().findResidue(shadow, exposedState); + + // make sure thisJoinPoint parameters are initialized + if ((extraParameterFlags & ThisJoinPoint) != 0) { + ((BcelShadow)shadow).getThisJoinPointVar(); + } + + if ((extraParameterFlags & ThisJoinPointStaticPart) != 0) { + ((BcelShadow)shadow).getThisJoinPointStaticPartVar(); + } + + if ((extraParameterFlags & ThisEnclosingJoinPointStaticPart) != 0) { + ((BcelShadow)shadow).getThisEnclosingJoinPointStaticPartVar(); + } + } + + public void implementOn(Shadow s) { + BcelShadow shadow = (BcelShadow) s; + if (getKind() == AdviceKind.Before) { + shadow.weaveBefore(this); + } else if (getKind() == AdviceKind.AfterReturning) { + shadow.weaveAfterReturning(this); + } else if (getKind() == AdviceKind.AfterThrowing) { + TypeX catchType = + hasExtraParameter() + ? getExtraParameterType() + : TypeX.THROWABLE; + shadow.weaveAfterThrowing(this, catchType); + } else if (getKind() == AdviceKind.After) { + shadow.weaveAfter(this); + } else if (getKind() == AdviceKind.Around) { + shadow.weaveAroundClosure(this, hasDynamicTests()); + } else if (getKind() == AdviceKind.InterInitializer) { + shadow.weaveAfterReturning(this); + } else if (getKind().isCflow()) { + shadow.weaveCflowEntry(this, getSignature()); + } else if (getKind() == AdviceKind.PerThisEntry) { + shadow.weavePerObjectEntry(this, (BcelVar)shadow.getThisVar()); + } else if (getKind() == AdviceKind.PerTargetEntry) { + shadow.weavePerObjectEntry(this, (BcelVar)shadow.getTargetVar()); + } else if (getKind() == AdviceKind.Softener) { + shadow.weaveSoftener(this, ((ExactTypePattern)exceptionType).getType()); + } else { + throw new BCException("unimplemented kind: " + getKind()); + } + } + + // ---- implementations + + // only call me after prepare has been called + public boolean hasDynamicTests() { +// if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) { +// TypeX extraParameterType = getExtraParameterType(); +// if (! extraParameterType.equals(TypeX.OBJECT) +// && ! extraParameterType.isPrimitive()) +// return true; +// } + + + return pointcutTest != null && + !(pointcutTest == Literal.TRUE);// || pointcutTest == Literal.NO_TEST); + } + + + /** + * get the instruction list for the really simple version of this advice. + * Is broken apart + * for other advice, but if you want it in one block, this is the method to call. + * + * @param s The shadow around which these instructions will eventually live. + * @param extraArgVar The var that will hold the return value or thrown exception + * for afterX advice + * @param ifNoAdvice The instructionHandle to jump to if the dynamic + * tests for this munger fails. + */ + InstructionList getAdviceInstructions( + BcelShadow s, + BcelVar extraArgVar, + InstructionHandle ifNoAdvice) + { + BcelShadow shadow = (BcelShadow) s; + InstructionFactory fact = shadow.getFactory(); + BcelWorld world = shadow.getWorld(); + + InstructionList il = new InstructionList(); + + // we test to see if we have the right kind of thing... + // after throwing does this just by the exception mechanism. + if (hasExtraParameter() && getKind() == AdviceKind.AfterReturning) { + TypeX extraParameterType = getExtraParameterType(); + if (! extraParameterType.equals(TypeX.OBJECT) + && ! extraParameterType.isPrimitive()) { + il.append( + BcelRenderer.renderTest( + fact, + world, + Test.makeInstanceof( + extraArgVar, getExtraParameterType().resolve(world)), + null, + ifNoAdvice, + null)); + } + } + il.append(getAdviceArgSetup(shadow, extraArgVar, null)); + il.append(getNonTestAdviceInstructions(shadow)); + + InstructionHandle ifYesAdvice = il.getStart(); + il.insert(getTestInstructions(shadow, ifYesAdvice, ifNoAdvice, ifYesAdvice)); + return il; + } + + public InstructionList getAdviceArgSetup( + BcelShadow shadow, + BcelVar extraVar, + InstructionList closureInstantiation) + { + InstructionFactory fact = shadow.getFactory(); + BcelWorld world = shadow.getWorld(); + InstructionList il = new InstructionList(); + +// if (targetAspectField != null) { +// il.append(fact.createFieldAccess( +// targetAspectField.getDeclaringType().getName(), +// targetAspectField.getName(), +// BcelWorld.makeBcelType(targetAspectField.getType()), +// Constants.GETSTATIC)); +// } +// + //System.err.println("BcelAdvice: " + exposedState); + + + if (exposedState.getAspectInstance() != null) { + il.append( + BcelRenderer.renderExpr(fact, world, exposedState.getAspectInstance())); + } + for (int i = 0, len = exposedState.size(); i < len; i++) { + BcelVar v = (BcelVar) exposedState.get(i); + if (v == null) continue; + TypeX desiredTy = getSignature().getParameterTypes()[i]; + v.appendLoadAndConvert(il, fact, desiredTy.resolve(world)); + } + + + if (getKind() == AdviceKind.Around) { + il.append(closureInstantiation); + } else if (hasExtraParameter()) { + extraVar.appendLoadAndConvert( + il, + fact, + getExtraParameterType().resolve(world)); + } + + // handle thisJoinPoint parameters + if ((extraParameterFlags & ThisJoinPoint) != 0) { + shadow.getThisJoinPointBcelVar().appendLoad(il, fact); + } + + if ((extraParameterFlags & ThisJoinPointStaticPart) != 0) { + shadow.getThisJoinPointStaticPartBcelVar().appendLoad(il, fact); + } + + if ((extraParameterFlags & ThisEnclosingJoinPointStaticPart) != 0) { + shadow.getThisEnclosingJoinPointStaticPartBcelVar().appendLoad(il, fact); + } + + + return il; + } + + public InstructionList getNonTestAdviceInstructions(BcelShadow shadow) { + return new InstructionList( + Utility.createInvoke(shadow.getFactory(), shadow.getWorld(), getSignature())); + } + + public InstructionList getTestInstructions( + BcelShadow shadow, + InstructionHandle sk, + InstructionHandle fk, + InstructionHandle next) + { + //System.err.println("test: " + pointcutTest); + return BcelRenderer.renderTest( + shadow.getFactory(), + shadow.getWorld(), + pointcutTest, + sk, + fk, + next); + } + + public int compareTo(Object other) { + if (!(other instanceof BcelAdvice)) return 0; + BcelAdvice o = (BcelAdvice)other; + + //System.err.println("compareTo: " + this + ", " + o); + if (kind.getPrecedence() != o.kind.getPrecedence()) { + if (kind.getPrecedence() > o.kind.getPrecedence()) return +1; + else return -1; + } + + if (kind.isCflow()) { + if (this.innerCflowEntries.contains(o)) return -1; + else if (o.innerCflowEntries.contains(this)) return +1; + else return 0; + } + + + if (kind.isPerEntry() || kind == AdviceKind.Softener) { + return 0; + } + + //System.out.println("compare: " + this + " with " + other); + World world = concreteAspect.getWorld(); + + int ret = + concreteAspect.getWorld().compareByDominates( + concreteAspect, + o.concreteAspect); + if (ret != 0) return ret; + + + ResolvedTypeX declaringAspect = getDeclaringAspect().resolve(world); + ResolvedTypeX o_declaringAspect = o.getDeclaringAspect().resolve(world); + + + if (declaringAspect == o_declaringAspect) { + if (kind.isAfter() || o.kind.isAfter()) { + return this.lexicalPosition < o.lexicalPosition ? -1: +1; + } else { + return this.lexicalPosition < o.lexicalPosition ? +1: -1; + } + } else if (declaringAspect.isAssignableFrom(o_declaringAspect)) { + return -1; + } else if (o_declaringAspect.isAssignableFrom(declaringAspect)) { + return +1; + } else { + return 0; + } + } + + public BcelVar[] getExposedStateAsBcelVars() { + //System.out.println("vars: " + Arrays.asList(exposedState.vars)); + if (exposedState == null) return BcelVar.NONE; + int len = exposedState.vars.length; + BcelVar[] ret = new BcelVar[len]; + for (int i=0; i < len; i++) { + ret[i] = (BcelVar)exposedState.vars[i]; + } + return ret; //(BcelVar[]) exposedState.vars; + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelAttributes.java b/weaver/src/org/aspectj/weaver/bcel/BcelAttributes.java new file mode 100644 index 000000000..840d7b04b --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelAttributes.java @@ -0,0 +1,52 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.util.*; + +import org.apache.bcel.classfile.*; +import org.apache.bcel.generic.ConstantPoolGen; +import org.aspectj.weaver.*; +import org.aspectj.weaver.AjAttribute; + + +// this is a class o' static methods for reading attributes. It's pretty much a bridge from +// bcel to AjAttribute. +class BcelAttributes { + + public static List readAjAttributes(Attribute[] as, ISourceContext context) { + List l = new ArrayList(); + for (int i = as.length - 1; i >= 0; i--) { + Attribute a = as[i]; + if (a instanceof Unknown) { + Unknown u = (Unknown) a; + String name = u.getName(); + if (name.startsWith(AjAttribute.AttributePrefix)) { + l.add(AjAttribute.read(name, u.getBytes(), context)); + } + } + } + return l; + } + + public static Attribute bcelAttribute(AjAttribute a, ConstantPoolGen pool) { + int nameIndex = pool.addUtf8(a.getNameString()); + byte[] bytes = a.getBytes(); + int length = bytes.length; + + return new Unknown(nameIndex, length, bytes, pool.getConstantPool()); + + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelCflowAccessVar.java b/weaver/src/org/aspectj/weaver/bcel/BcelCflowAccessVar.java new file mode 100644 index 000000000..a04bcc292 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelCflowAccessVar.java @@ -0,0 +1,92 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; +import org.aspectj.weaver.ast.Var; + +/** + * XXX Erik and I need to discuss this hierarchy. Having FieldRef + * extend Var is convenient, but hopefully there's a better design. + * + * This is always a static reference. + */ +public class BcelCflowAccessVar extends BcelVar { + + + private Member stackField; + private int index; + + /** + * @param type The type to convert to from Object + * @param stackField the member containing the CFLOW_STACK_TYPE + * @param index yeah yeah + */ + public BcelCflowAccessVar(ResolvedTypeX type, Member stackField, int index) { + super(type, 0); + this.stackField = stackField; + this.index = index; + } + + public String toString() { + return "BcelCflowAccessVar(" + getType() + " " + stackField + "." + index + ")"; + } + + public Instruction createLoad(InstructionFactory fact) { + throw new RuntimeException("unimplemented"); + } + public Instruction createStore(InstructionFactory fact) { + throw new RuntimeException("unimplemented"); + } + + public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { + throw new RuntimeException("unimplemented"); + } + + public void appendLoad(InstructionList il, InstructionFactory fact) { + il.append(createLoadInstructions(getType(), fact)); + } + + public InstructionList createLoadInstructions(ResolvedTypeX toType, InstructionFactory fact) { + InstructionList il = new InstructionList(); + + il.append(Utility.createGet(fact, stackField)); + il.append(Utility.createConstant(fact, index)); + il.append( + fact.createInvoke( + NameMangler.CFLOW_STACK_TYPE, "get", + Type.OBJECT, new Type[] { Type.INT }, + Constants.INVOKEVIRTUAL)); + il.append(Utility.createConversion(fact, Type.OBJECT, BcelWorld.makeBcelType(toType))); + + return il; + + } + + public void appendLoadAndConvert( + InstructionList il, + InstructionFactory fact, + ResolvedTypeX toType) { + il.append(createLoadInstructions(toType, fact)); + + } + + public void insertLoad(InstructionList il, InstructionFactory fact) { + il.insert(createLoadInstructions(getType(), fact)); + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelCflowStackFieldAdder.java b/weaver/src/org/aspectj/weaver/bcel/BcelCflowStackFieldAdder.java new file mode 100644 index 000000000..c398cec63 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelCflowStackFieldAdder.java @@ -0,0 +1,72 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.generic.*; +import org.apache.bcel.generic.FieldGen; +import org.aspectj.weaver.*; + +public class BcelCflowStackFieldAdder extends BcelTypeMunger { + private ResolvedMember cflowStackField; + public BcelCflowStackFieldAdder(ResolvedMember cflowStackField) { + super(null, null); + this.cflowStackField = cflowStackField; + } + + public boolean munge(BcelClassWeaver weaver) { + LazyClassGen gen = weaver.getLazyClassGen(); + if (!gen.getType().equals(cflowStackField.getDeclaringType())) return false; + + Field f = new FieldGen(cflowStackField.getModifiers(), + BcelWorld.makeBcelType(cflowStackField.getReturnType()), + cflowStackField.getName(), + gen.getConstantPoolGen()).getField(); + gen.addField(f); + + LazyMethodGen clinit = gen.getStaticInitializer(); + InstructionList setup = new InstructionList(); + InstructionFactory fact = gen.getFactory(); + + setup.append(fact.createNew(new ObjectType(NameMangler.CFLOW_STACK_TYPE))); + setup.append(fact.createDup(1)); + setup.append(fact.createInvoke( + NameMangler.CFLOW_STACK_TYPE, + "<init>", + Type.VOID, + new Type[0], + Constants.INVOKESPECIAL)); + + + setup.append(Utility.createSet(fact, cflowStackField)); + clinit.getBody().insert(setup); + + return true; + } + + + public ResolvedMember getMatchingSyntheticMember(Member member) { + return null; + } + + public ResolvedMember getSignature() { + return cflowStackField; + } + + public boolean matches(ResolvedTypeX onType) { + return onType.equals(cflowStackField.getDeclaringType()); + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java new file mode 100644 index 000000000..74d2ace0f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelClassWeaver.java @@ -0,0 +1,889 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.util.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.util.PartialOrder; +import org.aspectj.weaver.*; + +class BcelClassWeaver implements IClassWeaver { + + /** + * This is called from {@link BcelWeaver} to perform the per-class weaving process. + */ + public static boolean weave( + BcelWorld world, + LazyClassGen clazz, + List shadowMungers, + List typeMungers) + { + boolean b = new BcelClassWeaver(world, clazz, shadowMungers, typeMungers).weave(); + //clazz.print(); + return b; + } + + // -------------------------------------------- + + private final LazyClassGen clazz; + private final List shadowMungers; + private final List typeMungers; + + private final BcelObjectType ty; // alias of clazz.getType() + private final BcelWorld world; // alias of ty.getWorld() + private final ConstantPoolGen cpg; // alias of clazz.getConstantPoolGen() + private final InstructionFactory fact; // alias of clazz.getFactory(); + + + private final List addedLazyMethodGens = new ArrayList(); + private final Set addedDispatchTargets = new HashSet(); + + + private List addedSuperInitializersAsList = null; // List<IfaceInitList> + private final Map addedSuperInitializers = new HashMap(); // Interface -> IfaceInitList + private List addedThisInitializers = new ArrayList(); // List<NewFieldMunger> + private List addedClassInitializers = new ArrayList(); // List<NewFieldMunger> + + private BcelShadow clinitShadow = null; + + + + /** + * This holds the initialization and pre-initialization shadows for this class + * that were actually matched by mungers (if no match, then we don't even create the + * shadows really). + */ + private final List initializationShadows = new ArrayList(1); + + private BcelClassWeaver( + BcelWorld world, + LazyClassGen clazz, + List shadowMungers, + List typeMungers) + { + super(); + // assert world == clazz.getType().getWorld() + this.world = world; + this.clazz = clazz; + this.shadowMungers = shadowMungers; + this.typeMungers = typeMungers; + this.ty = clazz.getType(); + this.cpg = clazz.getConstantPoolGen(); + this.fact = clazz.getFactory(); + initializeSuperInitializerMap(ty); + } + + // -------------------------------------------- + + private void initializeSuperInitializerMap(ResolvedTypeX child) { + ResolvedTypeX[] superInterfaces = child.getDeclaredInterfaces(); + for (int i=0, len=superInterfaces.length; i < len; i++) { + if (ty.isTopmostImplementor(superInterfaces[i])) { + if (addSuperInitializer(superInterfaces[i])) { + initializeSuperInitializerMap(superInterfaces[i]); + } + } + } + } + + private boolean addSuperInitializer(ResolvedTypeX onType) { + IfaceInitList l = (IfaceInitList) addedSuperInitializers.get(onType); + if (l != null) return false; + l = new IfaceInitList(onType); + addedSuperInitializers.put(onType, l); + return true; + } + + public void addInitializer(ConcreteTypeMunger cm) { + NewFieldTypeMunger m = (NewFieldTypeMunger) cm.getMunger(); + ResolvedTypeX onType = m.getSignature().getDeclaringType().resolve(world); + if (m.getSignature().isStatic()) { + addedClassInitializers.add(cm); + } else { + if (onType == ty) { + addedThisInitializers.add(cm); + } else { + IfaceInitList l = (IfaceInitList) addedSuperInitializers.get(onType); + l.list.add(cm); + } + } + } + + private static class IfaceInitList implements PartialOrder.PartialComparable { + final ResolvedTypeX onType; + List list = new ArrayList(); + IfaceInitList(ResolvedTypeX onType) { + this.onType = onType; + } + + public int compareTo(Object other) { + IfaceInitList o = (IfaceInitList)other; + if (onType.isAssignableFrom(o.onType)) return +1; + else if (o.onType.isAssignableFrom(onType)) return -1; + else return 0; + } + + public int fallbackCompareTo(Object other) { + return 0; + } + } + + // XXX this is being called, but the result doesn't seem to be being used + public boolean addDispatchTarget(ResolvedMember m) { + return addedDispatchTargets.add(m); + } + + public void addLazyMethodGen(LazyMethodGen gen) { + addedLazyMethodGens.add(gen); + } + + public void addOrReplaceLazyMethodGen(LazyMethodGen mg) { + if (alreadyDefined(clazz, mg)) return; + + for (Iterator i = addedLazyMethodGens.iterator(); i.hasNext(); ) { + LazyMethodGen existing = (LazyMethodGen)i.next(); + if (signaturesMatch(mg, existing)) { + if (existing.definingType == null) { + // this means existing was introduced on the class itself + return; + } else if (mg.definingType.isAssignableFrom(existing.definingType)) { + // existing is mg's subtype and dominates mg + return; + } else if (existing.definingType.isAssignableFrom(mg.definingType)) { + // mg is existing's subtype and dominates existing + i.remove(); + addedLazyMethodGens.add(mg); + return; + } else { + throw new BCException("conflict between: " + mg + " and " + existing); + } + } + } + addedLazyMethodGens.add(mg); + } + + private boolean alreadyDefined(LazyClassGen clazz, LazyMethodGen mg) { + for (Iterator i = clazz.getMethodGens().iterator(); i.hasNext(); ) { + if (signaturesMatch(mg, (LazyMethodGen)i.next())) { + return true; + } + } + return false; + } + + private boolean signaturesMatch(LazyMethodGen mg, LazyMethodGen existing) { + return mg.getName().equals(existing.getName()) && + mg.getSignature().equals(existing.getSignature()); + } + + // ---- + + public boolean weave() { + if (clazz.getWeaverState().isWoven()) { + throw new RuntimeException("already woven: " + clazz); + } + + boolean isChanged = false; + + // we want to "touch" all aspects + if (clazz.getType().isAspect()) isChanged = true; + + + // start by munging all typeMungers + for (Iterator i = typeMungers.iterator(); i.hasNext(); ) { + BcelTypeMunger munger = (BcelTypeMunger)i.next(); + isChanged |= munger.munge(this); + } + + // XXX do major sort of stuff + // sort according to: Major: type hierarchy + // within each list: dominates + // don't forget to sort addedThisInitialiers according to dominates + addedSuperInitializersAsList = new ArrayList(addedSuperInitializers.values()); + addedSuperInitializersAsList = PartialOrder.sort(addedSuperInitializersAsList); + if (addedSuperInitializersAsList == null) { + throw new BCException("circularity in inter-types"); + } + + // this will create a static initializer if there isn't one + // this is in just as bad taste as NOPs + LazyMethodGen staticInit = clazz.getStaticInitializer(); + staticInit.getBody().insert(genInitInstructions(addedClassInitializers, true)); + + + // now go through each method, and match against each method. This + // sets up each method's {@link LazyMethodGen#matchedShadows} field, + // and it also possibly adds to {@link #initializationShadows}. + List methodGens = new ArrayList(clazz.getMethodGens()); + for (Iterator i = methodGens.iterator(); i.hasNext();) { + LazyMethodGen mg = (LazyMethodGen)i.next(); + if (! mg.hasBody()) continue; + isChanged |= match(mg); + } + if (! isChanged) return false; + + // now we weave all but the initialization shadows + for (Iterator i = methodGens.iterator(); i.hasNext();) { + LazyMethodGen mg = (LazyMethodGen)i.next(); + if (! mg.hasBody()) continue; + implement(mg); + } + + + // if we matched any initialization shadows, we inline and weave + if (! initializationShadows.isEmpty()) { + inlineSelfConstructors(methodGens); + positionAndImplement(initializationShadows); + } + + + // finally, if we changed, we add in the introduced methods. + if (isChanged) { + clazz.setWeaverState(WeaverStateKind.Woven); + weaveInAddedMethods(); + } + + return isChanged; + } + + + private void inlineSelfConstructors(List methodGens) { + for (Iterator i = methodGens.iterator(); i.hasNext();) { + LazyMethodGen mg = (LazyMethodGen) i.next(); + if (! mg.getName().equals("<init>")) continue; + InstructionHandle ih = findSuperOrThisCall(mg); + if (ih != null && isThisCall(ih)) { + LazyMethodGen donor = getCalledMethod(ih); + inlineMethod(donor, mg, ih); + } + } + } + + private void positionAndImplement(List initializationShadows) { + for (Iterator i = initializationShadows.iterator(); i.hasNext(); ) { + BcelShadow s = (BcelShadow) i.next(); + positionInitializationShadow(s); + //s.getEnclosingMethod().print(); + s.implement(); + } + } + + private void positionInitializationShadow(BcelShadow s) { + LazyMethodGen mg = s.getEnclosingMethod(); + InstructionHandle call = findSuperOrThisCall(mg); + InstructionList body = mg.getBody(); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow((BcelShadow) s); + if (s.getKind() == Shadow.PreInitialization) { + // XXX assert first instruction is an ALOAD_0. + // a pre shadow goes from AFTER the first instruction (which we believe to + // be an ALOAD_0) to just before the call to super + r.associateWithTargets( + Range.genStart(body, body.getStart().getNext()), + Range.genEnd(body, call.getPrev())); + } else { + // assert s.getKind() == Shadow.Initialization + r.associateWithTargets( + Range.genStart(body, call.getNext()), + Range.genEnd(body)); + } + } + + private boolean isThisCall(InstructionHandle ih) { + INVOKESPECIAL inst = (INVOKESPECIAL) ih.getInstruction(); + return inst.getClassName(cpg).equals(clazz.getName()); + } + + + /** inline a particular call in bytecode. + * + * @param donor the method we want to inline + * @param recipient the method containing the call we want to inline + * @param call the instructionHandle in recipient's body holding the call we want to + * inline. + */ + public static void inlineMethod( + LazyMethodGen donor, + LazyMethodGen recipient, + InstructionHandle call) + { + // assert recipient.contains(call) + + /* Implementation notes: + * + * We allocate two slots for every tempvar so we don't screw up + * longs and doubles which may share space. This could be conservatively avoided + * (no reference to a long/double instruction, don't do it) or packed later. + * Right now we don't bother to pack. + * + * Allocate a new var for each formal param of the inlined. Fill with stack + * contents. Then copy the inlined instructions in with the appropriate remap + * table. Any framelocs used by locals in inlined are reallocated to top of + * frame, + */ + final InstructionFactory fact = recipient.getEnclosingClass().getFactory(); + + IntMap frameEnv = new IntMap(); + + // this also sets up the initial environment + InstructionList argumentStores = + genArgumentStores(donor, recipient, frameEnv, fact); + + InstructionList inlineInstructions = + genInlineInstructions(donor, recipient, frameEnv, fact); + + inlineInstructions.insert(argumentStores); + + recipient.getBody().append(call, inlineInstructions); + Utility.deleteInstruction(call, recipient); + } + + /** generate the instructions to be inlined. + * + * @param donor the method from which we will copy (and adjust frame and jumps) + * instructions. + * @param recipient the method the instructions will go into. Used to get the frame + * size so we can allocate new frame locations for locals in donor. + * @param frameEnv an environment to map from donor frame to recipient frame, + * initially populated with argument locations. + * @param fact an instruction factory for recipient + */ + private static InstructionList genInlineInstructions( + LazyMethodGen donor, + LazyMethodGen recipient, + IntMap frameEnv, + InstructionFactory fact) + { + InstructionList footer = new InstructionList(); + InstructionHandle end = footer.append(fact.NOP); + + InstructionList ret = new InstructionList(); + InstructionList sourceList = donor.getBody(); + + Map srcToDest = new HashMap(); + ConstantPoolGen donorCpg = donor.getEnclosingClass().getConstantPoolGen(); + ConstantPoolGen recipientCpg = recipient.getEnclosingClass().getConstantPoolGen(); + + boolean isAcrossClass = donorCpg != recipientCpg; + + // first pass: copy the instructions directly, populate the srcToDest map, + // fix frame instructions + for (InstructionHandle src = sourceList.getStart(); + src != null; + src = src.getNext()) + { + Instruction fresh = src.getInstruction().copy(); + InstructionHandle dest; + if (fresh instanceof CPInstruction) { + // need to reset index to go to new constant pool. This is totally + // a computation leak... we're testing this LOTS of times. Sigh. + if (isAcrossClass) { + CPInstruction cpi = (CPInstruction) fresh; + cpi.setIndex(recipientCpg.addConstant(donorCpg.getConstant(cpi.getIndex()), donorCpg)); + } + } + if (src.getInstruction() == Range.RANGEINSTRUCTION) { + dest = ret.append(Range.RANGEINSTRUCTION); + } else if (fresh instanceof ReturnInstruction) { + dest = ret.append(fact.createBranchInstruction(Constants.GOTO, end)); + } else if (fresh instanceof BranchInstruction) { + dest = ret.append((BranchInstruction) fresh); + } else if ( + fresh instanceof LocalVariableInstruction || fresh instanceof RET) { + IndexedInstruction indexed = (IndexedInstruction) fresh; + int oldIndex = indexed.getIndex(); + int freshIndex; + if (!frameEnv.hasKey(oldIndex)) { + freshIndex = recipient.allocateLocal(2); + frameEnv.put(oldIndex, freshIndex); + } else { + freshIndex = frameEnv.get(oldIndex); + } + indexed.setIndex(freshIndex); + dest = ret.append(fresh); + } else { + dest = ret.append(fresh); + } + srcToDest.put(src, dest); + } + + // second pass: retarget branch instructions, copy ranges and tags + Map tagMap = new HashMap(); + Map shadowMap = new HashMap(); + for (InstructionHandle dest = ret.getStart(), src = sourceList.getStart(); + dest != null; + dest = dest.getNext(), src = src.getNext()) { + Instruction inst = dest.getInstruction(); + + // retarget branches + if (inst instanceof BranchInstruction) { + BranchInstruction branch = (BranchInstruction) inst; + InstructionHandle oldTarget = branch.getTarget(); + InstructionHandle newTarget = + (InstructionHandle) srcToDest.get(oldTarget); + if (newTarget == null) { + // assert this is a GOTO + // this was a return instruction we previously replaced + } else { + branch.setTarget(newTarget); + if (branch instanceof Select) { + Select select = (Select) branch; + InstructionHandle[] oldTargets = select.getTargets(); + for (int k = oldTargets.length - 1; k >= 0; k--) { + select.setTarget( + k, + (InstructionHandle) srcToDest.get(oldTargets[k])); + } + } + } + } + + //copy over tags and range attributes + InstructionTargeter[] srcTargeters = src.getTargeters(); + if (srcTargeters != null) { + for (int j = srcTargeters.length - 1; j >= 0; j--) { + InstructionTargeter old = srcTargeters[j]; + if (old instanceof Tag) { + Tag oldTag = (Tag) old; + Tag fresh = (Tag) tagMap.get(oldTag); + if (fresh == null) { + fresh = oldTag.copy(); + tagMap.put(oldTag, fresh); + } + dest.addTargeter(fresh); + } else if (old instanceof ExceptionRange) { + ExceptionRange er = (ExceptionRange) old; + if (er.getStart() == src) { + ExceptionRange freshEr = + new ExceptionRange( + recipient.getBody(), + er.getCatchType(), + er.getPriority()); + freshEr.associateWithTargets( + dest, + (InstructionHandle)srcToDest.get(er.getEnd()), + (InstructionHandle)srcToDest.get(er.getHandler())); + } + } else if (old instanceof ShadowRange) { + ShadowRange oldRange = (ShadowRange) old; + if (oldRange.getStart() == src) { + BcelShadow oldShadow = oldRange.getShadow(); + BcelShadow freshEnclosing = + oldShadow.getEnclosingShadow() == null + ? null + : (BcelShadow) shadowMap.get(oldShadow.getEnclosingShadow()); + BcelShadow freshShadow = + oldShadow.copyInto(recipient, freshEnclosing); + ShadowRange freshRange = new ShadowRange(recipient.getBody()); + freshRange.associateWithShadow(freshShadow); + freshRange.associateWithTargets( + dest, + (InstructionHandle) srcToDest.get(oldRange.getEnd())); + shadowMap.put(oldRange, freshRange); + //recipient.matchedShadows.add(freshShadow); + } + } + } + } + } + ret.append(footer); + return ret; + } + + /** generate the argument stores in preparation for inlining. + * + * @param donor the method we will inline from. Used to get the signature. + * @param recipient the method we will inline into. Used to get the frame size + * so we can allocate fresh locations. + * @param frameEnv an empty environment we populate with a map from donor frame to + * recipient frame. + * @param fact an instruction factory for recipient + */ + private static InstructionList genArgumentStores( + LazyMethodGen donor, + LazyMethodGen recipient, + IntMap frameEnv, + InstructionFactory fact) + { + InstructionList ret = new InstructionList(); + + int donorFramePos = 0; + + // writing ret back to front because we're popping. + if (! donor.isStatic()) { + int targetSlot = recipient.allocateLocal(Type.OBJECT); + ret.insert(fact.createStore(Type.OBJECT, targetSlot)); + frameEnv.put(donorFramePos, targetSlot); + donorFramePos += 1; + } + Type[] argTypes = donor.getArgumentTypes(); + for (int i = 0, len = argTypes.length; i < len; i++) { + Type argType = argTypes[i]; + int argSlot = recipient.allocateLocal(argType); + ret.insert(fact.createStore(argType, argSlot)); + frameEnv.put(donorFramePos, argSlot); + donorFramePos += argType.getSize(); + } + return ret; + } + + /** get a called method: Assumes the called method is in this class, + * and the reference to it is exact (a la INVOKESPECIAL). + * + * @param ih The InvokeInstruction instructionHandle pointing to the called method. + */ + private LazyMethodGen getCalledMethod( + InstructionHandle ih) + { + InvokeInstruction inst = (InvokeInstruction) ih.getInstruction(); + + String methodName = inst.getName(cpg); + String signature = inst.getSignature(cpg); + + return clazz.getLazyMethodGen(methodName, signature); + } + + private void weaveInAddedMethods() { + Collections.sort(addedLazyMethodGens, + new Comparator() { + public int compare(Object a, Object b) { + LazyMethodGen aa = (LazyMethodGen) a; + LazyMethodGen bb = (LazyMethodGen) b; + int i = aa.getName().compareTo(bb.getName()); + if (i != 0) return i; + return aa.getSignature().compareTo(bb.getSignature()); + } + } + ); + + for (Iterator i = addedLazyMethodGens.iterator(); i.hasNext(); ) { + clazz.addMethodGen((LazyMethodGen)i.next()); + } + } + + void addPerSingletonField(Member field) { + ObjectType aspectType = (ObjectType) BcelWorld.makeBcelType(field.getReturnType()); + String aspectName = field.getReturnType().getName(); + + LazyMethodGen clinit = clazz.getStaticInitializer(); + InstructionList setup = new InstructionList(); + InstructionFactory fact = clazz.getFactory(); + + setup.append(fact.createNew(aspectType)); + setup.append(fact.createDup(1)); + setup.append(fact.createInvoke( + aspectName, + "<init>", + Type.VOID, + new Type[0], + Constants.INVOKESPECIAL)); + setup.append(fact.createFieldAccess(aspectName, field.getName(), aspectType, Constants.PUTSTATIC)); + clinit.getBody().insert(setup); + } + + /** + * Returns null if this is not a Java constructor, and then we won't + * weave into it at all + */ + private InstructionHandle findSuperOrThisCall(LazyMethodGen mg) { + int depth = 1; + InstructionHandle start = mg.getBody().getStart(); + while (true) { + if (start == null) return null; + + Instruction inst = start.getInstruction(); + if (inst instanceof INVOKESPECIAL + && ((INVOKESPECIAL) inst).getName(cpg).equals("<init>")) { + depth--; + if (depth == 0) return start; + } else if (inst instanceof NEW) { + depth++; + } + start = start.getNext(); + } + } + + // ---- + + private boolean match(LazyMethodGen mg) { + BcelShadow enclosingShadow; + + List shadowAccumulator = new ArrayList(); + // we want to match ajsynthetic constructors... + if (mg.getName().equals("<init>")) { + // XXX the enclosing join point is wrong for things before ignoreMe. + InstructionHandle superOrThisCall = findSuperOrThisCall(mg); + + // we don't walk bodies of things where it's a wrong constructor thingie + if (superOrThisCall == null) return false; + + enclosingShadow = BcelShadow.makeConstructorExecution(world, mg, superOrThisCall); + + // walk the body + if (shouldWeaveBody(mg)) { //!mg.isAjSynthetic()) { + for (InstructionHandle h = mg.getBody().getStart(); + h != null; + h = h.getNext()) { + if (h == superOrThisCall) + continue; + match(mg, h, enclosingShadow, shadowAccumulator); + } + match(enclosingShadow, shadowAccumulator); + } + + // XXX we don't do pre-inits of interfaces + + // now add interface inits and cexecs + if (superOrThisCall != null && ! isThisCall(superOrThisCall)) { + InstructionHandle curr = enclosingShadow.getRange().getStart(); + for (Iterator i = addedSuperInitializersAsList.iterator(); i.hasNext(); ) { + IfaceInitList l = (IfaceInitList) i.next(); + // generate the cexec jp + Member ifaceInitSig = AjcMemberMaker.interfaceConstructor(l.onType); + BcelShadow cexecShadow = + BcelShadow.makeIfaceConstructorExecution( + world, + mg, + curr, + ifaceInitSig); + if (match(cexecShadow, shadowAccumulator)) { + cexecShadow.getRange().getBody().append(cexecShadow.getRange().getStart(), fact.NOP); + } + // generate the init jp around it + BcelShadow initShadow = + BcelShadow.makeIfaceInitialization( + world, + mg, + cexecShadow, + ifaceInitSig); + match(initShadow, shadowAccumulator); + // insert code in place + InstructionList inits = genInitInstructions(l.list, false); + initShadow.getRange().insert(inits, Range.InsideAfter); + } + + // now we add our initialization code + InstructionList inits = genInitInstructions(addedThisInitializers, false); + enclosingShadow.getRange().insert(inits, Range.OutsideBefore); + } + + // actually, you only need to inline the self constructors that are + // in a particular group (partition the constructors into groups where members + // call or are called only by those in the group). Then only inline + // constructors + // in groups where at least one initialization jp matched. Future work. + boolean addedInitialization = + match( + BcelShadow.makeUnfinishedInitialization(world, mg), + initializationShadows); + addedInitialization |= + match( + BcelShadow.makeUnfinishedPreinitialization(world, mg), + initializationShadows); + mg.matchedShadows = shadowAccumulator; + return addedInitialization || !shadowAccumulator.isEmpty(); + } else if (!shouldWeaveBody(mg)) { //.isAjSynthetic()) { + return false; + } else { + if (mg.getName().equals("<clinit>")) { + clinitShadow = enclosingShadow = BcelShadow.makeStaticInitialization(world, mg); + //System.err.println(enclosingShadow); + } else if (mg.isAdviceMethod()) { + enclosingShadow = BcelShadow.makeAdviceExecution(world, mg); + } else { + AjAttribute.EffectiveSignatureAttribute effective = mg.getEffectiveSignature(); + if (effective == null) { + enclosingShadow = BcelShadow.makeMethodExecution(world, mg); + } else if (effective.isWeaveBody()) { + enclosingShadow = BcelShadow.makeShadowForMethod(world, mg, effective.getShadowKind(), effective.getEffectiveSignature()); + } else { + return false; + } + } + + for (InstructionHandle h = mg.getBody().getStart(); + h != null; + h = h.getNext()) { + match(mg, h, enclosingShadow, shadowAccumulator); + } + match(enclosingShadow, shadowAccumulator); + mg.matchedShadows = shadowAccumulator; + return !shadowAccumulator.isEmpty(); + } + } + + private boolean shouldWeaveBody(LazyMethodGen mg) { + if (mg.isAjSynthetic()) return mg.getName().equals("<clinit>"); + AjAttribute.EffectiveSignatureAttribute a = mg.getEffectiveSignature(); + if (a != null) return a.isWeaveBody(); + return true; + } + + + /** + * first sorts the mungers, then gens the initializers in the right order + */ + private InstructionList genInitInstructions(List list, boolean isStatic) { + list = PartialOrder.sort(list); + if (list == null) { + throw new BCException("circularity in inter-types"); + } + + InstructionList ret = new InstructionList(); + + for (Iterator i = list.iterator(); i.hasNext();) { + ConcreteTypeMunger cmunger = (ConcreteTypeMunger) i.next(); + NewFieldTypeMunger munger = (NewFieldTypeMunger) cmunger.getMunger(); + ResolvedMember initMethod = munger.getInitMethod(cmunger.getAspectType()); + if (!isStatic) ret.append(fact.ALOAD_0); + ret.append(Utility.createInvoke(fact, world, initMethod)); + } + return ret; + } + + + private void match( + LazyMethodGen mg, + InstructionHandle ih, + BcelShadow enclosingShadow, + List shadowAccumulator) + { + Instruction i = ih.getInstruction(); + if (i instanceof FieldInstruction) { + FieldInstruction fi = (FieldInstruction) i; + if (i instanceof PUTFIELD || i instanceof PUTSTATIC) { + match( + BcelShadow.makeFieldSet(world, mg, ih, enclosingShadow), + shadowAccumulator); + } else { + match( + BcelShadow.makeFieldGet(world, mg, ih, enclosingShadow), + shadowAccumulator); + } + } else if (i instanceof InvokeInstruction) { + InvokeInstruction ii = (InvokeInstruction) i; + if (ii.getMethodName(clazz.getConstantPoolGen()).equals("<init>")) { + match( + BcelShadow.makeConstructorCall(world, mg, ih, enclosingShadow), + shadowAccumulator); + } else if (ii instanceof INVOKESPECIAL) { + String onTypeName = ii.getClassName(cpg); + if (onTypeName.equals(mg.getEnclosingClass().getName())) { + // we are private + matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator); + } else { + // we are a super call, and this is not a join point in AspectJ-1.{0,1} + } + } else { + matchInvokeInstruction(mg, ih, ii, enclosingShadow, shadowAccumulator); + } + } + // performance optimization... we only actually care about ASTORE instructions, + // since that's what every javac type thing ever uses to start a handler, but for + // now we'll do this for everybody. + if (Range.isRangeHandle(ih)) return; + InstructionTargeter[] targeters = ih.getTargeters(); + if (targeters != null) { + for (int j = 0; j < targeters.length; j++) { + InstructionTargeter t = targeters[j]; + if (t instanceof ExceptionRange) { + // assert t.getHandler() == ih + ExceptionRange er = (ExceptionRange) t; + if (er.getCatchType() == null) continue; + match( + BcelShadow.makeExceptionHandler( + world, + er, + mg, ih, enclosingShadow), + shadowAccumulator); + } + } + } + } + + private void matchInvokeInstruction(LazyMethodGen mg, + InstructionHandle ih, + InvokeInstruction invoke, + BcelShadow enclosingShadow, + List shadowAccumulator) + { + String methodName = invoke.getName(cpg); + if (methodName.startsWith(NameMangler.PREFIX)) { + Member method = + world.makeMethodSignature(clazz, invoke); + ResolvedMember declaredSig = method.resolve(world); + if (declaredSig == null) return; + AjAttribute.EffectiveSignatureAttribute effectiveSig = declaredSig.getEffectiveSignature(); + if (effectiveSig == null) return; + //System.err.println("call to inter-type member: " + effectiveSig); + if (effectiveSig.isWeaveBody()) return; + + match(BcelShadow.makeShadowForMethodCall(world, mg, ih, enclosingShadow, + effectiveSig.getShadowKind(), effectiveSig.getEffectiveSignature()), + shadowAccumulator); + } else { + match( + BcelShadow.makeMethodCall(world, mg, ih, enclosingShadow), + shadowAccumulator); + } + } + + private boolean match(BcelShadow shadow, List shadowAccumulator) { + //System.err.println("match: " + shadow); + boolean isMatched = false; + for (Iterator i = shadowMungers.iterator(); i.hasNext(); ) { + ShadowMunger munger = (ShadowMunger)i.next(); + if (munger.match(shadow, world)) { + shadow.addMunger(munger); + isMatched = true; + } + } + if (isMatched) shadowAccumulator.add(shadow); + return isMatched; + } + + // ---- + + private void implement(LazyMethodGen mg) { + List shadows = mg.matchedShadows; + if (shadows == null) return; + // We depend on a partial order such that inner shadows are earlier on the list + // than outer shadows. That's fine. This order is preserved if: + + // A preceeds B iff B.getStart() is LATER THAN A.getStart(). + + for (Iterator i = shadows.iterator(); i.hasNext(); ) { + BcelShadow shadow = (BcelShadow)i.next(); + shadow.implement(); + } + mg.matchedShadows = null; + } + + // ---- + + public LazyClassGen getLazyClassGen() { + return clazz; + } + + public List getShadowMungers() { + return shadowMungers; + } + + public BcelWorld getWorld() { + return world; + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelField.java b/weaver/src/org/aspectj/weaver/bcel/BcelField.java new file mode 100644 index 000000000..aa9d4cec6 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelField.java @@ -0,0 +1,60 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.util.*; + +import org.apache.bcel.classfile.Field; +import org.aspectj.weaver.*; + +final class BcelField extends ResolvedMember { + + private Field field; + private boolean isAjSynthetic; + + BcelField(BcelObjectType declaringType, Field field) { + super( + FIELD, + declaringType, + field.getAccessFlags(), + field.getName(), + field.getSignature()); + this.field = field; + unpackAttributes(declaringType.getWorld()); + checkedExceptions = TypeX.NONE; + } + + // ---- + + BcelObjectType getBcelDeclaringType() { + return (BcelObjectType) getDeclaringType(); // I want covariant return types. + } + + private void unpackAttributes(World world) { + List as = BcelAttributes.readAjAttributes(field.getAttributes(), getSourceContext(world)); + for (Iterator iter = as.iterator(); iter.hasNext();) { + AjAttribute a = (AjAttribute) iter.next(); + if (a instanceof AjAttribute.AjSynthetic) { + isAjSynthetic = true; + } else { + throw new BCException("weird field attribute " + a); + } + } + isAjSynthetic = false; + } + + public boolean isAjSynthetic() { + return isAjSynthetic; // || getName().startsWith(NameMangler.PREFIX); + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelFieldRef.java b/weaver/src/org/aspectj/weaver/bcel/BcelFieldRef.java new file mode 100644 index 000000000..6896f0ba4 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelFieldRef.java @@ -0,0 +1,103 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; +import org.aspectj.weaver.ast.Var; + +/** + * XXX Erik and I need to discuss this hierarchy. Having FieldRef + * extend Var is convenient, but hopefully there's a better design. + * + * This is always a static reference. + */ +public class BcelFieldRef extends BcelVar { + + private String className, fieldName; + + public BcelFieldRef(ResolvedTypeX type, String className, String fieldName) { + super(type, 0); + this.className = className; + this.fieldName = fieldName; + } + + public String toString() { + return "BcelFieldRef(" + getType() + " " + className + "." + fieldName + ")"; + } + + //public int getSlot() { return slot; } + + public Instruction createLoad(InstructionFactory fact) { + return fact.createFieldAccess(className, fieldName, + BcelWorld.makeBcelType(getType()), Constants.GETSTATIC); + } + public Instruction createStore(InstructionFactory fact) { + return fact.createFieldAccess(className, fieldName, + BcelWorld.makeBcelType(getType()), Constants.PUTSTATIC); + } + + public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { + throw new RuntimeException("unimplemented"); + } + + // this is an array var +// void appendConvertableArrayLoad( +// InstructionList il, +// InstructionFactory fact, +// int index, +// ResolvedTypeX convertTo) +// { +// ResolvedTypeX convertFromType = getType().getResolvedComponentType(); +// appendLoad(il, fact); +// il.append(Utility.createConstant(fact, index)); +// il.append(fact.createArrayLoad(BcelWorld.makeBcelType(convertFromType))); +// Utility.appendConversion(il, fact, convertFromType, convertTo); +// } +// +// void appendConvertableArrayStore( +// InstructionList il, +// InstructionFactory fact, +// int index, +// BcelFieldRef storee) +// { +// ResolvedTypeX convertToType = getType().getResolvedComponentType(); +// appendLoad(il, fact); +// il.append(Utility.createConstant(fact, index)); +// storee.appendLoad(il, fact); +// Utility.appendConversion(il, fact, storee.getType(), convertToType); +// il.append(fact.createArrayStore(BcelWorld.makeBcelType(convertToType))); +// } +// +// InstructionList createConvertableArrayStore( +// InstructionFactory fact, +// int index, +// BcelFieldRef storee) +// { +// InstructionList il = new InstructionList(); +// appendConvertableArrayStore(il, fact, index, storee); +// return il; +// } +// InstructionList createConvertableArrayLoad( +// InstructionFactory fact, +// int index, +// ResolvedTypeX convertTo) +// { +// InstructionList il = new InstructionList(); +// appendConvertableArrayLoad(il, fact, index, convertTo); +// return il; +// } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java b/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java new file mode 100644 index 000000000..c43ae2241 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelMethod.java @@ -0,0 +1,107 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.lang.reflect.Modifier; +import java.util.*; + +import org.apache.bcel.classfile.*; +import org.aspectj.weaver.*; + +final class BcelMethod extends ResolvedMember { + + private Method method; + private boolean isAjSynthetic; + private ShadowMunger associatedShadowMunger; + private AjAttribute.EffectiveSignatureAttribute effectiveSignature; + + BcelMethod(BcelObjectType declaringType, Method method) { + super( + method.getName().equals("<init>") ? CONSTRUCTOR : METHOD, + declaringType, + declaringType.isInterface() + ? method.getAccessFlags() | Modifier.INTERFACE + : method.getAccessFlags(), + method.getName(), + method.getSignature()); + this.method = method; + unpackAjAttributes(declaringType.getWorld()); + unpackJavaAttributes(); + } + + // ---- + + BcelObjectType getBcelDeclaringType() { + return (BcelObjectType) getDeclaringType(); // I want covariant return types. + } + + private void unpackJavaAttributes() { + ExceptionTable exnTable = method.getExceptionTable(); + checkedExceptions = (exnTable == null) + ? TypeX.NONE + : TypeX.forNames(exnTable.getExceptionNames()); + + LocalVariableTable varTable = method.getLocalVariableTable(); + int len = getArity(); + if (varTable == null) { + this.parameterNames = Utility.makeArgNames(len); + } else { + TypeX[] paramTypes = getParameterTypes(); + String[] paramNames = new String[len]; + int index = isStatic() ? 0 : 1; + for (int i = 0; i < len; i++) { + LocalVariable lv = varTable.getLocalVariable(index); + if (lv == null) { + paramNames[i] = "arg" + i; + } else { + paramNames[i] = lv.getName(); + } + index += paramTypes[i].getSize(); + } + this.parameterNames = paramNames; + } + } + + private void unpackAjAttributes(World world) { + List as = BcelAttributes.readAjAttributes(method.getAttributes(), getSourceContext(world)); + //System.out.println("unpack: " + this + ", " + as); + for (Iterator iter = as.iterator(); iter.hasNext();) { + AjAttribute a = (AjAttribute) iter.next(); + if (a instanceof AjAttribute.AdviceAttribute) { + associatedShadowMunger = ((AjAttribute.AdviceAttribute)a).reify(this, world); + return; + } else if (a instanceof AjAttribute.AjSynthetic) { + isAjSynthetic = true; + } else if (a instanceof AjAttribute.EffectiveSignatureAttribute) { + //System.out.println("found effective: " + this); + effectiveSignature = (AjAttribute.EffectiveSignatureAttribute)a; + } else { + throw new BCException("weird method attribute " + a); + } + } + associatedShadowMunger = null; + } + + public boolean isAjSynthetic() { + return isAjSynthetic; // || getName().startsWith(NameMangler.PREFIX); + } + + public ShadowMunger getAssociatedShadowMunger() { + return associatedShadowMunger; + } + + public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() { + return effectiveSignature; + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java new file mode 100644 index 000000000..303e12561 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelObjectType.java @@ -0,0 +1,236 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.PrintStream; +import java.util.*; + +import org.apache.bcel.classfile.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.patterns.*; +import org.aspectj.weaver.patterns.PerClause; + +// ??? exposed for testing +public class BcelObjectType extends ResolvedTypeX.Name { + private JavaClass javaClass; + private boolean isObject = false; // set upon construction + private LazyClassGen lazyClassGen = null; // set lazily if it's an aspect + + // lazy, for no particular reason I can discern + private ResolvedTypeX[] interfaces = null; + private ResolvedTypeX superClass = null; + private ResolvedMember[] fields = null; + private ResolvedMember[] methods = null; + + // strangely non-lazy + private ResolvedPointcutDefinition[] pointcuts = null; + private PerClause perClause = null; + private WeaverStateKind weaverState = null; + private List typeMungers = Collections.EMPTY_LIST; + private List declares = Collections.EMPTY_LIST; + private ResolvedMember[] privilegedAccess = null; + + + public Collection getTypeMungers() { + return typeMungers; + } + + + public Collection getDeclares() { + return declares; + } + + public Collection getPrivilegedAccesses() { + if (privilegedAccess == null) return Collections.EMPTY_LIST; + return Arrays.asList(privilegedAccess); + } + + + // IMPORTANT! THIS DOESN'T do real work on the java class, just stores it away. + BcelObjectType(String signature, World world, JavaClass javaClass) { + super(signature, world); + this.javaClass = javaClass; + + sourceContext = new BcelSourceContext(this); + + // this should only ever be java.lang.Object which is + // the only class in Java-1.4 with no superclasses + isObject = (javaClass.getSuperclassNameIndex() == 0); + unpackAspectAttributes(); + } + + public int getModifiers() { + return javaClass.getAccessFlags(); + } + + public ResolvedTypeX getSuperclass() { + if (isObject) return null; + if (superClass == null) { + superClass = world.resolve(TypeX.forName(javaClass.getSuperclassName())); + } + return superClass; + } + + public ResolvedTypeX[] getDeclaredInterfaces() { + if (interfaces == null) { + String[] ifaceNames = javaClass.getInterfaceNames(); + interfaces = new ResolvedTypeX[ifaceNames.length]; + for (int i = 0, len = ifaceNames.length; i < len; i++) { + interfaces[i] = world.resolve(TypeX.forName(ifaceNames[i])); + } + } + return interfaces; + } + + public ResolvedMember[] getDeclaredMethods() { + if (methods == null) { + Method[] ms = javaClass.getMethods(); + ResolvedMember[] ret = new ResolvedMember[ms.length]; + for (int i = ms.length - 1; i >= 0; i--) { + ret[i] = new BcelMethod(this, ms[i]); + } + methods = ret; + } + return methods; + } + + public ResolvedMember[] getDeclaredFields() { + if (fields == null) { + Field[] fs = javaClass.getFields(); + ResolvedMember[] ret = new ResolvedMember[fs.length]; + for (int i = 0, len = fs.length; i < len; i++) { + ret[i] = new BcelField(this, fs[i]); + } + fields = ret; + } + return fields; + } + + // ---- + // fun based on the aj attributes + + public ResolvedMember[] getDeclaredPointcuts() { + return pointcuts; + } + + //??? method only used for testing + public void addPointcutDefinition(ResolvedPointcutDefinition d) { + int len = pointcuts.length; + ResolvedPointcutDefinition[] ret = new ResolvedPointcutDefinition[len+1]; + System.arraycopy(pointcuts, 0, ret, 0, len); + ret[len] = d; + pointcuts = ret; + } + + + + public boolean isAspect() { + return perClause != null; + } + + private void unpackAspectAttributes() { + List pointcuts = new ArrayList(); + typeMungers = new ArrayList(); + declares = new ArrayList(); + List l = BcelAttributes.readAjAttributes(javaClass.getAttributes(), getSourceContext()); + for (Iterator iter = l.iterator(); iter.hasNext();) { + AjAttribute a = (AjAttribute) iter.next(); + if (a instanceof AjAttribute.Aspect) { + perClause = ((AjAttribute.Aspect)a).reify(this); + } else if (a instanceof AjAttribute.PointcutDeclarationAttribute) { + pointcuts.add(((AjAttribute.PointcutDeclarationAttribute)a).reify()); + } else if (a instanceof AjAttribute.WeaverState) { + weaverState = ((AjAttribute.WeaverState)a).reify(); + } else if (a instanceof AjAttribute.TypeMunger) { + typeMungers.add(((AjAttribute.TypeMunger)a).reify(getWorld(), this)); + } else if (a instanceof AjAttribute.DeclareAttribute) { + declares.add(((AjAttribute.DeclareAttribute)a).getDeclare()); + } else if (a instanceof AjAttribute.PrivilegedAttribute) { + privilegedAccess = ((AjAttribute.PrivilegedAttribute)a).getAccessedMembers(); + } else if (a instanceof AjAttribute.SourceContextAttribute) { + ((BcelSourceContext)sourceContext).addAttributeInfo((AjAttribute.SourceContextAttribute)a); + } else { + throw new BCException("bad attribute " + a); + } + } + this.pointcuts = (ResolvedPointcutDefinition[]) + pointcuts.toArray(new ResolvedPointcutDefinition[pointcuts.size()]); +// this.typeMungers = (BcelTypeMunger[]) +// typeMungers.toArray(new BcelTypeMunger[typeMungers.size()]); +// this.declares = (Declare[]) +// declares.toArray(new Declare[declares.size()]); + } + + public PerClause getPerClause() { + return perClause; + } + + + JavaClass getJavaClass() { + return javaClass; + } + + /** + * Switch to a new JavaClass and clear all caches + */ + void replaceJavaClass(JavaClass jc) { + if (this.javaClass == jc) return; + + this.javaClass = jc; + this.interfaces = null; + this.superClass = null; + this.fields = null; + this.methods = null; + this.pointcuts = null; + this.perClause = null; + this.weaverState = null; + this.lazyClassGen = null; + //XXX is clearing these caches sufficient + } + + public WeaverStateKind getWeaverState() { + return weaverState; + } + + public void setWeaverState(WeaverStateKind weaverState) { + this.weaverState = weaverState; + } + + public void printWackyStuff(PrintStream out) { + if (typeMungers.size() > 0) { + out.println(" TypeMungers: " + typeMungers); + } + if (declares.size() > 0) { + out.println(" declares: " + declares); + } + } + + /** + * Return the lazyClassGen associated with this type. For aspect types, this + * value will be cached, since it is used to inline advice. For non-aspect + * types, this lazyClassGen is always newly constructed. + */ + public LazyClassGen getLazyClassGen() { + LazyClassGen ret = lazyClassGen; + if (ret == null) { + ret = new LazyClassGen(this); + if (isAspect()) { + lazyClassGen = ret; + } + } + return ret; + } +} + + diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java b/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java new file mode 100644 index 000000000..ab5595916 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelRenderer.java @@ -0,0 +1,232 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.BCException; +import org.aspectj.weaver.ast.*; + +// we generate right to left, btw. +public class BcelRenderer implements ITestVisitor, IExprVisitor { + + private InstructionList instructions; + private InstructionFactory fact; + private BcelWorld world; + + InstructionHandle sk, fk, next = null; + + private BcelRenderer(InstructionFactory fact, BcelWorld world) { + super(); + this.fact = fact; + this.world = world; + this.instructions = new InstructionList(); + } + + // ---- renderers + + public static InstructionList renderExpr( + InstructionFactory fact, + BcelWorld world, + Expr e) + { + BcelRenderer renderer = new BcelRenderer(fact, world); + e.accept(renderer); + return renderer.instructions; + } + public static InstructionList renderExpr( + InstructionFactory fact, + BcelWorld world, + Expr e, + Type desiredType) + { + BcelRenderer renderer = new BcelRenderer(fact, world); + e.accept(renderer); + InstructionList il = renderer.instructions; + il.append(Utility.createConversion(fact, world.makeBcelType(e.getType()), desiredType)); + return il; + } + + public static InstructionList renderExprs( + InstructionFactory fact, + BcelWorld world, + Expr[] es) + { + BcelRenderer renderer = new BcelRenderer(fact, world); + for (int i = es.length - 1; i >= 0; i--) { + es[i].accept(renderer); + } + return renderer.instructions; + } + + /* + * Get the instructions representing this test. + * + * @param e test to render + * @param sk instructionHandle to jump to if our rendered check succeeds (typically start of advice) + * @param fk instructionHandle to jump to if our rendered check fails (typically after end of advice) + * @param next instructionHandle that will follow this generated code. Passing in null will generate + * one unnecessary GOTO instruction. + * + * @returns the instruction list representing this expression + */ + public static InstructionList renderTest( + InstructionFactory fact, + BcelWorld world, + Test e, + InstructionHandle sk, + InstructionHandle fk, + InstructionHandle next) + { + BcelRenderer renderer = new BcelRenderer(fact, world); + renderer.recur(e, sk, fk, next); + return renderer.instructions; + } + + /* + * Get the instructions representing this test. + * + * @param e test to render + * @param sk instructionHandle to jump to if our rendered check succeeds (typically start of advice) + * @param fk instructionHandle to jump to if our rendered check fails (typically after end of advice) + * + * @returns the instruction list representing this expression + */ + public static InstructionList renderTest( + InstructionFactory fact, + BcelWorld world, + Test e, + InstructionHandle sk, + InstructionHandle fk) + { + return renderTest(fact, world, e, sk, fk, null); + } + + // ---- recurrers + + private void recur( + Test e, + InstructionHandle sk, + InstructionHandle fk, + InstructionHandle next) + { + this.sk = sk; + this.fk = fk; + this.next = next; + e.accept(this); + } + + // ---- test visitors + + public void visit(And e) { + InstructionHandle savedFk = fk; + recur(e.getRight(), sk, fk, next); + InstructionHandle ning = instructions.getStart(); + recur(e.getLeft(), ning, savedFk, ning); + } + + public void visit(Or e) { + InstructionHandle savedSk = sk; + recur(e.getRight(), sk, fk, next); + recur(e.getLeft(), savedSk, instructions.getStart(), instructions.getStart()); + } + + public void visit(Not e) { + recur(e.getBody(), fk, sk, next); + } + + public void visit(Instanceof i) { + instructions.insert(createJumpBasedOnBooleanOnStack()); + instructions.insert( + Utility.createInstanceof(fact, (ObjectType) world.makeBcelType(i.getType()))); + i.getVar().accept(this); + } + + private InstructionList createJumpBasedOnBooleanOnStack() { + InstructionList il = new InstructionList(); + if (sk == fk) { + // don't bother generating if it doesn't matter + if (sk != next) { + il.insert(fact.createBranchInstruction(Constants.GOTO, sk)); + } + return il; + } + + if (fk == next) { + il.insert(fact.createBranchInstruction(Constants.IFNE, sk)); + } else if (sk == next) { + il.insert(fact.createBranchInstruction(Constants.IFEQ, fk)); + } else { + il.insert(fact.createBranchInstruction(Constants.GOTO, sk)); + il.insert(fact.createBranchInstruction(Constants.IFEQ, fk)); + } + return il; + } + + + public void visit(Literal literal) { + if (literal == Literal.FALSE) + throw new BCException("bad"); + } + + public void visit(Call call) { + Member method = call.getMethod(); + // assert method.isStatic() + Expr[] args = call.getArgs(); + //System.out.println("args: " + Arrays.asList(args)); + InstructionList callIl = renderExprs(fact, world, args); + //System.out.println("rendered args: " + callIl); + callIl.append(Utility.createInvoke(fact, world, method)); + callIl.append(createJumpBasedOnBooleanOnStack()); + instructions.insert(callIl); + } + + public void visit(FieldGetCall fieldGetCall) { + Member field = fieldGetCall.getField(); + Member method = fieldGetCall.getMethod(); + InstructionList il = new InstructionList(); + il.append(Utility.createGet(fact, field)); + // assert !method.isStatic() + Expr[] args = fieldGetCall.getArgs(); + //System.out.println("args: " + Arrays.asList(args)); + il.append(renderExprs(fact, world, args)); + //System.out.println("rendered args: " + callIl); + il.append(Utility.createInvoke(fact, world, method)); + il.append(createJumpBasedOnBooleanOnStack()); + instructions.insert(il); + } + + // ---- expr visitors + + public void visit(Var var) { + BcelVar bvar = (BcelVar) var; + bvar.insertLoad(instructions, fact); + } + + public void visit(FieldGet fieldGet) { + Member field = fieldGet.getField(); + // assert field.isStatic() + instructions.insert(Utility.createGet(fact, field)); + } + + public void visit(CallExpr call) { + Member method = call.getMethod(); + // assert method.isStatic() + Expr[] args = call.getArgs(); + InstructionList callIl = renderExprs(fact, world, args); + callIl.append(Utility.createInvoke(fact, world, method)); + instructions.insert(callIl); + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java new file mode 100644 index 000000000..432acd17b --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelShadow.java @@ -0,0 +1,1731 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.File; +import java.lang.reflect.Modifier; +import java.util.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.generic.*; +import org.aspectj.bridge.SourceLocation; +import org.aspectj.weaver.*; +import org.aspectj.weaver.Shadow.Kind; +import org.aspectj.weaver.ast.Var; + + +/* + * Some fun implementation stuff: + * + * * expressionKind advice is non-execution advice + * * may have a target. + * * if the body is extracted, it will be extracted into + * a static method. The first argument to the static + * method is the target + * * advice may expose a this object, but that's the advice's + * consideration, not ours. This object will NOT be cached in another + * local, but will always come from frame zero. + * + * * non-expressionKind advice is execution advice + * * may have a this. + * * target is same as this, and is exposed that way to advice + * (i.e., target will not be cached, will always come from frame zero) + * * if the body is extracted, it will be extracted into a method + * with same static/dynamic modifier as enclosing method. If non-static, + * target of callback call will be this. + * + * * because of these two facts, the setup of the actual arguments (including + * possible target) callback method is the same for both kinds of advice: + * push the targetVar, if it exists (it will not exist for advice on static + * things), then push all the argVars. + * + * Protected things: + * + * * the above is sufficient for non-expressionKind advice for protected things, + * since the target will always be this. + * + * * For expressionKind things, we have to modify the signature of the callback + * method slightly. For non-static expressionKind things, we modify + * the first argument of the callback method NOT to be the type specified + * by the method/field signature (the owner), but rather we type it to + * the currentlyEnclosing type. We are guaranteed this will be fine, + * since the verifier verifies that the target is a subtype of the currently + * enclosingType. + * + * Worries: + * + * * ConstructorCalls will be weirder than all of these, since they + * supposedly don't have a target (according to AspectJ), but they clearly + * do have a target of sorts, just one that needs to be pushed on the stack, + * dupped, and not touched otherwise until the constructor runs. + * + */ + +public class BcelShadow extends Shadow { + + private ShadowRange range; + private final BcelWorld world; + private final LazyMethodGen enclosingMethod; + private final BcelShadow enclosingShadow; + + private boolean fallsThrough; + + // ---- initialization + + /** + * This generates an unassociated shadow, rooted in a particular method but not rooted + * to any particular point in the code. It should be given to a rooted ShadowRange + * in the {@link ShadowRange#associateWithShadow(BcelShadow)} method. + */ + public BcelShadow( + BcelWorld world, + Kind kind, + Member signature, + LazyMethodGen enclosingMethod, + BcelShadow enclosingShadow) + { + super(kind, signature); + this.world = world; + this.enclosingMethod = enclosingMethod; + this.enclosingShadow = enclosingShadow; + fallsThrough = kind.argsOnStack(); + } + + // ---- copies all state, including Shadow's mungers... + + public BcelShadow copyInto(LazyMethodGen recipient, BcelShadow enclosing) { + BcelShadow s = new BcelShadow(world, getKind(), getSignature(), recipient, enclosing); + List src = mungers; + List dest = s.mungers; + + for (Iterator i = src.iterator(); i.hasNext(); ) { + dest.add(i.next()); + } + return s; + } + + // ---- overridden behaviour + + public World getIWorld() { + return world; + } + + + + private void deleteNewAndDup() { + final ConstantPoolGen cpg = getEnclosingClass().getConstantPoolGen(); + int depth = 1; + InstructionHandle ih = range.getStart(); + + while (true) { + Instruction inst = ih.getInstruction(); + if (inst instanceof INVOKESPECIAL + && ((INVOKESPECIAL) inst).getName(cpg).equals("<init>")) { + depth++; + } else if (inst instanceof NEW) { + depth--; + if (depth == 0) break; + } + ih = ih.getPrev(); + } + // now IH points to the NEW. We're followed by the DUP, and that is followed + // by the actual instruciton we care about. + InstructionHandle newHandle = ih; + InstructionHandle endHandle = newHandle.getNext(); + InstructionHandle nextHandle; + if (endHandle.getInstruction() instanceof DUP) { + nextHandle = endHandle.getNext(); + retargetFrom(newHandle, nextHandle); + retargetFrom(endHandle, nextHandle); + } else if (endHandle.getInstruction() instanceof DUP_X1) { + InstructionHandle dupHandle = endHandle; + endHandle = endHandle.getNext(); + nextHandle = endHandle.getNext(); + if (endHandle.getInstruction() instanceof SWAP) {} + else { + // XXX see next XXX comment + throw new RuntimeException("Unhandled kind of new " + endHandle); + } + retargetFrom(newHandle, nextHandle); + retargetFrom(dupHandle, nextHandle); + retargetFrom(endHandle, nextHandle); + } else { + // XXX we want to fail gracefully here. This should not be picked out as a join point, + // probably. So change BcelClassWeaver.match appropriately. + throw new RuntimeException("Unhandled kind of new"); + } + // assert (dupHandle.getInstruction() instanceof DUP); + + try { + range.getBody().delete(newHandle, endHandle); + } catch (TargetLostException e) { + throw new BCException("shouldn't happen"); + } + } + private void retargetFrom(InstructionHandle old, InstructionHandle fresh) { + InstructionTargeter[] sources = old.getTargeters(); + if (sources != null) { + for (int i = sources.length - 1; i >= 0; i--) { + sources[i].updateTarget(old, fresh); + } + } + } + + protected void prepareForMungers() { + // if we're a constructor call, we need to remove the new:dup or the new:dup_x1:swap, + // and store all our + // arguments on the frame. + + // ??? This is a bit of a hack (for the Java langauge). We do this because + // we sometime add code "outsideBefore" when dealing with weaving join points. We only + // do this for exposing state that is on the stack. It turns out to just work for + // everything except for constructor calls and exception handlers. If we were to clean + // this up, every ShadowRange would have three instructionHandle points, the start of + // the arg-setup code, the start of the running code, and the end of the running code. + if (getKind() == ConstructorCall) { + deleteNewAndDup(); + initializeArgVars(); + } else if (getKind() == ExceptionHandler) { + ShadowRange range = getRange(); + InstructionList body = range.getBody(); + InstructionHandle start = range.getStart(); + InstructionHandle freshIh = body.insert(start, getFactory().NOP); + InstructionTargeter[] targeters = start.getTargeters(); + for (int i = 0; i < targeters.length; i++) { + InstructionTargeter t = targeters[i]; + if (t instanceof ExceptionRange) { + ExceptionRange er = (ExceptionRange) t; + er.updateTarget(start, freshIh, body); + } + } + } + + // now we ask each munger to request our state + for (Iterator iter = mungers.iterator(); iter.hasNext();) { + ShadowMunger munger = (ShadowMunger) iter.next(); + munger.specializeOn(this); + } + + // If we are an expression kind, we require our target/arguments on the stack + // before we do our actual thing. However, they may have been removed + // from the stack as the shadowMungers have requested state. + // if any of our shadowMungers requested either the arguments or target, + // the munger will have added code + // to pop the target/arguments into temporary variables, represented by + // targetVar and argVars. In such a case, we must make sure to re-push the + // values. + + // If we are nonExpressionKind, we don't expect arguments on the stack + // so this is moot. If our argVars happen to be null, then we know that + // no ShadowMunger has squirrelled away our arguments, so they're still + // on the stack. + InstructionFactory fact = getFactory(); + if (getKind().argsOnStack() && argVars != null) { + range.insert( + BcelRenderer.renderExprs(fact, world, argVars), + Range.InsideBefore); + if (targetVar != null) { + range.insert( + BcelRenderer.renderExpr(fact, world, targetVar), + Range.InsideBefore); + } + if (getKind() == ConstructorCall) { + range.insert((Instruction) fact.createDup(1), Range.InsideBefore); + range.insert( + fact.createNew( + (ObjectType) BcelWorld.makeBcelType( + getSignature().getDeclaringType())), + Range.InsideBefore); + } + } + } + + // ---- getters + + public ShadowRange getRange() { + return range; + } + public void setRange(ShadowRange range) { + this.range = range; + } + + public int getSourceLine() { + if (range == null) return 0; + int ret = Utility.getSourceLine(range.getStart()); + if (ret < 0) return 0; + return ret; + } + + // overrides + public TypeX getEnclosingType() { + return world.resolve(getEnclosingClass().getClassName()); + } + + public LazyClassGen getEnclosingClass() { + return enclosingMethod.getEnclosingClass(); + } + + public BcelWorld getWorld() { + return world; + } + + // ---- factory methods + + public static BcelShadow makeConstructorExecution( + BcelWorld world, + LazyMethodGen enclosingMethod, + InstructionHandle justBeforeStart) + { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = + new BcelShadow( + world, + ConstructorExecution, + world.makeMethodSignature(enclosingMethod), + enclosingMethod, + null); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets( + Range.genStart(body, justBeforeStart.getNext()), + Range.genEnd(body)); + return s; + } + + public static BcelShadow makeStaticInitialization( + BcelWorld world, + LazyMethodGen enclosingMethod) + { + InstructionList body = enclosingMethod.getBody(); + BcelShadow s = + new BcelShadow( + world, + StaticInitialization, + world.makeMethodSignature(enclosingMethod), + enclosingMethod, + null); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets( + Range.genStart(body), + Range.genEnd(body)); + return s; + } + + /** Make the shadow for an exception handler. Currently makes an empty shadow that + * only allows before advice to be woven into it. + */ + + + public static BcelShadow makeExceptionHandler( + BcelWorld world, + ExceptionRange exceptionRange, + LazyMethodGen enclosingMethod, + InstructionHandle startOfHandler, + BcelShadow enclosingShadow) + { + InstructionList body = enclosingMethod.getBody(); + TypeX catchType = exceptionRange.getCatchType(); + TypeX inType = enclosingMethod.getEnclosingClass().getType(); + BcelShadow s = + new BcelShadow( + world, + ExceptionHandler, + Member.makeExceptionHandlerSignature(inType, catchType), + enclosingMethod, + enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + InstructionHandle start = Range.genStart(body, startOfHandler); + InstructionHandle end = Range.genEnd(body, start); + + r.associateWithTargets(start, end); + exceptionRange.updateTarget(startOfHandler, start, body); + return s; + } + + /** create an init join point associated w/ an interface in the body of a constructor */ + + public static BcelShadow makeIfaceInitialization( + BcelWorld world, + LazyMethodGen constructor, + BcelShadow ifaceCExecShadow, + Member interfaceConstructorSignature) + { + InstructionList body = constructor.getBody(); + TypeX inType = constructor.getEnclosingClass().getType(); + BcelShadow s = + new BcelShadow( + world, + Initialization, + interfaceConstructorSignature, + constructor, + null); + s.fallsThrough = true; + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + InstructionHandle start = Range.genStart(body, ifaceCExecShadow.getRange().getStart()); + InstructionHandle end = Range.genEnd(body, ifaceCExecShadow.getRange().getEnd()); + + r.associateWithTargets(start, end); + return s; + } + + public static BcelShadow makeIfaceConstructorExecution( + BcelWorld world, + LazyMethodGen constructor, + InstructionHandle next, + Member interfaceConstructorSignature) + { + final InstructionFactory fact = constructor.getEnclosingClass().getFactory(); + InstructionList body = constructor.getBody(); + TypeX inType = constructor.getEnclosingClass().getType(); + BcelShadow s = + new BcelShadow( + world, + ConstructorExecution, + interfaceConstructorSignature, + constructor, + null); + s.fallsThrough = true; + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + // ??? this may or may not work + InstructionHandle start = Range.genStart(body, next); + //InstructionHandle end = Range.genEnd(body, body.append(start, fact.NOP)); + InstructionHandle end = Range.genStart(body, next); + //body.append(start, fact.NOP); + + r.associateWithTargets(start, end); + return s; + } + + + /** Create an initialization join point associated with a constructor, but not + * with any body of code yet. If this is actually matched, it's range will be set + * when we inline self constructors. + * + * @param constructor The constructor starting this initialization. + */ + public static BcelShadow makeUnfinishedInitialization( + BcelWorld world, + LazyMethodGen constructor) + { + return new BcelShadow( + world, + Initialization, + world.makeMethodSignature(constructor), + constructor, + null); + } + + public static BcelShadow makeUnfinishedPreinitialization( + BcelWorld world, + LazyMethodGen constructor) + { + BcelShadow ret = new BcelShadow( + world, + PreInitialization, + world.makeMethodSignature(constructor), + constructor, + null); + ret.fallsThrough = true; + return ret; + } + + + public static BcelShadow makeMethodExecution( + BcelWorld world, + LazyMethodGen enclosingMethod) + { + return makeShadowForMethod(world, enclosingMethod, MethodExecution, + world.makeMethodSignature(enclosingMethod)); + } + + + public static BcelShadow makeShadowForMethod(BcelWorld world, + LazyMethodGen enclosingMethod, Shadow.Kind kind, Member sig) + { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = + new BcelShadow( + world, + kind, + sig, + enclosingMethod, + null); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets( + Range.genStart(body), + Range.genEnd(body)); + return s; + } + + + + public static BcelShadow makeAdviceExecution( + BcelWorld world, + LazyMethodGen enclosingMethod) + { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = + new BcelShadow( + world, + AdviceExecution, + world.makeMethodSignature(enclosingMethod), + enclosingMethod, + null); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets(Range.genStart(body), Range.genEnd(body)); + return s; + } + + + // constructor call shadows are <em>initially</em> just around the + // call to the constructor. If ANY advice gets put on it, we move + // the NEW instruction inside the join point, which involves putting + // all the arguments in temps. + public static BcelShadow makeConstructorCall( + BcelWorld world, + LazyMethodGen enclosingMethod, + InstructionHandle callHandle, + BcelShadow enclosingShadow) + { + final InstructionList body = enclosingMethod.getBody(); + + Member sig = world.makeMethodSignature( + enclosingMethod.getEnclosingClass(), + (InvokeInstruction) callHandle.getInstruction()); + + BcelShadow s = + new BcelShadow( + world, + ConstructorCall, + sig, + enclosingMethod, + enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets( + Range.genStart(body, callHandle), + Range.genEnd(body, callHandle)); + retargetAllBranches(callHandle, r.getStart()); + return s; + } + + public static BcelShadow makeMethodCall( + BcelWorld world, + LazyMethodGen enclosingMethod, + InstructionHandle callHandle, + BcelShadow enclosingShadow) + { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = + new BcelShadow( + world, + MethodCall, + world.makeMethodSignature( + enclosingMethod.getEnclosingClass(), + (InvokeInstruction) callHandle.getInstruction()), + enclosingMethod, + enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets( + Range.genStart(body, callHandle), + Range.genEnd(body, callHandle)); + retargetAllBranches(callHandle, r.getStart()); + return s; + } + + + public static BcelShadow makeShadowForMethodCall( + BcelWorld world, + LazyMethodGen enclosingMethod, + InstructionHandle callHandle, + BcelShadow enclosingShadow, + Kind kind, + ResolvedMember sig) + { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = + new BcelShadow( + world, + kind, + sig, + enclosingMethod, + enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets( + Range.genStart(body, callHandle), + Range.genEnd(body, callHandle)); + retargetAllBranches(callHandle, r.getStart()); + return s; + } + + + public static BcelShadow makeFieldGet( + BcelWorld world, + LazyMethodGen enclosingMethod, + InstructionHandle getHandle, + BcelShadow enclosingShadow) + { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = + new BcelShadow( + world, + FieldGet, + world.makeFieldSignature( + enclosingMethod.getEnclosingClass(), + (FieldInstruction) getHandle.getInstruction()), + enclosingMethod, + enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets( + Range.genStart(body, getHandle), + Range.genEnd(body, getHandle)); + retargetAllBranches(getHandle, r.getStart()); + return s; + } + + public static BcelShadow makeFieldSet( + BcelWorld world, + LazyMethodGen enclosingMethod, + InstructionHandle setHandle, + BcelShadow enclosingShadow) + { + final InstructionList body = enclosingMethod.getBody(); + BcelShadow s = + new BcelShadow( + world, + FieldSet, + world.makeFieldSignature( + enclosingMethod.getEnclosingClass(), + (FieldInstruction) setHandle.getInstruction()), + enclosingMethod, + enclosingShadow); + ShadowRange r = new ShadowRange(body); + r.associateWithShadow(s); + r.associateWithTargets( + Range.genStart(body, setHandle), + Range.genEnd(body, setHandle)); + retargetAllBranches(setHandle, r.getStart()); + return s; + } + + public static void retargetAllBranches(InstructionHandle from, InstructionHandle to) { + InstructionTargeter[] sources = from.getTargeters(); + if (sources != null) { + for (int i = sources.length - 1; i >= 0; i--) { + InstructionTargeter source = sources[i]; + if (source instanceof BranchInstruction) { + source.updateTarget(from, to); + } + } + } + } + + // ---- type access methods + + public boolean hasThis() { + if (getKind() == PreInitialization) return false; + return !getEnclosingCodeSignature().isStatic(); + //???return !enclosingMethod.isStatic(); + } + public TypeX getThisType() { + if (!hasThis()) return ResolvedTypeX.MISSING; + return getEnclosingCodeSignature().getDeclaringType(); + //???return TypeX.forName(getEnclosingClass().getClassName()); + } + + public boolean hasRealTarget() { + return hasTarget() && isExpressionKind(); + } + + + private ObjectType getTargetBcelType() { + return (ObjectType) world.makeBcelType(getTargetType()); + } + private Type getArgBcelType(int arg) { + return world.makeBcelType(getArgType(arg)); + } + + // ---- kinding + + public boolean isExpressionKind() { + if (getKind() == PreInitialization) return true; + return getKind().argsOnStack(); + } + + // ---- argument getting methods + + private BcelVar thisVar = null; + private BcelVar targetVar = null; + private BcelVar[] argVars = null; + + public Var getThisVar() { + if (!hasThis()) { + throw new IllegalStateException("no this"); + } + initializeThisVar(); + return thisVar; + } + public Var getTargetVar() { + if (!hasTarget()) { + throw new IllegalStateException("no target"); + } + initializeTargetVar(); + return targetVar; + } + public Var getArgVar(int i) { + initializeArgVars(); + return argVars[i]; + } + + // reflective thisJoinPoint support + private BcelVar thisJoinPointVar = null; + private BcelVar thisJoinPointStaticPartVar = null; //XXX should be field + private BcelVar thisEnclosingJoinPointStaticPartVar = null; //XXX should be field + + public final Var getThisJoinPointVar() { + return getThisJoinPointBcelVar(); + } + public final Var getThisJoinPointStaticPartVar() { + return getThisJoinPointStaticPartBcelVar(); + } + public final Var getThisEnclosingJoinPointStaticPartVar() { + return getThisEnclosingJoinPointStaticPartBcelVar(); + } + + public BcelVar getThisJoinPointBcelVar() { + if (thisJoinPointVar == null) { + thisJoinPointVar = genTempVar(TypeX.forName("org.aspectj.lang.JoinPoint")); + InstructionFactory fact = getFactory(); + InstructionList il = new InstructionList(); + BcelVar staticPart = getThisJoinPointStaticPartBcelVar(); + staticPart.appendLoad(il, fact); + if (hasThis()) { + ((BcelVar)getThisVar()).appendLoad(il, fact); + } else { + il.append(new ACONST_NULL()); + } + if (hasTarget()) { + ((BcelVar)getTargetVar()).appendLoad(il, fact); + } else { + il.append(new ACONST_NULL()); + } + il.append(makeArgsObjectArray()); + + il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory", + "makeJP", LazyClassGen.tjpType, + new Type[] { LazyClassGen.staticTjpType, + Type.OBJECT, Type.OBJECT, new ArrayType(Type.OBJECT, 1)}, + Constants.INVOKESTATIC)); + il.append(thisJoinPointVar.createStore(fact)); + range.insert(il, Range.OutsideBefore); + } + return thisJoinPointVar; + } + + public BcelVar getThisJoinPointStaticPartBcelVar() { + if (thisJoinPointStaticPartVar == null) { + Field field = getEnclosingClass().getTjpField(this); + thisJoinPointStaticPartVar = + new BcelFieldRef( + world.resolve(TypeX.forName("org.aspectj.lang.JoinPoint$StaticPart")), + getEnclosingClass().getClassName(), + field.getName()); + } + return thisJoinPointStaticPartVar; + } + + public BcelVar getThisEnclosingJoinPointStaticPartBcelVar() { + if (enclosingShadow == null) { + // the enclosing of an execution is itself + return getThisJoinPointStaticPartBcelVar(); + } else { + return enclosingShadow.getThisJoinPointStaticPartBcelVar(); + } + } + + public Member getEnclosingCodeSignature() { + if (enclosingShadow == null) { + return getSignature(); + } else { + return enclosingShadow.getSignature(); + } + } + + + private InstructionList makeArgsObjectArray() { + InstructionFactory fact = getFactory(); + BcelVar arrayVar = genTempVar(TypeX.OBJECTARRAY); + final InstructionList il = new InstructionList(); + int alen = getArgCount() ; + il.append(Utility.createConstant(fact, alen)); + il.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1)); + arrayVar.appendStore(il, fact); + + int stateIndex = 0; + for (int i = 0, len = getArgCount(); i<len; i++) { + arrayVar.appendConvertableArrayStore(il, fact, stateIndex, (BcelVar)getArgVar(i)); + stateIndex++; + } + arrayVar.appendLoad(il, fact); + return il; + } + + // ---- initializing var tables + + /* initializing this is doesn't do anything, because this + * is protected from side-effects, so we don't need to copy its location + */ + + private void initializeThisVar() { + if (thisVar != null) return; + thisVar = new BcelVar(getThisType().resolve(world), 0); + } + public void initializeTargetVar() { + InstructionFactory fact = getFactory(); + if (targetVar != null) return; + if (! isExpressionKind()) { + initializeThisVar(); + targetVar = thisVar; + } else { + initializeArgVars(); // gotta pop off the args before we find the target + TypeX type = getTargetType(); + targetVar = genTempVar(type, "ajc$target"); + range.insert(targetVar.createStore(fact), Range.OutsideBefore); + } + targetVar.setPositionInAroundState(0); + } + public void initializeArgVars() { + if (argVars != null) return; + InstructionFactory fact = getFactory(); + int len = getArgCount(); + argVars = new BcelVar[len]; + + if (getKind().argsOnStack()) { + // we move backwards because we're popping off the stack + for (int i = len - 1; i >= 0; i--) { + TypeX type = getArgType(i); + BcelVar tmp = genTempVar(type, "ajc$arg" + i); + range.insert(tmp.createStore(getFactory()), Range.OutsideBefore); + int position = i; + if (hasTarget()) position += 1; + tmp.setPositionInAroundState(position); + argVars[i] = tmp; + } + } else { + int index = 0; + if (hasThis()) index++; + for (int i = 0; i < len; i++) { + TypeX type = getArgType(i); + BcelVar tmp = genTempVar(type, "ajc$arg" + i); + range.insert(tmp.createCopyFrom(fact, index), Range.OutsideBefore); + argVars[i] = tmp; + int position = i; + if (hasTarget()) position += 1; + tmp.setPositionInAroundState(position); + index += type.getSize(); + } + } + } + public void initializeForAroundClosure() { + initializeArgVars(); + if (hasTarget()) initializeTargetVar(); + } + + + // ---- weave methods + + void weaveBefore(BcelAdvice munger) { + range.insert( + munger.getAdviceInstructions(this, null, range.getRealStart()), + Range.InsideBefore); + } + + public void weaveAfter(BcelAdvice munger) { + weaveAfterThrowing(munger, TypeX.THROWABLE); + weaveAfterReturning(munger); + } + + /** + * We guarantee that the return value is on the top of the stack when + * munger.getAdviceInstructions() will be run + * (Unless we have a void return type in which case there's nothing) + */ + public void weaveAfterReturning(BcelAdvice munger) { + InstructionFactory fact = getFactory(); + List returns = new ArrayList(); + Instruction ret = null; + for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) { + if (ih.getInstruction() instanceof ReturnInstruction) { + returns.add(ih); + ret = ih.getInstruction().copy(); + } + } + InstructionList retList; + InstructionHandle afterAdvice; + if (ret != null) { + retList = new InstructionList(ret); + afterAdvice = retList.getStart(); + } else /* if (munger.hasDynamicTests()) */ { + retList = new InstructionList(fact.NOP); + afterAdvice = retList.getStart(); +// } else { +// retList = new InstructionList(); +// afterAdvice = null; + } + + InstructionList advice = new InstructionList(); + BcelVar tempVar = null; + if (munger.hasExtraParameter()) { + TypeX tempVarType = getReturnType(); + if (tempVarType.equals(ResolvedTypeX.VOID)) { + tempVar = genTempVar(TypeX.OBJECT); + advice.append(getFactory().ACONST_NULL); + tempVar.appendStore(advice, getFactory()); + } else { + tempVar = genTempVar(tempVarType); + advice.append(getFactory().createDup(tempVarType.getSize())); + tempVar.appendStore(advice, getFactory()); + } + } + advice.append(munger.getAdviceInstructions(this, tempVar, afterAdvice)); + + if (ret != null) { + InstructionHandle gotoTarget = advice.getStart(); + for (Iterator i = returns.iterator(); i.hasNext(); ) { + InstructionHandle ih = (InstructionHandle) i.next(); + Utility.replaceInstruction(ih, fact.createBranchInstruction(Constants.GOTO, gotoTarget), enclosingMethod); + } + range.append(advice); + range.append(retList); + } else { + range.append(advice); + range.append(retList); + } + } + + public void weaveAfterThrowing(BcelAdvice munger, TypeX catchType) { + InstructionFactory fact = getFactory(); + InstructionList handler = new InstructionList(); + BcelVar exceptionVar = genTempVar(catchType); + exceptionVar.appendStore(handler, fact); + + + InstructionList endHandler = new InstructionList( + exceptionVar.createLoad(fact)); + handler.append(munger.getAdviceInstructions(this, exceptionVar, endHandler.getStart())); + handler.append(endHandler); + handler.append(fact.ATHROW); + InstructionHandle handlerStart = handler.getStart(); + + if (isFallsThrough()) { + InstructionHandle jumpTarget = handler.append(fact.NOP); + handler.insert(fact.createBranchInstruction(Constants.GOTO, jumpTarget)); + } + InstructionHandle protectedEnd = handler.getStart(); + range.insert(handler, Range.InsideAfter); + + enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), + handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType), //???Type.THROWABLE, + // high priority if our args are on the stack + isExpressionKind()); + } + + + public void weaveSoftener(BcelAdvice munger, TypeX catchType) { + InstructionFactory fact = getFactory(); + InstructionList handler = new InstructionList(); + BcelVar exceptionVar = genTempVar(catchType); + exceptionVar.appendStore(handler, fact); + + handler.append(fact.createNew(NameMangler.SOFT_EXCEPTION_TYPE)); + handler.append(fact.createDup(1)); + handler.append(exceptionVar.createLoad(fact)); + handler.append(fact.createInvoke(NameMangler.SOFT_EXCEPTION_TYPE, "<init>", + Type.VOID, new Type[] { Type.THROWABLE }, Constants.INVOKESPECIAL)); //??? special + handler.append(fact.ATHROW); + InstructionHandle handlerStart = handler.getStart(); + + if (isFallsThrough()) { + InstructionHandle jumpTarget = range.getEnd();//handler.append(fact.NOP); + handler.insert(fact.createBranchInstruction(Constants.GOTO, jumpTarget)); + } + InstructionHandle protectedEnd = handler.getStart(); + range.insert(handler, Range.InsideAfter); + + enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(), + handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType), + // high priority if our args are on the stack + isExpressionKind()); + } + + + public void weavePerObjectEntry(final BcelAdvice munger, final BcelVar onVar) { + final InstructionFactory fact = getFactory(); + + + InstructionList entryInstructions = new InstructionList(); + InstructionList entrySuccessInstructions = new InstructionList(); + onVar.appendLoad(entrySuccessInstructions, fact); + + entrySuccessInstructions.append( + Utility.createInvoke(fact, world, + AjcMemberMaker.perObjectBind(munger.getConcreteAspect()))); + + InstructionList testInstructions = + munger.getTestInstructions(this, entrySuccessInstructions.getStart(), + range.getRealStart(), + entrySuccessInstructions.getStart()); + + entryInstructions.append(testInstructions); + entryInstructions.append(entrySuccessInstructions); + + range.insert(entryInstructions, Range.InsideBefore); + } + + + public void weaveCflowEntry(final BcelAdvice munger, final Member cflowStackField) { + final boolean isPer = munger.getKind() == AdviceKind.PerCflowBelowEntry || + munger.getKind() == AdviceKind.PerCflowEntry; + + final Type objectArrayType = new ArrayType(Type.OBJECT, 1); + final InstructionFactory fact = getFactory(); + + final BcelVar testResult = genTempVar(ResolvedTypeX.BOOLEAN); + + InstructionList entryInstructions = new InstructionList(); + { + InstructionList entrySuccessInstructions = new InstructionList(); + + if (munger.hasDynamicTests()) { + entryInstructions.append(Utility.createConstant(fact, 0)); + testResult.appendStore(entryInstructions, fact); + + entrySuccessInstructions.append(Utility.createConstant(fact, 1)); + testResult.appendStore(entrySuccessInstructions, fact); + } + + if (isPer) { + entrySuccessInstructions.append( + fact.createInvoke(munger.getConcreteAspect().getName(), + NameMangler.PERCFLOW_PUSH_METHOD, + Type.VOID, + new Type[] { }, + Constants.INVOKESTATIC)); + } else { + BcelVar[] cflowStateVars = munger.getExposedStateAsBcelVars(); + + BcelVar arrayVar = genTempVar(TypeX.OBJECTARRAY); + + int alen = cflowStateVars.length; + entrySuccessInstructions.append(Utility.createConstant(fact, alen)); + entrySuccessInstructions.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1)); + arrayVar.appendStore(entrySuccessInstructions, fact); + + for (int i = 0; i < alen; i++) { + arrayVar.appendConvertableArrayStore(entrySuccessInstructions, fact, i, cflowStateVars[i]); + } + + entrySuccessInstructions.append( + Utility.createGet(fact, cflowStackField)); + arrayVar.appendLoad(entrySuccessInstructions, fact); + + entrySuccessInstructions.append( + fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "push", Type.VOID, + new Type[] { objectArrayType }, + Constants.INVOKEVIRTUAL)); + } + + + InstructionList testInstructions = + munger.getTestInstructions(this, entrySuccessInstructions.getStart(), + range.getRealStart(), + entrySuccessInstructions.getStart()); + + entryInstructions.append(testInstructions); + entryInstructions.append(entrySuccessInstructions); + } + + // this is the same for both per and non-per + weaveAfter(new BcelAdvice(null, null, null, 0, 0, 0, null, null) { + public InstructionList getAdviceInstructions(BcelShadow s, BcelVar extraArgVar, InstructionHandle ifNoAdvice) { + InstructionList exitInstructions = new InstructionList(); + if (munger.hasDynamicTests()) { + testResult.appendLoad(exitInstructions, fact); + exitInstructions.append(fact.createBranchInstruction(Constants.IFEQ, ifNoAdvice)); + } + exitInstructions.append( + Utility.createGet(fact, cflowStackField)); + exitInstructions.append( + fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "pop", Type.VOID, new Type[] {}, Constants.INVOKEVIRTUAL)); + return exitInstructions; + }}); + + + range.insert(entryInstructions, Range.InsideBefore); + } + + public void weaveAroundInline( + BcelAdvice munger, + boolean hasDynamicTest) + { + /* Implementation notes: + * + * AroundInline still extracts the instructions of the original shadow into + * an extracted method. This allows inlining of even that advice that doesn't + * call proceed or calls proceed more than once. + * + * It extracts the instructions of the original shadow into a method. + * + * Then it inlines the instructions of the advice in its place, taking care + * to treat the closure argument specially (it doesn't exist). + * + * Then it searches in the instructions of the advice for any call to the + * proceed method. + * + * At such a call, there is stuff on the stack representing the arguments to + * proceed. Pop these into the frame. + * + * Now build the stack for the call to the extracted method, taking values + * either from the join point state or from the new frame locs from proceed. + * Now call the extracted method. The right return value should be on the + * stack, so no cast is necessary. + * + * If only one call to proceed is made, we can re-inline the original shadow. + * We are not doing that presently. + */ + + // start by exposing various useful things into the frame + final InstructionFactory fact = getFactory(); + + // now generate the aroundBody method + LazyMethodGen extractedMethod = + extractMethod( + NameMangler.aroundCallbackMethodName( + getSignature(), + getEnclosingClass())); + + // the shadow is now empty. First, create a correct call + // to the around advice. This includes both the call (which may involve + // value conversion of the advice arguments) and the return + // (which may involve value conversion of the return value). Right now + // we push a null for the unused closure. It's sad, but there it is. + + InstructionList advice = new InstructionList(); + InstructionHandle adviceMethodInvocation; + { + // ??? we don't actually need to push NULL for the closure if we take care + advice.append(munger.getAdviceArgSetup(this, null, new InstructionList(fact.ACONST_NULL))); + adviceMethodInvocation = + advice.append( + Utility.createInvoke(fact, getWorld(), munger.getSignature())); + advice.append( + Utility.createConversion( + getFactory(), + world.makeBcelType(munger.getSignature().getReturnType()), + extractedMethod.getReturnType())); + if (! isFallsThrough()) { + advice.append(fact.createReturn(extractedMethod.getReturnType())); + } + } + + // now, situate the call inside the possible dynamic tests, + // and actually add the whole mess to the shadow + if (! hasDynamicTest) { + range.append(advice); + } else { + InstructionList callback = makeCallToCallback(extractedMethod); + if (! isExpressionKind()) { + callback.append(fact.createReturn(extractedMethod.getReturnType())); + } else { + advice.append(fact.createBranchInstruction(Constants.GOTO, range.getEnd())); + } + range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart())); + range.append(advice); + range.append(callback); + } + + // now the range contains everything we need. We now inline the advice method. + LazyMethodGen adviceMethod = + ((BcelObjectType) munger.getConcreteAspect()) + .getLazyClassGen() + .getLazyMethodGen(munger.getSignature()); + + BcelClassWeaver.inlineMethod(adviceMethod, enclosingMethod, adviceMethodInvocation); + + // now search through the advice, looking for a call to PROCEED. + // Then we replace the call to proceed with some argument setup, and a + // call to the extracted method. + String proceedName = + NameMangler.proceedMethodName(munger.getSignature().getName()); + + InstructionHandle curr = getRange().getStart(); + InstructionHandle end = getRange().getEnd(); + ConstantPoolGen cpg = extractedMethod.getEnclosingClass().getConstantPoolGen(); + while (curr != end) { + InstructionHandle next = curr.getNext(); + Instruction inst = curr.getInstruction(); + if ((inst instanceof INVOKESTATIC) + && proceedName.equals(((INVOKESTATIC) inst).getMethodName(cpg))) { + + + enclosingMethod.getBody().append(curr, getRedoneProceedCall(fact, extractedMethod, munger)); + Utility.deleteInstruction(curr, enclosingMethod); + } + curr = next; + } + // and that's it. + } + + private InstructionList getRedoneProceedCall( + InstructionFactory fact, + LazyMethodGen callbackMethod, + BcelAdvice munger) + { + InstructionList ret = new InstructionList(); + // we have on stack all the arguments for the ADVICE call. + // we have in frame somewhere all the arguments for the non-advice call. + + List argVarList = new ArrayList(); + + // start w/ stuff + if (targetVar != null) argVarList.add(targetVar); + for (int i = 0, len = getArgCount(); i < len; i++) { + argVarList.add(argVars[i]); + } + + BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(); + //??? this is too easy +// for (int i=0; i < adviceVars.length; i++) { +// if (adviceVars[i] != null) +// adviceVars[i].setPositionInAroundState(i); +// } + + + IntMap proceedMap = makeProceedArgumentMap(adviceVars); + +// System.out.println(proceedMap); +// System.out.println(Arrays.asList(adviceVars)); + + ResolvedTypeX[] proceedParamTypes = world.resolve(munger.getSignature().getParameterTypes()); + + BcelVar[] proceedVars = + Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, enclosingMethod); + + + Type[] stateTypes = callbackMethod.getArgumentTypes(); + + for (int i=0, len=stateTypes.length; i < len; i++) { + Type stateType = stateTypes[i]; + ResolvedTypeX stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); + if (proceedMap.hasKey(i)) { + //throw new RuntimeException("unimplemented"); + proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX); + } else { + ((BcelVar) argVarList.get(i)).appendLoad(ret, fact); + } + } + + ret.append(Utility.createInvoke(fact, callbackMethod)); + ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(), + BcelWorld.makeBcelType(munger.getSignature().getReturnType()))); + return ret; + } + + public void weaveAroundClosure( + BcelAdvice munger, + boolean hasDynamicTest) + { + InstructionFactory fact = getFactory(); + + // MOVE OUT ALL THE INSTRUCTIONS IN MY SHADOW INTO ANOTHER METHOD! + LazyMethodGen callbackMethod = + extractMethod( + NameMangler.aroundCallbackMethodName( + getSignature(), + getEnclosingClass())); + + BcelVar[] adviceVars = munger.getExposedStateAsBcelVars(); + + String closureClassName = + NameMangler.makeClosureClassName( + getEnclosingClass().getType(), + getEnclosingClass().getNewGeneratedNameTag()); + + Member constructorSig = new Member(Member.CONSTRUCTOR, + TypeX.forName(closureClassName), 0, "<init>", + "([Ljava/lang/Object;)V"); + + BcelVar closureHolder = null; + + // This is not being used currently since getKind() == preinitializaiton + // cannot happen in around advice + if (getKind() == PreInitialization) { + closureHolder = genTempVar(AjcMemberMaker.AROUND_CLOSURE_TYPE); + } + + InstructionList closureInstantiation = + makeClosureInstantiation(constructorSig, closureHolder); + + LazyMethodGen constructor = + makeClosureClassAndReturnConstructor( + closureClassName, + callbackMethod, + makeProceedArgumentMap(adviceVars) + ); + + InstructionList returnConversionCode; + if (getKind() == PreInitialization) { + returnConversionCode = new InstructionList(); + + BcelVar stateTempVar = genTempVar(TypeX.OBJECTARRAY); + closureHolder.appendLoad(returnConversionCode, fact); + + returnConversionCode.append( + Utility.createInvoke( + fact, + world, + AjcMemberMaker.aroundClosurePreInitializationGetter())); + stateTempVar.appendStore(returnConversionCode, fact); + + Type[] stateTypes = getSuperConstructorParameterTypes(); + + returnConversionCode.append(fact.ALOAD_0); // put "this" back on the stack + for (int i = 0, len = stateTypes.length; i < len; i++) { + stateTempVar.appendConvertableArrayLoad( + returnConversionCode, + fact, + i, + world.resolve(BcelWorld.fromBcel(stateTypes[i]))); + } + } else { + returnConversionCode = + Utility.createConversion( + getFactory(), + world.makeBcelType(munger.getSignature().getReturnType()), + callbackMethod.getReturnType()); + if (! isFallsThrough()) { + returnConversionCode.append(fact.createReturn(callbackMethod.getReturnType())); + } + } + + InstructionList advice = new InstructionList(); + advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation)); +// advice.append(closureInstantiation); + advice.append(munger.getNonTestAdviceInstructions(this)); + advice.append(returnConversionCode); + + if (! hasDynamicTest) { + range.append(advice); + } else { + InstructionList callback = makeCallToCallback(callbackMethod); + InstructionList postCallback = new InstructionList(); + if (! isExpressionKind()) { + callback.append(fact.createReturn(callbackMethod.getReturnType())); + } else { + advice.append(fact.createBranchInstruction(Constants.GOTO, postCallback.append(fact.NOP))); + } + range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart())); + range.append(advice); + range.append(callback); + range.append(postCallback); + } + } + + // XXX only used for testing + InstructionList makeCallToCallback(LazyMethodGen callbackMethod) { + InstructionFactory fact = getFactory(); + InstructionList callback = new InstructionList(); + if (targetVar != null) { + callback.append(BcelRenderer.renderExpr(fact, world, targetVar)); + } + callback.append(BcelRenderer.renderExprs(fact, world, argVars)); + callback.append(Utility.createInvoke(fact, callbackMethod)); + return callback; + } + + /** side-effect-free */ + private InstructionList makeClosureInstantiation(Member constructor, BcelVar holder) { + +// LazyMethodGen constructor) { + InstructionFactory fact = getFactory(); + BcelVar arrayVar = genTempVar(TypeX.OBJECTARRAY); + //final Type objectArrayType = new ArrayType(Type.OBJECT, 1); + final InstructionList il = new InstructionList(); + int alen = getArgCount() + (targetVar == null ? 0 : 1) + (thisJoinPointVar == null ? 0 : 1); + il.append(Utility.createConstant(fact, alen)); + il.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1)); + arrayVar.appendStore(il, fact); + + int stateIndex = 0; + if (targetVar != null) { + arrayVar.appendConvertableArrayStore(il, fact, stateIndex, targetVar); + targetVar.setPositionInAroundState(stateIndex); + stateIndex++; + } + for (int i = 0, len = getArgCount(); i<len; i++) { + arrayVar.appendConvertableArrayStore(il, fact, stateIndex, argVars[i]); + argVars[i].setPositionInAroundState(stateIndex); + stateIndex++; + } + if (thisJoinPointVar != null) { + arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisJoinPointVar); + thisJoinPointVar.setPositionInAroundState(stateIndex); + stateIndex++; + } + il.append(fact.createNew(new ObjectType(constructor.getDeclaringType().getName()))); + il.append(new DUP()); + arrayVar.appendLoad(il, fact); + il.append(Utility.createInvoke(fact, world, constructor)); + if (getKind() == PreInitialization) { + il.append(fact.DUP); + holder.appendStore(il, fact); + } + return il; + } + + + private IntMap makeProceedArgumentMap(BcelVar[] adviceArgs) { + //System.err.println("coming in with " + Arrays.asList(adviceArgs)); + + IntMap ret = new IntMap(); + for(int i = 0, len = adviceArgs.length; i < len; i++) { + BcelVar v = (BcelVar) adviceArgs[i]; + if (v == null) continue; // XXX we don't know why this is required + int pos = v.getPositionInAroundState(); + if (pos >= 0) { // need this test to avoid args bound via cflow + ret.put(pos, i); + } + } + //System.err.println("returning " + ret); + + return ret; + } + + /** + * + * + * @param callbackMethod the method we will call back to when our run method gets called. + * + * @param proceedMap A map from state position to proceed argument position. May be + * non covering on state position. + */ + + private LazyMethodGen makeClosureClassAndReturnConstructor( + String closureClassName, + LazyMethodGen callbackMethod, + IntMap proceedMap) + { + String superClassName = "org.aspectj.runtime.internal.AroundClosure"; + Type objectArrayType = new ArrayType(Type.OBJECT, 1); + + LazyClassGen closureClass = new LazyClassGen(closureClassName, + superClassName, + getEnclosingClass().getFileName(), + Modifier.PUBLIC, + new String[] {}); + InstructionFactory fact = new InstructionFactory(closureClass.getConstantPoolGen()); + + // constructor + LazyMethodGen constructor = new LazyMethodGen(Modifier.PUBLIC, + Type.VOID, + "<init>", + new Type[] {objectArrayType}, + new String[] {}, + closureClass); + InstructionList cbody = constructor.getBody(); + cbody.append(fact.createLoad(Type.OBJECT, 0)); + cbody.append(fact.createLoad(objectArrayType, 1)); + cbody.append(fact.createInvoke(superClassName, "<init>", Type.VOID, + new Type[] {objectArrayType}, Constants.INVOKESPECIAL)); + cbody.append(fact.createReturn(Type.VOID)); + + closureClass.addMethodGen(constructor); + + // method + LazyMethodGen runMethod = new LazyMethodGen(Modifier.PUBLIC, + Type.OBJECT, + "run", + new Type[] {objectArrayType}, + new String[] {}, + closureClass); + InstructionList mbody = runMethod.getBody(); + BcelVar proceedVar = new BcelVar(TypeX.OBJECTARRAY.resolve(world), 1); + // int proceedVarIndex = 1; + BcelVar stateVar = new BcelVar(TypeX.OBJECTARRAY.resolve(world), runMethod.allocateLocal(1)); + // int stateVarIndex = runMethod.allocateLocal(1); + mbody.append(fact.createThis()); + mbody.append(fact.createGetField(superClassName, "state", objectArrayType)); + mbody.append(stateVar.createStore(fact)); + // mbody.append(fact.createStore(objectArrayType, stateVarIndex)); + + Type[] stateTypes = callbackMethod.getArgumentTypes(); + + for (int i=0, len=stateTypes.length; i < len; i++) { + Type stateType = stateTypes[i]; + ResolvedTypeX stateTypeX = BcelWorld.fromBcel(stateType).resolve(world); + if (proceedMap.hasKey(i)) { + mbody.append( + proceedVar.createConvertableArrayLoad(fact, proceedMap.get(i), + stateTypeX)); + } else { + mbody.append( + stateVar.createConvertableArrayLoad(fact, i, + stateTypeX)); + } + } + + + mbody.append(Utility.createInvoke(fact, callbackMethod)); + + if (getKind() == PreInitialization) { + mbody.append(Utility.createSet( + fact, + AjcMemberMaker.aroundClosurePreInitializationField())); + mbody.append(fact.ACONST_NULL); + } else { + mbody.append( + Utility.createConversion( + fact, + callbackMethod.getReturnType(), + Type.OBJECT)); + } + mbody.append(fact.createReturn(Type.OBJECT)); + + closureClass.addMethodGen(runMethod); + + // class + getEnclosingClass().addGeneratedInner(closureClass); + + return constructor; + } + + // ---- extraction methods + + + public LazyMethodGen extractMethod(String newMethodName) { + LazyMethodGen.assertGoodBody(range.getBody(), newMethodName); + if (!getKind().allowsExtraction()) throw new BCException(); + LazyMethodGen freshMethod = createMethodGen(newMethodName); + +// System.err.println("******"); +// System.err.println("ABOUT TO EXTRACT METHOD for" + this); +// enclosingMethod.print(System.err); +// System.err.println("INTO"); +// freshMethod.print(System.err); +// System.err.println("WITH REMAP"); +// System.err.println(makeRemap()); + + range.extractInstructionsInto(freshMethod, makeRemap(), + (getKind() != PreInitialization) && + isFallsThrough()); + if (getKind() == PreInitialization) { + addPreInitializationReturnCode( + freshMethod, + getSuperConstructorParameterTypes()); + } + getEnclosingClass().addMethodGen(freshMethod); + + return freshMethod; + } + + private void addPreInitializationReturnCode( + LazyMethodGen extractedMethod, + Type[] superConstructorTypes) + { + InstructionList body = extractedMethod.getBody(); + final InstructionFactory fact = getFactory(); + + BcelVar arrayVar = new BcelVar( + world.resolve(TypeX.OBJECTARRAY), + extractedMethod.allocateLocal(1)); + + int len = superConstructorTypes.length; + + body.append(Utility.createConstant(fact, len)); + + body.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1)); + arrayVar.appendStore(body, fact); + + for (int i = len - 1; i >= 0; i++) { + // convert thing on top of stack to object + body.append( + Utility.createConversion(fact, superConstructorTypes[i], Type.OBJECT)); + // push object array + arrayVar.appendLoad(body, fact); + // swap + body.append(fact.SWAP); + // do object array store. + body.append(Utility.createConstant(fact, i)); + body.append(fact.SWAP); + body.append(fact.createArrayStore(Type.OBJECT)); + } + arrayVar.appendLoad(body, fact); + body.append(fact.ARETURN); + } + + private Type[] getSuperConstructorParameterTypes() { + // assert getKind() == PreInitialization + InstructionHandle superCallHandle = getRange().getEnd().getNext(); + InvokeInstruction superCallInstruction = + (InvokeInstruction) superCallHandle.getInstruction(); + return superCallInstruction.getArgumentTypes( + getEnclosingClass().getConstantPoolGen()); + } + + + /** make a map from old frame location to new frame location. Any unkeyed frame + * location picks out a copied local */ + private IntMap makeRemap() { + IntMap ret = new IntMap(5); + int reti = 0; + if (targetVar != null) { + ret.put(targetVar.getSlot(), reti++); + } + for (int i = 0, len = argVars.length; i < len; i++) { + ret.put(argVars[i].getSlot(), reti); + reti += argVars[i].getType().getSize(); + } + if (thisJoinPointVar != null) { + ret.put(thisJoinPointVar.getSlot(), reti++); + } + // we not only need to put the arguments, we also need to remap their + // aliases, which we so helpfully put into temps at the beginning of this join + // point. + if (! getKind().argsOnStack()) { + int index = 0; + if (hasThis()) { ret.put(0, 0); index++; } + for (int i = 0; i < getArgCount(); i++) { + TypeX type = getArgType(i); + ret.put(index, index); + index += type.getSize(); + } + } + return ret; + } + + /** + * The new method is nonStatic iff we're from nonExpression advice + * with an enclosing non-static method. + * Otherwise, it's static + */ + private LazyMethodGen createMethodGen(String newMethodName) { + Type[] parameterTypes = world.makeBcelTypes(getSignature().getParameterTypes()); + int modifiers = Modifier.FINAL; + + // XXX some bug +// if (! isExpressionKind() && getSignature().isStrict(world)) { +// modifiers |= Modifier.STRICT; +// } + modifiers |= Modifier.STATIC; + if (hasTarget()) { + TypeX targetType = getTargetType(); + parameterTypes = addType(world.makeBcelType(targetType), parameterTypes); + } + + // We always want to pass down thisJoinPoint in case we have already woven + // some advice in here. If we only have a single piece of around advice on a + // join point, it is unnecessary to accept (and pass) tjp. + if (thisJoinPointVar != null) { + parameterTypes = addTypeToEnd(LazyClassGen.tjpType, parameterTypes); + } + + TypeX returnType; + if (getKind() == ConstructorCall) { + returnType = getSignature().getDeclaringType(); + } else if (getKind() == PreInitialization) { + returnType = TypeX.OBJECTARRAY; + } else { + returnType = getSignature().getReturnType(); + } + return + new LazyMethodGen( + modifiers, + world.makeBcelType(returnType), + newMethodName, + parameterTypes, + new String[0], + // XXX again, we need to look up methods! +// TypeX.getNames(getSignature().getExceptions(world)), + getEnclosingClass()); + } + + private Type[] addType(Type type, Type[] types) { + int len = types.length; + Type[] ret = new Type[len+1]; + ret[0] = type; + System.arraycopy(types, 0, ret, 1, len); + return ret; + } + + private Type[] addTypeToEnd(Type type, Type[] types) { + int len = types.length; + Type[] ret = new Type[len+1]; + ret[len] = type; + System.arraycopy(types, 0, ret, 0, len); + return ret; + } + + public BcelVar genTempVar(TypeX typeX) { + return new BcelVar(typeX.resolve(world), genTempVarIndex(typeX.getSize())); + } + +// public static final boolean CREATE_TEMP_NAMES = true; + + public BcelVar genTempVar(TypeX typeX, String localName) { + BcelVar tv = genTempVar(typeX); + +// if (CREATE_TEMP_NAMES) { +// for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) { +// if (Range.isRangeHandle(ih)) continue; +// ih.addTargeter(new LocalVariableTag(typeX, localName, tv.getSlot())); +// } +// } + return tv; + } + + // eh doesn't think we need to garbage collect these (64K is a big number...) + private int genTempVarIndex(int size) { + return enclosingMethod.allocateLocal(size); + } + + public InstructionFactory getFactory() { + return getEnclosingClass().getFactory(); + } + + public SourceLocation getSourceLocation() { + return new SourceLocation(new File(getEnclosingClass().getFileName()), getSourceLine()); + } + + public BcelShadow getEnclosingShadow() { + return enclosingShadow; + } + + public LazyMethodGen getEnclosingMethod() { + return enclosingMethod; + } + + public boolean isFallsThrough() { + return fallsThrough; + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelSourceContext.java b/weaver/src/org/aspectj/weaver/bcel/BcelSourceContext.java new file mode 100644 index 000000000..aedfe074b --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelSourceContext.java @@ -0,0 +1,55 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.File; +import java.util.Arrays; + +import org.aspectj.bridge.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ISourceContext; +import org.aspectj.weaver.AjAttribute.SourceContextAttribute; + +public class BcelSourceContext implements ISourceContext { + private BcelObjectType inObject; + private String sourceFileName; + private int[] lineBreaks; + + public BcelSourceContext(BcelObjectType inObject) { + this.inObject = inObject; + } + + + public ISourceLocation makeSourceLocation(IHasPosition position) { + String fileName = sourceFileName; + if (fileName == null) inObject.getJavaClass().getFileName(); + if (fileName == null) fileName = inObject.getName() + ".class"; + + if (lineBreaks != null) { + int line = Arrays.binarySearch(lineBreaks, position.getStart()); + if (line < 0) line = -line; + return new SourceLocation(new File(fileName), line); //??? have more info + } else { + return new SourceLocation(new File(fileName), 0); + } + } + + + + public void addAttributeInfo(SourceContextAttribute sourceContextAttribute) { + this.sourceFileName = sourceContextAttribute.getSourceFileName(); + this.lineBreaks = sourceContextAttribute.getLineBreaks(); + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java b/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java new file mode 100644 index 000000000..a14f0e0b3 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java @@ -0,0 +1,566 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.lang.reflect.Modifier; +import java.util.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.patterns.*; + + +//XXX addLazyMethodGen is probably bad everywhere +public class BcelTypeMunger extends ConcreteTypeMunger { + + public BcelTypeMunger(ResolvedTypeMunger munger, ResolvedTypeX aspectType) { + super(munger, aspectType); + } + + public String toString() { + return "(BcelTypeMunger " + getMunger() + ")"; + } + + public boolean munge(BcelClassWeaver weaver) { + if (munger.getKind() == ResolvedTypeMunger.Field) { + return mungeNewField(weaver, (NewFieldTypeMunger)munger); + } else if (munger.getKind() == ResolvedTypeMunger.Method) { + return mungeNewMethod(weaver, (NewMethodTypeMunger)munger); + } else if (munger.getKind() == ResolvedTypeMunger.PerObjectInterface) { + return mungePerObjectInterface(weaver, (PerObjectInterfaceTypeMunger)munger); + } else if (munger.getKind() == ResolvedTypeMunger.PrivilegedAccess) { + return mungePrivilegedAccess(weaver, (PrivilegedAccessMunger)munger); + } else if (munger.getKind() == ResolvedTypeMunger.Constructor) { + return mungeNewConstructor(weaver, (NewConstructorTypeMunger)munger); + } else { + throw new RuntimeException("unimplemented"); + } + } + + + + private boolean mungePrivilegedAccess( + BcelClassWeaver weaver, + PrivilegedAccessMunger munger) + { + LazyClassGen gen = weaver.getLazyClassGen(); + ResolvedMember member = munger.getMember(); + + ResolvedTypeX onType = weaver.getWorld().resolve(member.getDeclaringType()); + //System.out.println("munging: " + gen + " with " + member); + if (onType.equals(gen.getType())) { + if (member.getKind() == Member.FIELD) { + //System.out.println("matched: " + gen); + addFieldGetter(gen, member, + AjcMemberMaker.privilegedAccessMethodForFieldGet(aspectType, member)); + addFieldSetter(gen, member, + AjcMemberMaker.privilegedAccessMethodForFieldSet(aspectType, member)); + return true; + } else if (member.getKind() == Member.METHOD) { + addMethodDispatch(gen, member, + AjcMemberMaker.privilegedAccessMethodForMethod(aspectType, member)); + } else { + throw new RuntimeException("unimplemented"); + } + } + return false; + } + + private void addFieldGetter( + LazyClassGen gen, + ResolvedMember field, + ResolvedMember accessMethod) + { + LazyMethodGen mg = makeMethodGen(gen, accessMethod); + InstructionList il = new InstructionList(); + InstructionFactory fact = gen.getFactory(); + if (field.isStatic()) { + il.append(fact.createFieldAccess( + gen.getClassName(), + field.getName(), + BcelWorld.makeBcelType(field.getType()), Constants.GETSTATIC)); + } else { + il.append(fact.ALOAD_0); + il.append(fact.createFieldAccess( + gen.getClassName(), + field.getName(), + BcelWorld.makeBcelType(field.getType()), Constants.GETFIELD)); + } + il.append(fact.createReturn(BcelWorld.makeBcelType(field.getType()))); + mg.getBody().insert(il); + + gen.addMethodGen(mg); + } + + private void addFieldSetter( + LazyClassGen gen, + ResolvedMember field, + ResolvedMember accessMethod) + { + LazyMethodGen mg = makeMethodGen(gen, accessMethod); + InstructionList il = new InstructionList(); + InstructionFactory fact = gen.getFactory(); + Type fieldType = BcelWorld.makeBcelType(field.getType()); + + if (field.isStatic()) { + il.append(fact.createLoad(fieldType, 0)); + il.append(fact.createFieldAccess( + gen.getClassName(), + field.getName(), + fieldType, Constants.PUTSTATIC)); + } else { + il.append(fact.ALOAD_0); + il.append(fact.createLoad(fieldType, 1)); + il.append(fact.createFieldAccess( + gen.getClassName(), + field.getName(), + fieldType, Constants.PUTFIELD)); + } + il.append(fact.createReturn(Type.VOID)); + mg.getBody().insert(il); + + gen.addMethodGen(mg); + } + + private void addMethodDispatch( + LazyClassGen gen, + ResolvedMember method, + ResolvedMember accessMethod) + { + LazyMethodGen mg = makeMethodGen(gen, accessMethod); + InstructionList il = new InstructionList(); + InstructionFactory fact = gen.getFactory(); + //Type fieldType = BcelWorld.makeBcelType(field.getType()); + Type[] paramTypes = BcelWorld.makeBcelTypes(method.getParameterTypes()); + + int pos = 0; + + if (!method.isStatic()) { + il.append(fact.ALOAD_0); + pos++; + } + for (int i = 0, len = paramTypes.length; i < len; i++) { + Type paramType = paramTypes[i]; + il.append(fact.createLoad(paramType, pos)); + pos+=paramType.getSize(); + } + il.append(Utility.createInvoke(fact, (BcelWorld)aspectType.getWorld(), + method)); + il.append(fact.createReturn(BcelWorld.makeBcelType(method.getReturnType()))); + + mg.getBody().insert(il); + + gen.addMethodGen(mg); + } + + + + private LazyMethodGen makeMethodGen(LazyClassGen gen, ResolvedMember member) { + return new LazyMethodGen( + member.getModifiers(), + BcelWorld.makeBcelType(member.getReturnType()), + member.getName(), + BcelWorld.makeBcelTypes(member.getParameterTypes()), + TypeX.getNames(member.getExceptions()), + gen); + } + + + private FieldGen makeFieldGen(LazyClassGen gen, ResolvedMember member) { + return new FieldGen( + member.getModifiers(), + BcelWorld.makeBcelType(member.getReturnType()), + member.getName(), + gen.getConstantPoolGen()); + } + + + + + private boolean mungePerObjectInterface( + BcelClassWeaver weaver, + PerObjectInterfaceTypeMunger munger) + { + LazyClassGen gen = weaver.getLazyClassGen(); + + if (couldMatch(gen.getType(), munger.getTestPointcut())) { + FieldGen fg = makeFieldGen(gen, + AjcMemberMaker.perObjectField(gen.getType(), aspectType)); + + gen.addField(fg.getField()); + + + Type fieldType = BcelWorld.makeBcelType(aspectType); + LazyMethodGen mg = new LazyMethodGen( + Modifier.PUBLIC, + fieldType, + NameMangler.perObjectInterfaceGet(aspectType), + new Type[0], new String[0], + gen); + InstructionList il = new InstructionList(); + InstructionFactory fact = gen.getFactory(); + il.append(fact.ALOAD_0); + il.append(fact.createFieldAccess( + gen.getClassName(), + fg.getName(), + fieldType, Constants.GETFIELD)); + il.append(fact.createReturn(fieldType)); + mg.getBody().insert(il); + + gen.addMethodGen(mg); + + LazyMethodGen mg1 = new LazyMethodGen( + Modifier.PUBLIC, + Type.VOID, + NameMangler.perObjectInterfaceSet(aspectType), + + new Type[]{fieldType,}, new String[0], + gen); + InstructionList il1 = new InstructionList(); + il1.append(fact.ALOAD_0); + il1.append(fact.createLoad(fieldType, 1)); + il1.append(fact.createFieldAccess( + gen.getClassName(), + fg.getName(), + fieldType, Constants.PUTFIELD)); + il1.append(fact.createReturn(Type.VOID)); + mg1.getBody().insert(il1); + + gen.addMethodGen(mg1); + + gen.addInterface(munger.getInterfaceType()); + + return true; + } else { + return false; + } + } + + private boolean couldMatch( + BcelObjectType bcelObjectType, + Pointcut pointcut) { + return !bcelObjectType.isInterface(); + } + + private boolean mungeNewMethod(BcelClassWeaver weaver, NewMethodTypeMunger munger) { + ResolvedMember signature = munger.getSignature(); + ResolvedMember dispatchMethod = munger.getDispatchMethod(aspectType); + + LazyClassGen gen = weaver.getLazyClassGen(); + + ResolvedTypeX onType = weaver.getWorld().resolve(signature.getDeclaringType()); + boolean onInterface = onType.isInterface(); + + if (onType.equals(gen.getType())) { + ResolvedMember introMethod = + AjcMemberMaker.interMethod(signature, aspectType, onInterface); + + LazyMethodGen mg = makeMethodGen(gen, introMethod); + + if (!onInterface && !Modifier.isAbstract(introMethod.getModifiers())) { + InstructionList body = mg.getBody(); + InstructionFactory fact = gen.getFactory(); + int pos = 0; + + if (!signature.isStatic()) { + body.append(fact.createThis()); + pos++; + } + Type[] paramTypes = BcelWorld.makeBcelTypes(introMethod.getParameterTypes()); + for (int i = 0, len = paramTypes.length; i < len; i++) { + Type paramType = paramTypes[i]; + body.append(fact.createLoad(paramType, pos)); + pos+=paramType.getSize(); + } + body.append(Utility.createInvoke(fact, weaver.getWorld(), dispatchMethod)); + body.append(fact.createReturn(BcelWorld.makeBcelType(introMethod.getReturnType()))); + } else { + //??? this is okay + //if (!(mg.getBody() == null)) throw new RuntimeException("bas"); + } + + + // XXX make sure to check that we set exceptions properly on this guy. + weaver.addLazyMethodGen(mg); + + Set neededSuperCalls = munger.getSuperMethodsCalled(); + + for (Iterator iter = neededSuperCalls.iterator(); iter.hasNext(); ) { + ResolvedMember superMethod = (ResolvedMember) iter.next(); + if (weaver.addDispatchTarget(superMethod)) { + String dispatchName = genSuperDispatchName(onType, superMethod); + LazyMethodGen dispatcher = makeDispatcher(gen, dispatchName, superMethod, weaver.getWorld()); + + weaver.addLazyMethodGen(dispatcher); + } + } + + return true; + } else if (onInterface && gen.getType().isTopmostImplementor(onType) && + !Modifier.isAbstract(signature.getModifiers())) + { + ResolvedMember introMethod = + AjcMemberMaker.interMethod(signature, aspectType, false); + + LazyMethodGen mg = makeMethodGen(gen, introMethod); + + // + + Type[] paramTypes = BcelWorld.makeBcelTypes(introMethod.getParameterTypes()); + Type returnType = BcelWorld.makeBcelType(introMethod.getReturnType()); + + InstructionList body = mg.getBody(); + InstructionFactory fact = gen.getFactory(); + int pos = 0; + + if (!introMethod.isStatic()) { + body.append(fact.createThis()); + pos++; + } + for (int i = 0, len = paramTypes.length; i < len; i++) { + Type paramType = paramTypes[i]; + body.append(fact.createLoad(paramType, pos)); + pos+=paramType.getSize(); + } + body.append(Utility.createInvoke(fact, weaver.getWorld(), dispatchMethod)); + body.append(fact.createReturn(returnType)); + mg.definingType = onType; + + weaver.addOrReplaceLazyMethodGen(mg); + + return true; + } else { + return false; + } + } + + + private boolean mungeNewConstructor( + BcelClassWeaver weaver, + NewConstructorTypeMunger newConstructorTypeMunger) + { + final LazyClassGen currentClass = weaver.getLazyClassGen(); + final InstructionFactory fact = currentClass.getFactory(); + + ResolvedMember newConstructorMember = newConstructorTypeMunger.getSyntheticConstructor(); + TypeX onType = newConstructorMember.getDeclaringType(); + + + if (! onType.equals(currentClass.getType())) return false; + + ResolvedMember explicitConstructor = newConstructorTypeMunger.getExplicitConstructor(); + //int declaredParameterCount = newConstructorTypeMunger.getDeclaredParameterCount(); + LazyMethodGen freshConstructor = + makeMethodGen(currentClass, newConstructorMember); + currentClass.addMethodGen(freshConstructor); + //weaver.addLazyMethodGen(freshConstructor); + + InstructionList body = freshConstructor.getBody(); + + // add to body: push arts for call to pre, from actual args starting at 1 (skipping this), going to + // declared argcount + 1 + TypeX[] declaredParams = newConstructorTypeMunger.getSignature().getParameterTypes(); + Type[] paramTypes = freshConstructor.getArgumentTypes(); + int frameIndex = 1; + for (int i = 0, len = declaredParams.length; i < len; i++) { + body.append(fact.createLoad(paramTypes[i], frameIndex)); + frameIndex += paramTypes[i].getSize(); + } + // do call to pre + Member preMethod = AjcMemberMaker.preIntroducedConstructor(aspectType, onType, declaredParams); + body.append(Utility.createInvoke(fact, null, preMethod)); + + // create a local, and store return pre stuff into it. + int arraySlot = freshConstructor.allocateLocal(1); + body.append(fact.createStore(Type.OBJECT, arraySlot)); + + // put this on the stack + body.append(fact.ALOAD_0); + + // unpack pre args onto stack + TypeX[] superParamTypes = explicitConstructor.getParameterTypes(); + + for (int i = 0, len = superParamTypes.length; i < len; i++) { + body.append(fact.createLoad(Type.OBJECT, arraySlot)); + body.append(Utility.createConstant(fact, i)); + body.append(fact.createArrayLoad(Type.OBJECT)); + body.append(Utility.createConversion(fact, Type.OBJECT, BcelWorld.makeBcelType(superParamTypes[i]))); + } + + // call super/this + + body.append(Utility.createInvoke(fact, null, explicitConstructor)); + + // put this back on the stack + + body.append(fact.ALOAD_0); + + // unpack params onto stack + Member postMethod = AjcMemberMaker.postIntroducedConstructor(aspectType, onType, declaredParams); + TypeX[] postParamTypes = postMethod.getParameterTypes(); + + for (int i = 1, len = postParamTypes.length; i < len; i++) { + body.append(fact.createLoad(Type.OBJECT, arraySlot)); + body.append(Utility.createConstant(fact, superParamTypes.length + i-1)); + body.append(fact.createArrayLoad(Type.OBJECT)); + body.append(Utility.createConversion(fact, Type.OBJECT, BcelWorld.makeBcelType(postParamTypes[i]))); + } + + // call post + body.append(Utility.createInvoke(fact, null, postMethod)); + + // don't forget to return!! + + body.append(fact.RETURN); + + return true; + } + + + private static LazyMethodGen makeDispatcher( + LazyClassGen onGen, + String dispatchName, + ResolvedMember superMethod, + BcelWorld world) + { + Type[] paramTypes = BcelWorld.makeBcelTypes(superMethod.getParameterTypes()); + Type returnType = BcelWorld.makeBcelType(superMethod.getReturnType()); + + LazyMethodGen mg = + new LazyMethodGen( + Modifier.PUBLIC, + returnType, + dispatchName, + paramTypes, + TypeX.getNames(superMethod.getExceptions()), + onGen); + InstructionList body = mg.getBody(); + + // assert (!superMethod.isStatic()) + InstructionFactory fact = onGen.getFactory(); + int pos = 0; + + body.append(fact.createThis()); + pos++; + for (int i = 0, len = paramTypes.length; i < len; i++) { + Type paramType = paramTypes[i]; + body.append(fact.createLoad(paramType, pos)); + pos+=paramType.getSize(); + } + body.append(Utility.createSuperInvoke(fact, world, superMethod)); + body.append(fact.createReturn(returnType)); + + return mg; + } + + + private static String genSuperDispatchName( + ResolvedTypeX onType, + ResolvedMember superMethod) + { + return "ajc$" + ResolvedTypeMunger.SUPER_DISPATCH_NAME + "$" + onType.getNameAsIdentifier() + "$" + superMethod.getName(); + } + + + + private boolean mungeNewField(BcelClassWeaver weaver, NewFieldTypeMunger munger) { + ResolvedMember initMethod = munger.getInitMethod(aspectType); + + LazyClassGen gen = weaver.getLazyClassGen(); + ResolvedMember field = munger.getSignature(); + + + ResolvedTypeX onType = weaver.getWorld().resolve(field.getDeclaringType()); + boolean onInterface = onType.isInterface(); + + if (onType.equals(gen.getType())) { + if (onInterface) { + LazyMethodGen mg = makeMethodGen(gen, + AjcMemberMaker.interFieldInterfaceGetter(field, onType, aspectType)); + gen.addMethodGen(mg); + + LazyMethodGen mg1 = makeMethodGen(gen, + AjcMemberMaker.interFieldInterfaceSetter(field, onType, aspectType)); + gen.addMethodGen(mg1); + } else { + weaver.addInitializer(this); + FieldGen fg = makeFieldGen(gen, + AjcMemberMaker.interFieldClassField(field, aspectType)); + gen.addField(fg.getField()); + } + return true; + } else if (onInterface && gen.getType().isTopmostImplementor(onType)) { + // wew know that we can't be static since we don't allow statics on interfaces + if (field.isStatic()) throw new RuntimeException("unimplemented"); + weaver.addInitializer(this); + //System.err.println("impl body on " + gen.getType() + " for " + munger); + Type fieldType = BcelWorld.makeBcelType(field.getType()); + + FieldGen fg = makeFieldGen(gen, + AjcMemberMaker.interFieldInterfaceField(field, onType, aspectType)); + gen.addField(fg.getField()); + + //this uses a shadow munger to add init method to constructors + //weaver.getShadowMungers().add(makeInitCallShadowMunger(initMethod)); + + LazyMethodGen mg = makeMethodGen(gen, + AjcMemberMaker.interFieldInterfaceGetter(field, gen.getType(), aspectType)); + InstructionList il = new InstructionList(); + InstructionFactory fact = gen.getFactory(); + if (field.isStatic()) { + il.append(fact.createFieldAccess( + gen.getClassName(), + fg.getName(), + fieldType, Constants.GETSTATIC)); + } else { + il.append(fact.ALOAD_0); + il.append(fact.createFieldAccess( + gen.getClassName(), + fg.getName(), + fieldType, Constants.GETFIELD)); + } + il.append(fact.createReturn(fieldType)); + mg.getBody().insert(il); + + gen.addMethodGen(mg); + + LazyMethodGen mg1 = makeMethodGen(gen, + AjcMemberMaker.interFieldInterfaceSetter(field, gen.getType(), aspectType)); + InstructionList il1 = new InstructionList(); + if (field.isStatic()) { + il1.append(fact.createLoad(fieldType, 0)); + il1.append(fact.createFieldAccess( + gen.getClassName(), + fg.getName(), + fieldType, Constants.PUTSTATIC)); + } else { + il1.append(fact.ALOAD_0); + il1.append(fact.createLoad(fieldType, 1)); + il1.append(fact.createFieldAccess( + gen.getClassName(), + fg.getName(), + fieldType, Constants.PUTFIELD)); + } + il1.append(fact.createReturn(Type.VOID)); + mg1.getBody().insert(il1); + + gen.addMethodGen(mg1); + + return true; + } else { + return false; + } + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelVar.java b/weaver/src/org/aspectj/weaver/bcel/BcelVar.java new file mode 100644 index 000000000..8423e9c79 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelVar.java @@ -0,0 +1,126 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; +import org.aspectj.weaver.ast.Var; + +public class BcelVar extends Var { + + private int positionInAroundState = -1; + + private int slot; + + public BcelVar(ResolvedTypeX type, int slot) { + super(type); + this.slot = slot; + } + + public String toString() { + return "BcelVar(" + getType() + " " + slot + + ((positionInAroundState != -1) ? (" " + positionInAroundState) : "") + + + ")"; + } + + public int getSlot() { return slot; } + + public Instruction createLoad(InstructionFactory fact) { + return fact.createLoad(BcelWorld.makeBcelType(getType()), slot); + } + public Instruction createStore(InstructionFactory fact) { + return fact.createStore(BcelWorld.makeBcelType(getType()), slot); + } + + public void appendStore(InstructionList il, InstructionFactory fact) { + il.append(createStore(fact)); + } + public void appendLoad(InstructionList il, InstructionFactory fact) { + il.append(createLoad(fact)); + } + public void appendLoadAndConvert(InstructionList il, InstructionFactory fact, ResolvedTypeX toType) { + il.append(createLoad(fact)); + Utility.appendConversion(il, fact, getType(), toType); + } + public void insertLoad(InstructionList il, InstructionFactory fact) { + il.insert(createLoad(fact)); + } + public InstructionList createCopyFrom(InstructionFactory fact, int oldSlot) { + InstructionList il = new InstructionList(); + il.append(fact.createLoad(BcelWorld.makeBcelType(getType()), oldSlot)); + il.append(createStore(fact)); + return il; + } + + // this is an array var + void appendConvertableArrayLoad( + InstructionList il, + InstructionFactory fact, + int index, + ResolvedTypeX convertTo) + { + ResolvedTypeX convertFromType = getType().getResolvedComponentType(); + appendLoad(il, fact); + il.append(Utility.createConstant(fact, index)); + il.append(fact.createArrayLoad(BcelWorld.makeBcelType(convertFromType))); + Utility.appendConversion(il, fact, convertFromType, convertTo); + } + + void appendConvertableArrayStore( + InstructionList il, + InstructionFactory fact, + int index, + BcelVar storee) + { + ResolvedTypeX convertToType = getType().getResolvedComponentType(); + appendLoad(il, fact); + il.append(Utility.createConstant(fact, index)); + storee.appendLoad(il, fact); + Utility.appendConversion(il, fact, storee.getType(), convertToType); + il.append(fact.createArrayStore(BcelWorld.makeBcelType(convertToType))); + } + + InstructionList createConvertableArrayStore( + InstructionFactory fact, + int index, + BcelVar storee) + { + InstructionList il = new InstructionList(); + appendConvertableArrayStore(il, fact, index, storee); + return il; + } + InstructionList createConvertableArrayLoad( + InstructionFactory fact, + int index, + ResolvedTypeX convertTo) + { + InstructionList il = new InstructionList(); + appendConvertableArrayLoad(il, fact, index, convertTo); + return il; + } + public int getPositionInAroundState() { + return positionInAroundState; + } + + public void setPositionInAroundState(int positionInAroundState) { + this.positionInAroundState = positionInAroundState; + } + + // random useful fields + + public static final BcelVar[] NONE = new BcelVar[] {}; + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java new file mode 100644 index 000000000..63eb043d5 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWeaver.java @@ -0,0 +1,374 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.util.*; +import java.util.zip.*; + +import org.apache.bcel.classfile.*; +import org.apache.bcel.classfile.JavaClass; +import org.aspectj.util.FileUtil; +import org.aspectj.weaver.*; + +public class BcelWeaver implements IWeaver { + private BcelWorld world; + private CrosscuttingMembersSet xcutSet; + + public BcelWeaver(BcelWorld world) { + super(); + this.world = world; + this.xcutSet = world.getCrosscuttingMembersSet(); + } + + public BcelWeaver() { + this(new BcelWorld()); + } + + // ---- fields + private Map sourceJavaClasses = new HashMap(); /* String -> UnwovenClassFile */ + private List addedClasses = new ArrayList(); /* List<UnovenClassFile> */ + private List deletedTypenames = new ArrayList(); /* List<String> */ + private boolean needToReweaveWorld = false; + + private List shadowMungerList = null; // setup by prepareForWeave + private List typeMungerList = null; // setup by prepareForWeave + + private ZipOutputStream zipOutputStream; + + // ---- + + // only called for testing + public void setShadowMungers(List l) { + shadowMungerList = l; + } + + + public void addLibraryAspect(String aspectName) { + ResolvedTypeX type = world.resolve(aspectName); + System.out.println("type: " + type + " for " + aspectName); + if (type.isAspect()) { + xcutSet.addOrReplaceAspect(type); + } else { + throw new RuntimeException("unimplemented"); + } + } + + + + public void addLibraryJarFile(File inFile) throws IOException { + ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); //??? buffered + + List addedAspects = new ArrayList(); + + while (true) { + ZipEntry entry = inStream.getNextEntry(); + if (entry == null) break; + + if (entry.isDirectory() || !entry.getName().endsWith(".class")) { + continue; + } + + ClassParser parser = new ClassParser(new ByteArrayInputStream(FileUtil.readAsByteArray(inStream)), entry.getName()); + JavaClass jc = parser.parse(); + inStream.closeEntry(); + + ResolvedTypeX type = world.addSourceObjectType(jc); + if (type.isAspect()) { + addedAspects.add(type); + } + + } + + inStream.close(); + + for (Iterator i = addedAspects.iterator(); i.hasNext();) { + ResolvedTypeX aspectX = (ResolvedTypeX) i.next(); + xcutSet.addOrReplaceAspect(aspectX); + } + } + + + /** Adds all class files in the jar + */ + public void addJarFile(File inFile, File outDir) throws IOException { + needToReweaveWorld = true; + //System.err.println("adding jar: " + inFile); + ZipInputStream inStream = new ZipInputStream(new FileInputStream(inFile)); //??? buffered + + while (true) { + ZipEntry entry = inStream.getNextEntry(); + if (entry == null) break; + + if (entry.isDirectory() || !entry.getName().endsWith(".class")) { + continue; //??? need to pass other things along untouched +// outStream.putNextEntry(entry); +// outStream.write(Utility.getByteArray(inStream)); +// outStream.closeEntry(); +// return; + } + //System.err.println("adding class: " + entry.getName()); + + byte[] bytes = FileUtil.readAsByteArray(inStream); + String filename = entry.getName(); + UnwovenClassFile classFile = new UnwovenClassFile(new File(outDir, filename).getAbsolutePath(), bytes); + inStream.closeEntry(); + this.addClassFile(classFile); + } + + inStream.close(); + } + + + /** Should be addOrReplace + */ + public void addClassFile(UnwovenClassFile classFile) { + addedClasses.add(classFile); + sourceJavaClasses.put(classFile.getClassName(), classFile); + world.addSourceObjectType(classFile.getJavaClass()); + } + + + public void deleteClassFile(String typename) { + deletedTypenames.add(typename); + sourceJavaClasses.remove(typename); + world.deleteSourceObjectType(TypeX.forName(typename)); + } + + // ---- weave preparation + + public void prepareForWeave() { + needToReweaveWorld = false; + + + // update mungers + for (Iterator i = addedClasses.iterator(); i.hasNext(); ) { + UnwovenClassFile jc = (UnwovenClassFile)i.next(); + String name = jc.getClassName(); + ResolvedTypeX type = world.resolve(name); + if (type.isAspect()) { + needToReweaveWorld |= xcutSet.addOrReplaceAspect(type); + } + } + + for (Iterator i = deletedTypenames.iterator(); i.hasNext(); ) { + String name = (String)i.next(); + xcutSet.deleteAspect(TypeX.forName(name)); + needToReweaveWorld = true; + } + + shadowMungerList = xcutSet.getShadowMungers(); + typeMungerList = xcutSet.getTypeMungers(); + + //XXX this gets us a stable (but completely meaningless) order + Collections.sort( + shadowMungerList, + new Comparator() { + public int compare(Object o1, Object o2) { + return o1.toString().compareTo(o2.toString()); + } + }); + } + + public void dumpUnwoven(File file) throws IOException { + BufferedOutputStream os = FileUtil.makeOutputStream(file); + this.zipOutputStream = new ZipOutputStream(os); + dumpUnwoven(); + zipOutputStream.close(); //this flushes and closes the acutal file + } + + + public void dumpUnwoven() throws IOException { + Collection filesToDump = new HashSet(sourceJavaClasses.values()); + for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { + UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + dumpUnchanged(classFile); + } + } + + + // ---- weaving + + public Collection weave(File file) throws IOException { + OutputStream os = FileUtil.makeOutputStream(file); + this.zipOutputStream = new ZipOutputStream(os); + Collection c = weave(); + zipOutputStream.close(); //this flushes and closes the acutal file + return c; + } + + public Collection weave() throws IOException { + prepareForWeave(); + Collection filesToWeave; + if (needToReweaveWorld) { + filesToWeave = sourceJavaClasses.values(); + } else { + filesToWeave = addedClasses; + } + + Collection wovenClassNames = new ArrayList(); + + //XXX this isn't quite the right place for this... + for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { + UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + String className = classFile.getClassName(); + ResolvedTypeX onType = world.resolve(className); + weave(onType); + } + + // first weave into aspects + for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { + UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + String className = classFile.getClassName(); + BcelObjectType classType = (BcelObjectType) world.resolve(className); + if (classType.isAspect()) { + weave(classFile, classType); + wovenClassNames.add(className); + } + } + + // then weave into non-aspects + for (Iterator i = filesToWeave.iterator(); i.hasNext(); ) { + UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + String className = classFile.getClassName(); + BcelObjectType classType = (BcelObjectType) world.resolve(className); + if (! classType.isAspect()) { + weave(classFile, classType); + wovenClassNames.add(className); + } + } + + if (zipOutputStream != null && !needToReweaveWorld) { + Collection filesToDump = new HashSet(sourceJavaClasses.values()); + filesToDump.removeAll(filesToWeave); + for (Iterator i = filesToDump.iterator(); i.hasNext(); ) { + UnwovenClassFile classFile = (UnwovenClassFile)i.next(); + dumpUnchanged(classFile); + } + } + + addedClasses = new ArrayList(); + deletedTypenames = new ArrayList(); + + return wovenClassNames; + } + + private void weave(ResolvedTypeX onType) { + onType.clearInterTypeMungers(); + for (Iterator i = typeMungerList.iterator(); i.hasNext(); ) { + ConcreteTypeMunger m = (ConcreteTypeMunger)i.next(); + if (m.matches(onType)) { + onType.addInterTypeMunger(m); + } + } + } + + + // non-private for testing + LazyClassGen weave(UnwovenClassFile classFile, BcelObjectType classType) throws IOException { + JavaClass javaClass = classType.getJavaClass(); + List shadowMungers = fastMatch(shadowMungerList, javaClass); + List typeMungers = fastMatch(classType.getInterTypeMungers(), javaClass); + + LazyClassGen clazz = null; + + if (shadowMungers.size() > 0 || typeMungers.size() > 0) { + clazz = classType.getLazyClassGen(); + try { + boolean isChanged = BcelClassWeaver.weave(world, clazz, shadowMungers, typeMungers); + if (isChanged) { + dump(classFile, clazz); + return clazz; + } + } catch (RuntimeException re) { + System.err.println("trouble in: "); + clazz.print(System.err); + throw re; + } catch (Error re) { + System.err.println("trouble in: "); + clazz.print(System.err); + throw re; + } + } + + dumpUnchanged(classFile); + return clazz; + } + + // ---- writing + + private void dumpUnchanged(UnwovenClassFile classFile) throws IOException { + if (zipOutputStream != null) { + writeZipEntry(getEntryName(classFile.getJavaClass().getClassName()), classFile.getBytes()); + } else { + classFile.writeUnchangedBytes(); + } + } + + private String getEntryName(String className) { + //XXX what does bcel's getClassName do for inner names + return className.replace('.', '/') + ".class"; + } + + private void dump(UnwovenClassFile classFile, LazyClassGen clazz) throws IOException { + if (zipOutputStream != null) { + String mainClassName = classFile.getJavaClass().getClassName(); + + writeZipEntry(getEntryName(mainClassName), + clazz.getJavaClass().getBytes()); + if (!clazz.getChildClasses().isEmpty()) { + for (Iterator i = clazz.getChildClasses().iterator(); i.hasNext();) { + UnwovenClassFile.ChildClass c = (UnwovenClassFile.ChildClass) i.next(); + writeZipEntry(getEntryName(mainClassName + "$" + c.name), c.bytes); + } + } + } else { + classFile.writeWovenBytes( + clazz.getJavaClass().getBytes(), + clazz.getChildClasses() + ); + } + } + + private void writeZipEntry(String name, byte[] bytes) throws IOException { + ZipEntry newEntry = new ZipEntry(name); //??? get compression scheme right + + zipOutputStream.putNextEntry(newEntry); + zipOutputStream.write(bytes); + zipOutputStream.closeEntry(); + } + + // ---- fast matching + +// boolean fastMatch(JavaClass jc) { +// ConstantPool pool = jc.getConstantPool(); +// for (int i=0, len=pool.getLength(); i < len; i++) { +// Constant c = pool.getConstant(i); +// if (c instanceof ConstantNameAndType) { +// ConstantNameAndType nt = (ConstantNameAndType)c; +// if (nt.getName(pool).equals("toShortString")) { +// //System.out.println("found in " + jc); +// return true; +// } +// } +// } +// return false; +// } + + //XXX need to implement a real fast-match here + private List fastMatch(List list, JavaClass javaClass) { + if (list == null) return Collections.EMPTY_LIST; + return list; + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java new file mode 100644 index 000000000..1ff0c4e34 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/BcelWorld.java @@ -0,0 +1,320 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.zip.*; +import java.util.zip.ZipInputStream; + +import org.apache.bcel.classfile.*; +import org.apache.bcel.generic.*; +import org.apache.bcel.util.ClassPath; +import org.aspectj.util.FileUtil; +import org.aspectj.weaver.*; +import org.aspectj.weaver.patterns.*; +import org.aspectj.asm.StructureModel; +import org.aspectj.bridge.*; +import org.aspectj.bridge.IMessageHandler; + +public class BcelWorld extends World { + private ClassPathManager classPath; + + //private ClassPathManager aspectPath = null; + private List aspectPathEntries; + + // ---- constructors + + public BcelWorld() { + this(""); + } + + public BcelWorld(String cp) { + this(makeDefaultClasspath(cp), IMessageHandler.THROW); + } + + private static List makeDefaultClasspath(String cp) { + List classPath = new ArrayList(); + classPath.addAll(getPathEntries(cp)); + classPath.addAll(getPathEntries(ClassPath.getClassPath())); + //System.err.println("classpath: " + classPath); + return classPath; + + } + + private static List getPathEntries(String s) { + List ret = new ArrayList(); + StringTokenizer tok = new StringTokenizer(s, File.pathSeparator); + + while(tok.hasMoreTokens()) ret.add(tok.nextToken()); + + return ret; + } + + public BcelWorld(List classPath, IMessageHandler handler) { + //this.aspectPath = new ClassPathManager(aspectPath, handler); + this.classPath = new ClassPathManager(classPath, handler); + setMessageHandler(handler); + } + + /** + * Parse a string into advice. + * + * <blockquote><pre> + * Kind ( Id , ... ) : Pointcut -> MethodSignature + * </pre></blockquote> + */ + public Advice shadowMunger(String str, int extraFlag) { + str = str.trim(); + int start = 0; + int i = str.indexOf('('); + AdviceKind kind = + AdviceKind.stringToKind(str.substring(start, i)); + start = ++i; + i = str.indexOf(')', i); + String[] ids = parseIds(str.substring(start, i).trim()); + //start = ++i; + + + + i = str.indexOf(':', i); + start = ++i; + i = str.indexOf("->", i); + Pointcut pointcut = Pointcut.fromString(str.substring(start, i).trim()); + Member m = Member.methodFromString(str.substring(i+2, str.length()).trim()); + + // now, we resolve + TypeX[] types = m.getParameterTypes(); + FormalBinding[] bindings = new FormalBinding[ids.length]; + for (int j = 0, len = ids.length; j < len; j++) { + bindings[j] = new FormalBinding(types[j], ids[j], j, 0, 0, "fromString"); + } + + Pointcut p = + pointcut.resolve(new SimpleScope(this, bindings)); + + return concreteAdvice(kind, p, m, extraFlag, 0, 0, null); + } + + private String[] parseIds(String str) { + if (str.length() == 0) return ZERO_STRINGS; + List l = new ArrayList(); + int start = 0; + while (true) { + int i = str.indexOf(',', start); + if (i == -1) { + l.add(str.substring(start).trim()); + break; + } + l.add(str.substring(start, i).trim()); + start = i+1; + } + return (String[]) l.toArray(new String[l.size()]); + } + + // ---- various interactions with bcel + + public static Type makeBcelType(TypeX type) { + return Type.getType(type.getSignature()); + } + + static Type[] makeBcelTypes(TypeX[] types) { + Type[] ret = new Type[types.length]; + for (int i = 0, len = types.length; i < len; i++) { + ret[i] = makeBcelType(types[i]); + } + return ret; + } + + public static TypeX fromBcel(Type t) { + return TypeX.forSignature(t.getSignature()); + } + + static TypeX[] fromBcel(Type[] ts) { + TypeX[] ret = new TypeX[ts.length]; + for (int i = 0, len = ts.length; i < len; i++) { + ret[i] = fromBcel(ts[i]); + } + return ret; + } + + public ResolvedTypeX resolve(Type t) { + return resolve(fromBcel(t)); + } + + // ---- fluf + public ResolvedTypeX resolveObjectType(TypeX ty) { + String name = ty.getName(); + JavaClass jc = null; + //UnwovenClassFile classFile = (UnwovenClassFile)sourceJavaClasses.get(name); + //if (classFile != null) jc = classFile.getJavaClass(); +// if (jc == null) { +// jc = lookupJavaClass(aspectPath, name); +// } + if (jc == null) { + jc = lookupJavaClass(classPath, name); + } + if (jc == null) { + return ResolvedTypeX.MISSING; + } else { + return new BcelObjectType(ty.getSignature(), this, jc); + } + } + + private JavaClass lookupJavaClass(ClassPathManager classPath, String name) { + if (classPath == null) return null; + try { + ClassPathManager.ClassFile file = classPath.find(TypeX.forName(name)); + if (file == null) return null; + + ClassParser parser = new ClassParser(file.getInputStream(), file.getPath()); + + JavaClass jc = parser.parse(); + + return jc; + } catch (IOException ioe) { + return null; + } + } + + + BcelObjectType addSourceObjectType(JavaClass jc) { + String signature = TypeX.forName(jc.getClassName()).getSignature(); + BcelObjectType ret = (BcelObjectType)typeMap.get(signature); + if (ret == null) { + ret = new BcelObjectType(signature, this, jc); + typeMap.put(signature, ret); + } else { + ret.replaceJavaClass(jc); + } + return ret; + } + + void deleteSourceObjectType(TypeX ty) { + typeMap.remove(ty.getSignature()); + } + + public static Member makeFieldSignature(LazyClassGen cg, FieldInstruction fi) { + ConstantPoolGen cpg = cg.getConstantPoolGen(); + return + Member.field( + fi.getClassName(cpg), + (fi instanceof GETSTATIC || fi instanceof PUTSTATIC) + ? Modifier.STATIC + : 0, + fi.getName(cpg), + fi.getSignature(cpg)); + } + + public static Member makeFieldSetSignature(LazyClassGen cg, FieldInstruction fi) { + ConstantPoolGen cpg = cg.getConstantPoolGen(); + return + Member.field( + fi.getClassName(cpg), + (fi instanceof GETSTATIC || fi instanceof PUTSTATIC) + ? Modifier.STATIC + : 0, + fi.getName(cpg), + "(" + fi.getSignature(cpg) + ")" +fi.getSignature(cpg)); + } + + public Member makeMethodSignature(LazyMethodGen mg) { + ResolvedMember ret = mg.getMemberView(); + if (ret == null) { + int mods = mg.getAccessFlags(); + if (mg.getEnclosingClass().isInterface()) { + mods |= Modifier.INTERFACE; + } + return new ResolvedMember(mg.getName().equals("<init>") ? Member.CONSTRUCTOR : Member.METHOD, + TypeX.forName(mg.getClassName()), + mods, + fromBcel(mg.getReturnType()), + mg.getName(), + fromBcel(mg.getArgumentTypes()) + ); + } else { + return ret; + } + + } + + public static Member makeMethodSignature(LazyClassGen cg, InvokeInstruction ii) { + ConstantPoolGen cpg = cg.getConstantPoolGen(); + String declaring = ii.getClassName(cpg); + String name = ii.getName(cpg); + String signature = ii.getSignature(cpg); + + int modifier = + (ii instanceof INVOKEINTERFACE) + ? Modifier.INTERFACE + : (ii instanceof INVOKESTATIC) + ? Modifier.STATIC + : (ii instanceof INVOKESPECIAL && ! name.equals("<init>")) + ? Modifier.PRIVATE + : 0; + return Member.method(TypeX.forName(declaring), modifier, name, signature); + } + + public static Member makeMungerMethodSignature(JavaClass javaClass, Method method) { + int mods = 0; + if (method.isStatic()) mods = Modifier.STATIC; + else if (javaClass.isInterface()) mods = Modifier.INTERFACE; + else if (method.isPrivate()) mods = Modifier.PRIVATE; + return Member.method( + TypeX.forName(javaClass.getClassName()), mods, method.getName(), method.getSignature()); + } + + public JavaClass lookupJavaClass(String className) { + ResolvedTypeX t = resolve(TypeX.forName(className)); + if (t instanceof BcelObjectType) { + return ((BcelObjectType)t).getJavaClass(); + } else { + return null; + } + } + + private static final String[] ZERO_STRINGS = new String[0]; + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("BcelWorld("); + //buf.append(shadowMungerMap); + buf.append(")"); + return buf.toString(); + } + + public Advice concreteAdvice( + AdviceKind kind, + Pointcut p, + Member signature, + int extraParameterFlags, + int start, int end, ISourceContext sourceContext) + { + //System.err.println("concrete advice: " + signature + " context " + sourceContext); + return new BcelAdvice(kind, p, signature, extraParameterFlags, start, end, sourceContext, null); + } + + public ConcreteTypeMunger concreteTypeMunger( + ResolvedTypeMunger munger, ResolvedTypeX aspectType) + { + return new BcelTypeMunger(munger, aspectType); + } + + public ConcreteTypeMunger makeCflowStackFieldAdder(ResolvedMember cflowField) { + return new BcelCflowStackFieldAdder(cflowField); + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/ClassPathManager.java b/weaver/src/org/aspectj/weaver/bcel/ClassPathManager.java new file mode 100644 index 000000000..6f8d6deba --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/ClassPathManager.java @@ -0,0 +1,191 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.io.File; +import java.util.*; +import java.util.zip.*; +import java.util.zip.ZipFile; + +import org.aspectj.bridge.*; +import org.aspectj.bridge.IMessageHandler; +import org.aspectj.weaver.TypeX; + + +public class ClassPathManager { + + private List entries; + + public ClassPathManager(List classpath, IMessageHandler handler) { + entries = new ArrayList(); + for (Iterator i = classpath.iterator(); i.hasNext();) { + String name = (String) i.next(); + File f = new File(name); + String lc = name.toLowerCase(); + if (lc.endsWith(".jar") || lc.endsWith(".zip")) { + if (!f.isFile()) { + MessageUtil.info(handler, "zipfile classpath entry does not exist: " + name); + continue; + } + try { + entries.add(new ZipFileEntry(f)); + } catch (IOException ioe) { + MessageUtil.warn(handler, "zipfile classpath entry is invalid: " + name + "<" + ioe.getMessage() + ">"); + continue; + } + } else { + if (!f.isDirectory()) { + MessageUtil.info(handler, "directory classpath entry does not exist: " + name); + continue; + } + entries.add(new DirEntry(f)); + } + } + } + + public ClassFile find(TypeX type) { + String name = type.getName(); + for (Iterator i = entries.iterator(); i.hasNext(); ) { + Entry entry = (Entry)i.next(); + ClassFile ret = entry.find(name); + if (ret != null) return ret; + } + return null; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + boolean start = true; + for (Iterator i = entries.iterator(); i.hasNext(); ) { + if (start) { start = false; } + else {buf.append(File.pathSeparator); } + buf.append(i.next()); + } + return buf.toString(); + } + + /** + * This method is extremely expensive and should only be called rarely + */ + public List getAllClassFiles() { + List ret = new ArrayList(); + for (Iterator i = entries.iterator(); i.hasNext(); ) { + Entry entry = (Entry)i.next(); + ret.addAll(entry.getAllClassFiles()); + } + return ret; + } + + + + public abstract static class ClassFile { + public abstract InputStream getInputStream() throws IOException; + public abstract String getPath(); + } + + + public abstract static class Entry { + public abstract ClassFile find(String name); + public abstract List getAllClassFiles(); + } + + + private static class FileClassFile extends ClassFile { + private File file; + public FileClassFile(File file) { + this.file = file; + } + + public InputStream getInputStream() throws IOException { + return new FileInputStream(file); + } + + public String getPath() { return file.getPath(); } + } + + public class DirEntry extends Entry { + private String dirPath; + + public DirEntry(File dir) { this.dirPath = dir.getPath(); } + public DirEntry(String dirPath) { this.dirPath = dirPath; } + + public ClassFile find(String name) { + File f = new File(dirPath + File.separator + name.replace('.', File.separatorChar) + ".class"); + if (f.isFile()) return new FileClassFile(f); + else return null; + } + + public List getAllClassFiles() { + throw new RuntimeException("unimplemented"); + } + + public String toString() { return dirPath; } + } + + + private static class ZipEntryClassFile extends ClassFile { + private ZipEntry entry; + private ZipFile zipFile; + public ZipEntryClassFile(ZipFile zipFile, ZipEntry entry) { + this.zipFile = zipFile; + this.entry = entry; + } + + public InputStream getInputStream() throws IOException { + return zipFile.getInputStream(entry); + } + + public String getPath() { return entry.getName(); } + + } + + + public class ZipFileEntry extends Entry { + private ZipFile zipFile; + + public ZipFileEntry(File file) throws IOException { + this(new ZipFile(file)); + } + + public ZipFileEntry(ZipFile zipFile) { + this.zipFile = zipFile; + } + + public ClassFile find(String name) { + String key = name.replace('.', '/') + ".class"; + ZipEntry entry = zipFile.getEntry(key); + if (entry != null) return new ZipEntryClassFile(zipFile, entry); + else return null; + } + + public List getAllClassFiles() { + List ret = new ArrayList(); + for (Enumeration e = zipFile.entries(); e.hasMoreElements(); ) { + ZipEntry entry = (ZipEntry)e.nextElement(); + String name = entry.getName(); + if (hasClassExtension(name)) ret.add(new ZipEntryClassFile(zipFile, entry)); + } + return ret; + } + + + public String toString() { return zipFile.getName(); } + } + + + private static boolean hasClassExtension(String name) { + return name.toLowerCase().endsWith((".class")); + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/ExceptionRange.java b/weaver/src/org/aspectj/weaver/bcel/ExceptionRange.java new file mode 100644 index 000000000..2e6520361 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/ExceptionRange.java @@ -0,0 +1,146 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.apache.bcel.generic.*; +import org.aspectj.weaver.TypeX; + +/** exceptionRanges are set initially to be low priority. The various setPriority methods + * should be used accordingly. The priority is used when we pack the exception table into + * a method... the exception table should be sorted from high to low priority. Exceptions we generate + * for advice is either high priority (higher than anything coming from the original method... + * most kinds of non-execution advice) or low priority (lower than anything coming from the + * original method, for execution advice). + * + * <p> ??? This does not account for handler, or any other + * "statement-level" advice. When such statement level advice happens, we may want to go to a float level, + * so we can set the priority of advice to be lower than anything it encloses, and higher than + * anything enclosing it. + */ + +/* we're actually using the fact that we're an instruction targeter, for the + * handler */ +public final class ExceptionRange extends Range { + + private InstructionHandle handler; + private final TypeX exceptionType; + private final int priority; + + // ---- initialization + + /** + * After this constructor is called, this range is not well situated unless + * {@link #associateWithTargets} is called + */ + public ExceptionRange(InstructionList body, TypeX exceptionType, int priority) { + super(body); + this.exceptionType = exceptionType; + this.priority = priority; + } + public ExceptionRange(InstructionList body, TypeX exceptionType, boolean highPriority) { + this(body, exceptionType, highPriority ? Integer.MAX_VALUE : -1); + } + public void associateWithTargets( + InstructionHandle start, + InstructionHandle end, + InstructionHandle handler) + { + // assert body.contains(start) && body.contains(end) && body.contains(handler) + this.start = start; + this.end = end; + this.handler = handler; + start.addTargeter(this); + end.addTargeter(this); + handler.addTargeter(this); + } + + // ---- + + public InstructionHandle getHandler() { + return handler; + } + public TypeX getCatchType() { + return exceptionType; + } + public int getPriority() { + return priority; + } + + // ---- from object + + public String toString() { + String str; + if (exceptionType == null) { + str = "finally"; + } else { + str = "catch " + exceptionType; + } +// if (priority >= 0 && priority < Integer.MAX_VALUE) { +// str += " (priority " + priority + ")"; +// } + return str; + } + public boolean equals(Object other) { + if (!(other instanceof ExceptionRange)) return false; + ExceptionRange o = (ExceptionRange) other; + return o.getStart() == getStart() + && o.getEnd() == getEnd() + && o.handler == handler + && ((o.exceptionType == null) + ? (exceptionType == null) : + o.exceptionType.equals(exceptionType)) + && o.priority == priority; + } + private volatile int hashCode = 0; + public int hashCode() { + if (hashCode == 0) { + int ret = 17; + ret = 37*ret + getStart().hashCode(); + ret = 37*ret + getEnd().hashCode(); + ret = 37*ret + handler.hashCode(); + ret = 37*ret + ((exceptionType == null) ? 0 : exceptionType.hashCode()); + ret = 37*ret + priority; + hashCode = ret; + } + return hashCode; + } + + public void updateTarget( + InstructionHandle oldIh, + InstructionHandle newIh, + InstructionList newBody) + { + super.updateTarget(oldIh, newIh, newBody); + // we're guaranteed that start, end, and handler are distinct instruction handles. + if (oldIh == handler) { + handler = newIh; + } + } + public static boolean isExceptionStart(InstructionHandle ih) { + if (! isRangeHandle(ih)) return false; + Range r = getRange(ih); + if (! (r instanceof ExceptionRange)) return false; + ExceptionRange er = (ExceptionRange) r; + return er.getStart() == ih; + } + public static boolean isExceptionEnd(InstructionHandle ih) { + if (! isRangeHandle(ih)) return false; + Range r = getRange(ih); + if (! (r instanceof ExceptionRange)) return false; + ExceptionRange er = (ExceptionRange) r; + return er.getEnd() == ih; + } + + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java new file mode 100644 index 000000000..0a1861b47 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/LazyClassGen.java @@ -0,0 +1,471 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.*; +import org.apache.bcel.generic.*; +import org.apache.bcel.util.ClassPath; +import org.aspectj.weaver.*; +import org.aspectj.util.CollectionUtil; + +public final class LazyClassGen { + + /** Emit disassembled class and newline to out */ + public static void disassemble(String path, String name, PrintStream out) + throws IOException { + if (null == out) { + return; + } + //out.println("classPath: " + classPath); + + BcelWorld world = new BcelWorld(path); + + LazyClassGen clazz = new LazyClassGen((BcelObjectType) world.resolve(name)); + clazz.print(out); + out.println(); + } + + private BcelObjectType myType; // XXX is not set for types we create + private ClassGen myGen; + private ConstantPoolGen constantPoolGen; + + private List /*LazyMethodGen*/ + methodGens = new ArrayList(); + private List /*LazyClassGen*/ + classGens = new ArrayList(); + + private int childCounter = 0; + + public int getNewGeneratedNameTag() { + return childCounter++; + } + + private InstructionFactory fact; + // ---- + + public LazyClassGen( + String class_name, + String super_class_name, + String file_name, + int access_flags, + String[] interfaces) + { + myGen = new ClassGen(class_name, super_class_name, file_name, access_flags, interfaces); + constantPoolGen = myGen.getConstantPool(); + fact = new InstructionFactory(constantPoolGen); + } + + //Non child type, so it comes from a real type in the world. + public LazyClassGen(BcelObjectType myType) { + myGen = new ClassGen(myType.getJavaClass()); + constantPoolGen = myGen.getConstantPool(); + fact = new InstructionFactory(constantPoolGen); + this.myType = myType; + + Method[] methods = myGen.getMethods(); + for (int i = 0; i < methods.length; i++) { + addMethodGen(new LazyMethodGen(methods[i], this)); + } + } + +// public void addAttribute(Attribute i) { +// myGen.addAttribute(i); +// } + + // ---- + + public String getInternalClassName() { + return getConstantPoolGen().getConstantPool().getConstantString( + myGen.getClassNameIndex(), + Constants.CONSTANT_Class); + + } + + public File getPackagePath(File root) { + String str = getInternalClassName(); + int index = str.lastIndexOf('/'); + if (index == -1) + return root; + return new File(root, str.substring(0, index)); + } + + public String getClassId() { + String str = getInternalClassName(); + int index = str.lastIndexOf('/'); + if (index == -1) + return str; + return str.substring(index + 1); + } + + + public void addMethodGen(LazyMethodGen gen) { + //assert gen.getClassName() == super.getClassName(); + methodGens.add(gen); + } + + public List getMethodGens() { + return Collections.unmodifiableList(methodGens); + + } + + private void writeBack() { + addAjcInitializers(); + + + int len = methodGens.size(); + myGen.setMethods(new Method[0]); + for (int i = 0; i < len; i++) { + LazyMethodGen gen = (LazyMethodGen) methodGens.get(i); + // we skip empty clinits + if (isEmptyClinit(gen)) continue; + myGen.addMethod(gen.getMethod()); + } + } + + public JavaClass getJavaClass() { + writeBack(); + return myGen.getJavaClass(); + } + + public void addGeneratedInner(LazyClassGen newClass) { + classGens.add(newClass); + } + + public void addInterface(TypeX typeX) { + myGen.addInterface(typeX.getName()); + } + + // non-recursive, may be a bug, ha ha. + private List getClassGens() { + List ret = new ArrayList(); + ret.add(this); + ret.addAll(classGens); + + return ret; + } + + + public List getChildClasses() { + if (classGens.isEmpty()) return Collections.EMPTY_LIST; + List ret = new ArrayList(); + for (Iterator i = classGens.iterator(); i.hasNext();) { + LazyClassGen clazz = (LazyClassGen) i.next(); + byte[] bytes = clazz.getJavaClass().getBytes(); + String name = clazz.getName(); + int index = name.lastIndexOf('$'); + // XXX this could be bad, check use of dollar signs. + name = name.substring(index+1); + ret.add(new UnwovenClassFile.ChildClass(name, bytes)); + } + return ret; + } + + public String toString() { + return toShortString(); + } + + public String toShortString() { + String s = + org.apache.bcel.classfile.Utility.accessToString(myGen.getAccessFlags(), true); + if (s != "") + s += " "; + s += org.apache.bcel.classfile.Utility.classOrInterface(myGen.getAccessFlags()); + s += " "; + s += myGen.getClassName(); + return s; + } + + public String toLongString() { + ByteArrayOutputStream s = new ByteArrayOutputStream(); + print(new PrintStream(s)); + return new String(s.toByteArray()); + } + + public void print() { print(System.out); } + + public void print(PrintStream out) { + List classGens = getClassGens(); + for (Iterator iter = classGens.iterator(); iter.hasNext();) { + LazyClassGen element = (LazyClassGen) iter.next(); + element.printOne(out); + if (iter.hasNext()) out.println(); + } + } + + private void printOne(PrintStream out) { + out.print(toShortString()); + out.print(" extends "); + out.print( + org.apache.bcel.classfile.Utility.compactClassName( + myGen.getSuperclassName(), + false)); + + int size = myGen.getInterfaces().length; + + if (size > 0) { + out.print(" implements "); + for (int i = 0; i < size; i++) { + out.print(myGen.getInterfaceNames()[i]); + if (i < size - 1) + out.print(", "); + } + } + out.print(":"); + out.println(); + // XXX make sure to pass types correctly around, so this doesn't happen. + if (myType != null) { + myType.printWackyStuff(out); + } + Field[] fields = myGen.getFields(); + for (int i = 0, len = fields.length; i < len; i++) { + out.print(" "); + out.println(fields[i]); + } + List methodGens = getMethodGens(); + for (Iterator iter = methodGens.iterator(); iter.hasNext();) { + LazyMethodGen gen = (LazyMethodGen) iter.next(); + // we skip empty clinits + if (isEmptyClinit(gen)) continue; + gen.print(out); + if (iter.hasNext()) out.println(); + } +// out.println(" ATTRIBS: " + Arrays.asList(myGen.getAttributes())); + + out.println("end " + toShortString()); + } + + private boolean isEmptyClinit(LazyMethodGen gen) { + if (!gen.getName().equals("<clinit>")) return false; + //System.err.println("checking clinig: " + gen); + InstructionHandle start = gen.getBody().getStart(); + while (start != null) { + if (Range.isRangeHandle(start) || (start.getInstruction() instanceof RETURN)) { + start = start.getNext(); + } else { + return false; + } + } + + return true; + } + + public ConstantPoolGen getConstantPoolGen() { + return constantPoolGen; + } + + public String getName() { + return myGen.getClassName(); + } + + public WeaverStateKind getWeaverState() { + WeaverStateKind kind = myType.getWeaverState(); + if (kind == null) return WeaverStateKind.Untouched; + return kind; + } + + public void setWeaverState(WeaverStateKind s) { + Attribute[] attributes = myGen.getAttributes(); + if (attributes != null) { + for (int i = attributes.length - 1; i >=0; i--) { + Attribute a = attributes[i]; + if (a instanceof Unknown) { + Unknown u = (Unknown) a; + if (u.getName().equals(AjAttribute.WeaverState.AttributeName)) { + myGen.removeAttribute(u); + } + } + } + } + myGen.addAttribute(BcelAttributes.bcelAttribute( + new AjAttribute.WeaverState(s), + getConstantPoolGen())); + } + + public InstructionFactory getFactory() { + return fact; + } + + public LazyMethodGen getStaticInitializer() { + for (Iterator i = methodGens.iterator(); i.hasNext();) { + LazyMethodGen gen = (LazyMethodGen) i.next(); + if (gen.getName().equals("<clinit>")) return gen; + } + LazyMethodGen clinit = new LazyMethodGen( + Modifier.STATIC, + Type.VOID, + "<clinit>", + new Type[0], + CollectionUtil.NO_STRINGS, + this); + clinit.getBody().insert(getFactory().RETURN); + methodGens.add(clinit); + return clinit; + } + + + // reflective thisJoinPoint support + Map/*BcelShadow, Field*/ tjpFields = new HashMap(); + public static final ObjectType tjpType = + new ObjectType("org.aspectj.lang.JoinPoint"); + public static final ObjectType staticTjpType = + new ObjectType("org.aspectj.lang.JoinPoint$StaticPart"); + private static final ObjectType sigType = + new ObjectType("org.aspectj.lang.Signature"); + private static final ObjectType slType = + new ObjectType("org.aspectj.lang.reflect.SourceLocation"); + private static final ObjectType factoryType = + new ObjectType("org.aspectj.runtime.reflect.Factory"); + private static final ObjectType classType = + new ObjectType("java.lang.Class"); + + public Field getTjpField(BcelShadow shadow) { + Field ret = (Field)tjpFields.get(shadow); + if (ret != null) return ret; + + ret = new FieldGen(Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL, + staticTjpType, + "ajc$tjp_" + tjpFields.size(), + getConstantPoolGen()).getField(); + addField(ret); + tjpFields.put(shadow, ret); + return ret; + } + + private void addAjcInitializers() { + if (tjpFields.size() == 0) return; + + InstructionList il = initializeAllTjps(); + getStaticInitializer().getBody().insert(il); + } + + + private InstructionList initializeAllTjps() { + InstructionList list = new InstructionList(); + InstructionFactory fact = getFactory(); + + // make a new factory + list.append(fact.createNew(factoryType)); + list.append(fact.createDup(1)); + + list.append(new PUSH(getConstantPoolGen(), getFileName())); + + // load the current Class object + //XXX check that this works correctly for inners/anonymous + list.append(new PUSH(getConstantPoolGen(), getClassName())); + //XXX do we need to worry about the fact the theorectically this could throw + //a ClassNotFoundException + list.append(fact.createInvoke("java.lang.Class", "forName", classType, + new Type[] {Type.STRING}, Constants.INVOKESTATIC)); + + list.append(fact.createInvoke(factoryType.getClassName(), "<init>", + Type.VOID, new Type[] {Type.STRING, classType}, + Constants.INVOKESPECIAL)); + + list.append(fact.createStore(factoryType, 0)); + + List entries = new ArrayList(tjpFields.entrySet()); + Collections.sort(entries, new Comparator() { + public int compare(Object a, Object b) { + Map.Entry ae = (Map.Entry) a; + Map.Entry be = (Map.Entry) b; + return ((Field) ae.getValue()) + .getName() + .compareTo(((Field)be.getValue()).getName()); + } + }); + + for (Iterator i = entries.iterator(); i.hasNext(); ) { + Map.Entry entry = (Map.Entry)i.next(); + initializeTjp(fact, list, (Field)entry.getValue(), (BcelShadow)entry.getKey()); + } + + return list; + } + + + private void initializeTjp(InstructionFactory fact, InstructionList list, + Field field, BcelShadow shadow) + { + Member sig = shadow.getSignature(); + //ResolvedMember mem = shadow.getSignature().resolve(shadow.getWorld()); + + // load the factory + list.append(fact.createLoad(factoryType, 0)); + + // load the kind + list.append(new PUSH(getConstantPoolGen(), shadow.getKind().getName())); + + // create the signature + list.append(fact.createLoad(factoryType, 0)); + list.append(new PUSH(getConstantPoolGen(), sig.getSignatureString(shadow.getWorld()))); + list.append(fact.createInvoke(factoryType.getClassName(), + sig.getSignatureMakerName(), + new ObjectType(sig.getSignatureType()), + new Type[] { Type.STRING }, + Constants.INVOKEVIRTUAL)); + + //XXX should load source location from shadow + list.append(Utility.createConstant(fact, shadow.getSourceLine())); + + + list.append(fact.createInvoke(factoryType.getClassName(), + "makeSJP", staticTjpType, + new Type[] { Type.STRING, sigType, Type.INT}, + Constants.INVOKEVIRTUAL)); + + // put it in the field + list.append(fact.createFieldAccess(getClassName(), field.getName(), + staticTjpType, Constants.PUTSTATIC)); + } + + + public BcelObjectType getType() { + return myType; + } + + public String getFileName() { + return myGen.getFileName(); + } + + public void addField(Field field) { + myGen.addField(field); + } + + public String getClassName() { + return myGen.getClassName(); + } + + public boolean isInterface() { + return myGen.isInterface(); + } + + public LazyMethodGen getLazyMethodGen(Member m) { + return getLazyMethodGen(m.getName(), m.getSignature()); + } + + public LazyMethodGen getLazyMethodGen(String name, String signature) { + for (Iterator i = methodGens.iterator(); i.hasNext();) { + LazyMethodGen gen = (LazyMethodGen) i.next(); + if (gen.getName().equals(name) && gen.getSignature().equals(signature)) + return gen; + } + throw new BCException("Class " + this.getName() + " does not have a method " + + name + " with signature " + signature); + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java new file mode 100644 index 000000000..63d105e19 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/LazyMethodGen.java @@ -0,0 +1,1060 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.*; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; + + +/** + * A LazyMethodGen should be treated as a MethodGen. It's our way of abstracting over the + * low-level Method objects. It converts through {@link MethodGen} to create + * and to serialize, but that's it. + * + * <p> At any rate, there are two ways to create LazyMethodGens. + * One is from a method, which + * does work through MethodGen to do the correct thing. + * The other is the creation of a completely empty + * LazyMethodGen, and it is used when we're constructing code from scratch. + * + * <p> We stay away from targeters for rangey things like Shadows and Exceptions. + */ + +public final class LazyMethodGen { + private final int accessFlags; + private final Type returnType; + private final String name; + private final Type[] argumentTypes; + //private final String[] argumentNames; + private final String[] declaredExceptions; + private final InstructionList body; // leaving null for abstracts + private final Attribute[] attributes; + private final LazyClassGen enclosingClass; + private final BcelMethod memberView; + + private int maxLocals; + + /** + * only used by {@link BcelClassWeaver} + */ + List /*ShadowMungers*/ matchedShadows; + + // Used for interface introduction + // this is the type of the interface the method is technically on + public ResolvedTypeX definingType = null; + + public LazyMethodGen( + int accessFlags, + Type returnType, + String name, + Type[] paramTypes, + String[] declaredExceptions, + LazyClassGen enclosingClass) + { + this.memberView = null; // ??? should be okay, since constructed ones aren't woven into + this.accessFlags = accessFlags; + this.returnType = returnType; + this.name = name; + this.argumentTypes = paramTypes; + //this.argumentNames = Utility.makeArgNames(paramTypes.length); + this.declaredExceptions = declaredExceptions; + if (!Modifier.isAbstract(accessFlags)) { + body = new InstructionList(); + setMaxLocals(calculateMaxLocals()); + } else { + body = null; + } + this.attributes = new Attribute[0]; + this.enclosingClass = enclosingClass; + assertGoodBody(); + } + + private int calculateMaxLocals() { + int ret = 0; + if (!Modifier.isStatic(accessFlags)) ret++; + for (int i = 0, len = argumentTypes.length; i < len; i++) { + ret += argumentTypes[i].getSize(); + } + return ret; + } + + // build from an existing method + public LazyMethodGen(Method m, LazyClassGen enclosingClass) { + this.enclosingClass = enclosingClass; + if (!m.isAbstract() && m.getCode() == null) { + throw new RuntimeException("bad non-abstract method with no code: " + m + " on " + enclosingClass); + } + MethodGen gen = new MethodGen(m, enclosingClass.getName(), enclosingClass.getConstantPoolGen()); + this.memberView = new BcelMethod(enclosingClass.getType(), m); + this.accessFlags = gen.getAccessFlags(); + this.returnType = gen.getReturnType(); + this.name = gen.getName(); + this.argumentTypes = gen.getArgumentTypes(); + //this.argumentNames = gen.getArgumentNames(); + this.declaredExceptions = gen.getExceptions(); + this.attributes = gen.getAttributes(); + this.maxLocals = gen.getMaxLocals(); + if (gen.isAbstract() || gen.isNative()) { + body = null; + } else { + body = gen.getInstructionList(); + unpackHandlers(gen); + unpackLineNumbers(gen); + unpackLocals(gen); + } + assertGoodBody(); + } + + // XXX we're relying on the javac promise I've just made up that we won't have an early exception + // in the list mask a later exception: That is, for two exceptions E and F, + // if E preceeds F, then either E \cup F = {}, or E \nonstrictsubset F. So when we add F, + // we add it on the _OUTSIDE_ of any handlers that share starts or ends with it. + + // with that in mind, we merrily go adding ranges for exceptions. + + private void unpackHandlers(MethodGen gen) { + CodeExceptionGen[] exns = gen.getExceptionHandlers(); + if (exns != null) { + int len = exns.length; + int priority = len - 1; + for (int i = 0; i < len; i++, priority--) { + CodeExceptionGen exn = exns[i]; + + InstructionHandle start = + Range.genStart( + body, + getOutermostExceptionStart(exn.getStartPC())); + InstructionHandle end = Range.genEnd(body, getOutermostExceptionEnd(exn.getEndPC())); + // this doesn't necessarily handle overlapping correctly!!! + ExceptionRange er = + new ExceptionRange( + body, + exn.getCatchType() == null + ? null + : BcelWorld.fromBcel(exn.getCatchType()), + priority); + er.associateWithTargets(start, end, exn.getHandlerPC()); + exn.setStartPC(null); // also removes from target + exn.setEndPC(null); // also removes from target + exn.setHandlerPC(null); // also removes from target + } + gen.removeExceptionHandlers(); + } + } + + private InstructionHandle getOutermostExceptionStart(InstructionHandle ih) { + while (true) { + if (ExceptionRange.isExceptionStart(ih.getPrev())) { + ih = ih.getPrev(); + } else { + return ih; + } + } + } + private InstructionHandle getOutermostExceptionEnd(InstructionHandle ih) { + while (true) { + if (ExceptionRange.isExceptionEnd(ih.getNext())) { + ih = ih.getNext(); + } else { + return ih; + } + } + } + + + private void unpackLineNumbers(MethodGen gen) { + LineNumberTag lr = null; + for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { + InstructionTargeter[] targeters = ih.getTargeters(); + if (targeters != null) { + for (int i = targeters.length - 1; i >= 0; i--) { + InstructionTargeter targeter = targeters[i]; + if (targeter instanceof LineNumberGen) { + LineNumberGen lng = (LineNumberGen) targeter; + lng.updateTarget(ih, null); + lr = new LineNumberTag(lng.getSourceLine()); + } + } + } + if (lr != null) { + ih.addTargeter(lr); + } + } + gen.removeLineNumbers(); + } + + private void unpackLocals(MethodGen gen) { + Set locals = new HashSet(); + for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { + InstructionTargeter[] targeters = ih.getTargeters(); + List ends = new ArrayList(0); + if (targeters != null) { + for (int i = targeters.length - 1; i >= 0; i--) { + InstructionTargeter targeter = targeters[i]; + if (targeter instanceof LocalVariableGen) { + LocalVariableGen lng = (LocalVariableGen) targeter; + LocalVariableTag lr = new LocalVariableTag(BcelWorld.fromBcel(lng.getType()), lng.getName(), lng.getIndex()); + if (lng.getStart() == ih) { + lng.setStart(null); + locals.add(lr); + } else { + lng.setEnd(null); + ends.add(lr); + } + } + } + } + for (Iterator i = locals.iterator(); i.hasNext(); ) { + ih.addTargeter((LocalVariableTag) i.next()); + } + locals.removeAll(ends); + } + gen.removeLocalVariables(); + } + + // =============== + + public int allocateLocal(Type type) { + return allocateLocal(type.getSize()); + } + + public int allocateLocal(int slots) { + int max = getMaxLocals(); + setMaxLocals(max + slots); + return max; + } + + public Method getMethod() { + MethodGen gen = pack(); + return gen.getMethod(); + } + + // ============================= + + public String toString() { + return toLongString(); + } + + public String toShortString() { + org.apache.bcel.classfile.Utility util = null; // EVIL! + String access = util.accessToString(getAccessFlags()); + + StringBuffer buf = new StringBuffer(); + + if (!access.equals("")) { + buf.append(access); + buf.append(" "); + } + buf.append(util.signatureToString(getReturnType().getSignature(), true)); + buf.append(" "); + buf.append(getName()); + buf.append("("); + { + int len = argumentTypes.length; + if (len > 0) { + buf.append(util.signatureToString(argumentTypes[0].getSignature(), true)); + for (int i = 1; i < argumentTypes.length; i++) { + buf.append(", "); + buf.append(util.signatureToString(argumentTypes[i].getSignature(), true)); + } + } + } + buf.append(")"); + + { + int len = declaredExceptions != null ? declaredExceptions.length : 0; + if (len > 0) { + buf.append(" throws "); + buf.append(declaredExceptions[0]); + for (int i = 1; i < declaredExceptions.length; i++) { + buf.append(", "); + buf.append(declaredExceptions[i]); + } + } + } + return buf.toString(); + } + + public String toLongString() { + ByteArrayOutputStream s = new ByteArrayOutputStream(); + print(new PrintStream(s)); + return new String(s.toByteArray()); + } + + public void print() { + print(System.out); + } + + public void print(PrintStream out) { + out.print(" " + toShortString()); + printAspectAttributes(out); + + InstructionList body = getBody(); + if (body == null) { + out.println(";"); + return; + } + out.println(":"); + new BodyPrinter(out).run(); + out.println(" end " + toShortString()); + } + + + private void printAspectAttributes(PrintStream out) { + ISourceContext context = null; + if (enclosingClass != null && enclosingClass.getType() != null) { + context = enclosingClass.getType().getSourceContext(); + } + List as = BcelAttributes.readAjAttributes(attributes, context); + if (! as.isEmpty()) { + out.println(" " + as.get(0)); // XXX assuming exactly one attribute, munger... + } + } + + + private class BodyPrinter { + Map prefixMap = new HashMap(); + Map suffixMap = new HashMap(); + Map labelMap = new HashMap(); + + InstructionList body; + PrintStream out; + ConstantPool pool; + List ranges; + + BodyPrinter(PrintStream out) { + this.pool = enclosingClass.getConstantPoolGen().getConstantPool(); + this.body = getBody(); + this.out = out; + } + + void run() { + assignLabels(); + print(); + } + + // label assignment + void assignLabels() { + LinkedList exnTable = new LinkedList(); + String pendingLabel = null; +// boolean hasPendingTargeters = false; + int lcounter = 0; + for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { + InstructionTargeter[] targeters = ih.getTargeters(); + if (targeters != null) { + for (int i = targeters.length - 1; i >= 0; i--) { + InstructionTargeter t = targeters[i]; + if (t instanceof ExceptionRange) { + // assert isRangeHandle(h); + ExceptionRange r = (ExceptionRange) t; + if (r.getStart() == ih) { + insertHandler(r, exnTable); + } + } else if (t instanceof BranchInstruction) { + if (pendingLabel == null) { + pendingLabel = "L" + lcounter++; + } + } else { + // assert isRangeHandle(h) + } + } + } + if (pendingLabel != null) { + labelMap.put(ih, pendingLabel); + if (! Range.isRangeHandle(ih)) { + pendingLabel = null; + } + } + } + int ecounter = 0; + for (Iterator i = exnTable.iterator(); i.hasNext();) { + ExceptionRange er = (ExceptionRange) i.next(); + String exceptionLabel = "E" + ecounter++; + labelMap.put(Range.getRealStart(er.getHandler()), exceptionLabel); + labelMap.put(er.getHandler(), exceptionLabel); + } + } + + // printing + + void print() { + int depth = 0; + int currLine = -1; + bodyPrint: + for (InstructionHandle ih = body.getStart(); ih != null; ih = ih.getNext()) { + if (Range.isRangeHandle(ih)) { + Range r = Range.getRange(ih); + // don't print empty ranges, that is, ranges who contain no actual instructions + for (InstructionHandle xx = r.getStart(); Range.isRangeHandle(xx); xx = xx.getNext()) { + if (xx == r.getEnd()) continue bodyPrint; + } + // doesn't handle nested: if (r.getStart().getNext() == r.getEnd()) continue; + if (r.getStart() == ih) { + printRangeString(r, depth++); + } else { + if (r.getEnd() != ih) throw new RuntimeException("bad"); + printRangeString(r, --depth); + } + } else { + printInstruction(ih, depth); + int line = getLineNumber(ih, currLine); + if (line != currLine) { + currLine = line; + out.println(" (line " + line + ")"); + } else { + out.println(); + } + } + } + } + + void printRangeString(Range r, int depth) { + printDepth(depth); + out.println(getRangeString(r, labelMap)); + } + + + String getRangeString(Range r, Map labelMap) { + if (r instanceof ExceptionRange) { + ExceptionRange er = (ExceptionRange) r; + return er.toString() + " -> " + labelMap.get(er.getHandler()); + } else { + return r.toString(); + } + } + + void printDepth(int depth) { + pad(BODY_INDENT); + while (depth > 0) { + out.print("| "); + depth--; + } + } + + + void printLabel(String s, int depth) { + int space = Math.max(CODE_INDENT - depth * 2, 0); + if (s == null) { + pad(space); + } else { + space = Math.max(space - (s.length() + 2), 0); + pad(space); + out.print(s); + out.print(": "); + } + } + + void printInstruction(InstructionHandle h, int depth) { + printDepth(depth); + printLabel((String) labelMap.get(h), depth); + + Instruction inst = h.getInstruction(); + if (inst instanceof CPInstruction) { + CPInstruction cpinst = (CPInstruction) inst; + out.print(Constants.OPCODE_NAMES[cpinst.getOpcode()].toUpperCase()); + out.print(" "); + out.print(pool.constantToString(pool.getConstant(cpinst.getIndex()))); + } else if (inst instanceof Select) { + Select sinst = (Select) inst; + out.println(Constants.OPCODE_NAMES[sinst.getOpcode()].toUpperCase()); + int[] matches = sinst.getMatchs(); + InstructionHandle[] targets = sinst.getTargets(); + InstructionHandle defaultTarget = sinst.getTarget(); + for (int i = 0, len = matches.length; i < len; i++) { + printDepth(depth); + printLabel(null, depth); + out.print(" "); + out.print(matches[i]); + out.print(": \t"); + out.println(labelMap.get(targets[i])); + } + printDepth(depth); + printLabel(null, depth); + out.print(" "); + out.print("default: \t"); + out.print(labelMap.get(defaultTarget)); + } else if (inst instanceof BranchInstruction) { + BranchInstruction brinst = (BranchInstruction) inst; + out.print(Constants.OPCODE_NAMES[brinst.getOpcode()].toUpperCase()); + out.print(" "); + out.print(labelMap.get(brinst.getTarget())); + } else if (inst instanceof LocalVariableInstruction) { + LocalVariableInstruction lvinst = (LocalVariableInstruction) inst; + out.print(inst.toString(false).toUpperCase()); + int index = lvinst.getIndex(); + LocalVariableTag tag = getLocalVariableTag(h, index); + if (tag != null) { + out.print(" // "); + out.print(tag.getType()); + out.print(" "); + out.print(tag.getName()); + } + } else { + out.print(inst.toString(false).toUpperCase()); + } + } + + + + + static final int BODY_INDENT = 4; + static final int CODE_INDENT = 16; + + void pad(int size) { + for (int i = 0; i < size; i++) { + out.print(" "); + } + } + } + + + static LocalVariableTag getLocalVariableTag( + InstructionHandle ih, + int index) + { + InstructionTargeter[] targeters = ih.getTargeters(); + if (targeters == null) return null; + for (int i = targeters.length - 1; i >= 0; i--) { + InstructionTargeter t = targeters[i]; + if (t instanceof LocalVariableTag) { + LocalVariableTag lvt = (LocalVariableTag) t; + if (lvt.getSlot() == index) return lvt; + } + } + return null; + } + + static int getLineNumber( + InstructionHandle ih, + int prevLine) + { + InstructionTargeter[] targeters = ih.getTargeters(); + if (targeters == null) return prevLine; + for (int i = targeters.length - 1; i >= 0; i--) { + InstructionTargeter t = targeters[i]; + if (t instanceof LineNumberTag) { + return ((LineNumberTag)t).getLineNumber(); + } + } + return prevLine; + } + + public boolean isStatic() { + return Modifier.isStatic(getAccessFlags()); + } + + public void addExceptionHandler( + InstructionHandle start, + InstructionHandle end, + InstructionHandle handlerStart, + ObjectType catchType, + boolean highPriority) { + + InstructionHandle start1 = Range.genStart(body, start); + InstructionHandle end1 = Range.genEnd(body, end); + + ExceptionRange er = + new ExceptionRange(body, BcelWorld.fromBcel(catchType), highPriority); + er.associateWithTargets(start1, end1, handlerStart); + } + + public int getAccessFlags() { + return accessFlags; + } + + public Type[] getArgumentTypes() { + return argumentTypes; + } + +// public String[] getArgumentNames() { +// return argumentNames; +// } + + public LazyClassGen getEnclosingClass() { + return enclosingClass; + } + + public int getMaxLocals() { + return maxLocals; + } + + public String getName() { + return name; + } + + public Type getReturnType() { + return returnType; + } + + public void setMaxLocals(int maxLocals) { + this.maxLocals = maxLocals; + } + + public InstructionList getBody() { + return body; + } + + public boolean hasBody() { return body != null; } + + + public Attribute[] getAttributes() { + return attributes; + } + + public String[] getDeclaredExceptions() { + return declaredExceptions; + } + + public String getClassName() { + return enclosingClass.getName(); + } + + + // ---- packing! + + public MethodGen pack() { + MethodGen gen = + new MethodGen( + getAccessFlags(), + getReturnType(), + getArgumentTypes(), + null, //getArgumentNames(), + getName(), + getEnclosingClass().getName(), + new InstructionList(), + getEnclosingClass().getConstantPoolGen()); + for (int i = 0, len = declaredExceptions.length; i < len; i++) { + gen.addException(declaredExceptions[i]); + } + for (int i = 0, len = attributes.length; i < len; i++) { + gen.addAttribute(attributes[i]); + } + if (hasBody()) { + packBody(gen); + gen.setMaxLocals(); + gen.setMaxStack(); + } + return gen; + } + + /** fill the newly created method gen with our body, + * inspired by InstructionList.copy() + */ + public void packBody(MethodGen gen) { + HashMap map = new HashMap(); + InstructionList fresh = gen.getInstructionList(); + + /* Make copies of all instructions, append them to the new list + * and associate old instruction references with the new ones, i.e., + * a 1:1 mapping. + */ + for (InstructionHandle ih = getBody().getStart(); ih != null; ih = ih.getNext()) { + if (Range.isRangeHandle(ih)) { + continue; + } + Instruction i = ih.getInstruction(); + Instruction c = i.copy(); // Use clone for shallow copy + + if (c instanceof BranchInstruction) + map.put(ih, fresh.append((BranchInstruction) c)); + else + map.put(ih, fresh.append(c)); + } + // at this point, no rangeHandles are in fresh. Let's use that... + + /* Update branch targets and insert various attributes. + * Insert our exceptionHandlers + * into a sorted list, so they can be added in order later. + */ + InstructionHandle ih = getBody().getStart(); + InstructionHandle jh = fresh.getStart(); + + LinkedList exnList = new LinkedList(); + + Map localVariableStarts = new HashMap(); + Map localVariableEnds = new HashMap(); + + int currLine = -1; + + while (ih != null) { + if (map.get(ih) == null) { + // we're a range instruction + Range r = Range.getRange(ih); + if (r instanceof ExceptionRange) { + ExceptionRange er = (ExceptionRange) r; + if (er.getStart() == ih) { + // order is important, insert handlers in order of start + insertHandler(er, exnList); + } + } else { + // we must be a shadow range or something equally useless, + // so forget about doing anything + } + // just increment ih. + ih = ih.getNext(); + } else { + // assert map.get(ih) == jh + Instruction i = ih.getInstruction(); + Instruction j = jh.getInstruction(); + + if (i instanceof BranchInstruction) { + BranchInstruction bi = (BranchInstruction) i; + BranchInstruction bj = (BranchInstruction) j; + InstructionHandle itarget = bi.getTarget(); // old target + +// try { + // New target is in hash map + bj.setTarget(remap(itarget, map)); +// } catch (NullPointerException e) { +// print(); +// System.out.println("Was trying to remap " + bi); +// System.out.println("who's target was supposedly " + itarget); +// throw e; +// } + + if (bi instanceof Select) { + // Either LOOKUPSWITCH or TABLESWITCH + InstructionHandle[] itargets = ((Select) bi).getTargets(); + InstructionHandle[] jtargets = ((Select) bj).getTargets(); + + for (int k = itargets.length - 1; k >= 0; k--) { + // Update all targets + jtargets[k] = remap(itargets[k], map); + jtargets[k].addTargeter(bj); + } + } + } + + // now deal with line numbers + // and store up info for local variables + InstructionTargeter[] targeters = ih.getTargeters(); + if (targeters != null) { + for (int k = targeters.length - 1; k >= 0; k--) { + InstructionTargeter targeter = targeters[k]; + if (targeter instanceof LineNumberTag) { + int line = ((LineNumberTag)targeter).getLineNumber(); + if (line != currLine) { + gen.addLineNumber(jh, line); + currLine = line; + } + } else if (targeter instanceof LocalVariableTag) { + LocalVariableTag lvt = (LocalVariableTag) targeter; + if (i instanceof LocalVariableInstruction) { + int index = ((LocalVariableInstruction)i).getIndex(); + if (lvt.getSlot() == index) { + if (localVariableStarts.get(lvt) == null) { + localVariableStarts.put(lvt, jh); + } + localVariableEnds.put(lvt, jh); + } + } + } + } + } + // now continue + ih = ih.getNext(); + jh = jh.getNext(); + } + } + + // now add exception handlers + for (Iterator iter = exnList.iterator(); iter.hasNext();) { + ExceptionRange r = (ExceptionRange) iter.next(); + if (r.isEmpty()) continue; + gen.addExceptionHandler( + remap(r.getRealStart(), map), + remap(r.getRealEnd(), map), + remap(r.getHandler(), map), + (r.getCatchType() == null) + ? null + : (ObjectType) BcelWorld.makeBcelType(r.getCatchType())); + } + // now add local variables + gen.removeLocalVariables(); + for (Iterator iter = localVariableStarts.keySet().iterator(); iter.hasNext(); ) { + LocalVariableTag tag = (LocalVariableTag) iter.next(); + gen.addLocalVariable( + tag.getName(), + BcelWorld.makeBcelType(tag.getType()), + tag.getSlot(), + (InstructionHandle) localVariableStarts.get(tag), + (InstructionHandle) localVariableEnds.get(tag)); + } + } + + private static InstructionHandle remap(InstructionHandle ih, Map map) { + while (true) { + Object ret = map.get(ih); + if (ret == null) { + ih = ih.getNext(); + } else { + return (InstructionHandle) ret; + } + } + } + + // exception ordering + // An exception A preceeds an exception B in the exception table iff: + + // * A and B were in the original method, and A preceeded B in the original exception table + // * If A has a higher priority than B, than it preceeds B. + // * If A and B have the same priority, then the one whose START happens EARLIEST has LEAST priority. + // in short, the outermost exception has least priority. + // we implement this with a LinkedList. We could possibly implement this with a java.util.SortedSet, + // but I don't trust the only implementation, TreeSet, to do the right thing. + + private static void insertHandler(ExceptionRange fresh, LinkedList l) { + for (ListIterator iter = l.listIterator(); iter.hasNext();) { + ExceptionRange r = (ExceptionRange) iter.next(); + if (fresh.getPriority() >= r.getPriority()) { + iter.previous(); + iter.add(fresh); + return; + } + } + l.add(fresh); + } + + + + public boolean isPrivate() { + return Modifier.isPrivate(getAccessFlags()); + } + + + // ---- + + /** A good body is a body with the following properties: + * + * <ul> + * <li> For each branch instruction S in body, target T of S is in body. + * <li> For each branch instruction S in body, target T of S has S as a targeter. + * <li> For each instruction T in body, for each branch instruction S that is a + * targeter of T, S is in body. + * <li> For each non-range-handle instruction T in body, for each instruction S + * that is a targeter of T, S is + * either a branch instruction, an exception range or a tag + * <li> For each range-handle instruction T in body, there is exactly one targeter S + * that is a range. + * <li> For each range-handle instruction T in body, the range R targeting T is in body. + * <li> For each instruction T in body, for each exception range R targeting T, R is + * in body. + * <li> For each exception range R in body, let T := R.handler. T is in body, and R is one + * of T's targeters + * <li> All ranges are properly nested: For all ranges Q and R, if Q.start preceeds + * R.start, then R.end preceeds Q.end. + * </ul> + * + * Where the shorthand "R is in body" means "R.start is in body, R.end is in body, and + * any InstructionHandle stored in a field of R (such as an exception handle) is in body". + */ + + public void assertGoodBody() { + // XXX this is REALLY slow since we get the string first... + assertGoodBody(getBody(), toString()); + } + + // XXX we might not want to release with any calls to this incredibly inefficient method. + public static void assertGoodBody(InstructionList il, String from) { + if (true) return; + if (il == null) return; + Set body = new HashSet(); + Stack ranges = new Stack(); + for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { + body.add(ih); + if (ih.getInstruction() instanceof BranchInstruction) { + body.add(ih.getInstruction()); + } + } + + for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { + assertGoodHandle(ih, body, ranges, from); + InstructionTargeter[] ts = ih.getTargeters(); + if (ts != null) { + for (int i = ts.length - 1; i >= 0; i--) { + assertGoodTargeter(ts[i], ih, body, from); + } + } + } + } + + private static void assertGoodHandle(InstructionHandle ih, Set body, Stack ranges, String from) { + Instruction inst = ih.getInstruction(); + if ((inst instanceof BranchInstruction) ^ (ih instanceof BranchHandle)) { + throw new BCException("bad instruction/handle pair in " + from); + } + if (Range.isRangeHandle(ih)) { + assertGoodRangeHandle(ih, body, ranges, from); + } else if (inst instanceof BranchInstruction) { + assertGoodBranchInstruction((BranchHandle) ih, (BranchInstruction) inst, body, ranges, from); + } + } + + private static void assertGoodBranchInstruction( + BranchHandle ih, + BranchInstruction inst, + Set body, + Stack ranges, + String from) + { + if (ih.getTarget() != inst.getTarget()) { + throw new BCException("bad branch instruction/handle pair in " + from); + } + InstructionHandle target = ih.getTarget(); + assertInBody(target, body, from); + assertTargetedBy(target, inst, from); + if (inst instanceof Select) { + Select sel = (Select) inst; + InstructionHandle[] itargets = sel.getTargets(); + for (int k = itargets.length - 1; k >= 0; k--) { + assertInBody(itargets[k], body, from); + assertTargetedBy(itargets[k], inst, from); + } + } + } + + /** ih is an InstructionHandle or a BranchInstruction */ + private static void assertInBody(Object ih, Set body, String from) { + if (! body.contains(ih)) throw new BCException("thing not in body in " + from); + } + + private static void assertGoodRangeHandle(InstructionHandle ih, Set body, Stack ranges, String from) { + Range r = getRangeAndAssertExactlyOne(ih, from); + assertGoodRange(r, body, from); + if (r.getStart() == ih) { + ranges.push(r); + } else if (r.getEnd() == ih) { + if (ranges.peek() != r) throw new BCException("bad range inclusion in " + from); + ranges.pop(); + } + } + + private static void assertGoodRange(Range r, Set body, String from) { + assertInBody(r.getStart(), body, from); + assertRangeHandle(r.getStart(), from); + assertTargetedBy(r.getStart(), r, from); + + assertInBody(r.getEnd(), body, from); + assertRangeHandle(r.getEnd(), from); + assertTargetedBy(r.getEnd(), r, from); + + if (r instanceof ExceptionRange) { + ExceptionRange er = (ExceptionRange) r; + assertInBody(er.getHandler(), body, from); + assertTargetedBy(er.getHandler(), r, from); + } + } + + private static void assertRangeHandle(InstructionHandle ih, String from) { + if (! Range.isRangeHandle(ih)) throw new BCException("bad range handle " + ih + " in " + from); + } + + + private static void assertTargetedBy( + InstructionHandle target, + InstructionTargeter targeter, + String from) + { + InstructionTargeter[] ts = target.getTargeters(); + if (ts == null) throw new BCException("bad targeting relationship in " + from); + for (int i = ts.length - 1; i >= 0; i--) { + if (ts[i] == targeter) return; + } + throw new RuntimeException("bad targeting relationship in " + from); + } + + private static void assertTargets(InstructionTargeter targeter, InstructionHandle target, String from) { + if (targeter instanceof Range) { + Range r = (Range) targeter; + if (r.getStart() == target || r.getEnd() == target) return; + if (r instanceof ExceptionRange) { + if (((ExceptionRange)r).getHandler() == target) return; + } + } else if (targeter instanceof BranchInstruction) { + BranchInstruction bi = (BranchInstruction) targeter; + if (bi.getTarget() == target) return; + if (targeter instanceof Select) { + Select sel = (Select) targeter; + InstructionHandle[] itargets = sel.getTargets(); + for (int k = itargets.length - 1; k >= 0; k--) { + if (itargets[k] == target) return; + } + } + } else if (targeter instanceof Tag) { + return; + } + throw new BCException(targeter + " doesn't target " + target + " in " + from ); + } + + private static Range getRangeAndAssertExactlyOne(InstructionHandle ih, String from) { + Range ret = null; + InstructionTargeter[] ts = ih.getTargeters(); + if (ts == null) throw new BCException("range handle with no range in " + from); + for (int i = ts.length - 1; i >= 0; i--) { + if (ts[i] instanceof Range) { + if (ret != null) throw new BCException("range handle with multiple ranges in " + from); + ret = (Range) ts[i]; + } + } + if (ret == null) throw new BCException("range handle with no range in " + from); + return ret; + } + + private static void assertGoodTargeter( + InstructionTargeter t, + InstructionHandle ih, + Set body, + String from) + { + assertTargets(t, ih, from); + if (t instanceof Range) { + assertGoodRange((Range) t, body, from); + } else if (t instanceof BranchInstruction) { + assertInBody(t, body, from); + } + } + + + // ---- + + boolean isAdviceMethod() { + return memberView.getAssociatedShadowMunger() != null; + } + + boolean isAjSynthetic() { + if (memberView == null) return true; + return memberView.isAjSynthetic(); + } + + public AjAttribute.EffectiveSignatureAttribute getEffectiveSignature() { + //if (memberView == null) return null; + return memberView.getEffectiveSignature(); + } + + public String getSignature() { + return Member.typesToSignature(BcelWorld.fromBcel(getReturnType()), + BcelWorld.fromBcel(getArgumentTypes())); + } + + public BcelMethod getMemberView() { + return memberView; + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/LineNumberTag.java b/weaver/src/org/aspectj/weaver/bcel/LineNumberTag.java new file mode 100644 index 000000000..ef5822f3a --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/LineNumberTag.java @@ -0,0 +1,39 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +/** we don't actually target instructions, but instructions target us. */ +public class LineNumberTag extends Tag { + + private final int lineNumber; + + public LineNumberTag(int lineNumber) { + this.lineNumber = lineNumber; + } + + public int getLineNumber() { return lineNumber; } + + // ---- from Object + + public String toString() { + return "line " + lineNumber; + } + public boolean equals(Object other) { + if (! (other instanceof LineNumberTag)) return false; + return lineNumber == ((LineNumberTag)other).lineNumber; + } + public int hashCode() { + return lineNumber; + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/LocalVariableTag.java b/weaver/src/org/aspectj/weaver/bcel/LocalVariableTag.java new file mode 100644 index 000000000..609dac005 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/LocalVariableTag.java @@ -0,0 +1,60 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.aspectj.weaver.TypeX; + +public final class LocalVariableTag extends Tag { + private final TypeX type; + private final String name; + private final int slot; + + public LocalVariableTag(TypeX type, String name, int slot) { + this.type = type; + this.name = name; + this.slot = slot; + } + + public String getName() { + return name; + } + public int getSlot() { + return slot; + } + public TypeX getType() { + return type; + } + + // ---- from Object + + public String toString() { + return "local " + slot + ": " + type + " " + name; + } + public boolean equals(Object other) { + if (!(other instanceof LocalVariableTag)) return false; + LocalVariableTag o = (LocalVariableTag)other; + return o.type.equals(type) && o.name.equals(name) && o.slot == slot; + } + private volatile int hashCode = 0; + public int hashCode() { + if (hashCode == 0) { + int ret = 17; + ret = 37*ret + type.hashCode(); + ret = 37*ret + name.hashCode(); + ret = 37*ret + slot; + hashCode = ret; + } + return hashCode; + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/Range.java b/weaver/src/org/aspectj/weaver/bcel/Range.java new file mode 100644 index 000000000..0d6eb21b6 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/Range.java @@ -0,0 +1,225 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.lang.reflect.Modifier; +import java.util.Map; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.IntMap; + +abstract class Range implements InstructionTargeter { + + protected InstructionList body; + protected InstructionHandle start; + protected InstructionHandle end; + + // ---- initialization + + protected Range(InstructionList il) { + this.body = il; + } + + + // ---- + + final InstructionList getBody() { + return body; + } + final InstructionHandle getStart() { + return start; + } + final InstructionHandle getEnd() { + return end; + } + + // ---- + + boolean isEmpty() { + InstructionHandle ih = start; + while (ih != end) { + if (! Range.isRangeHandle(ih)) return false; + ih = ih.getNext(); + } + return true; + } + + static InstructionHandle getRealStart(InstructionHandle ih) { + while (Range.isRangeHandle(ih)) { + ih = ih.getNext(); + } + return ih; + } + + InstructionHandle getRealStart() { + return getRealStart(start); + } + + static InstructionHandle getRealEnd(InstructionHandle ih) { + while (Range.isRangeHandle(ih)) { + ih = ih.getPrev(); + } + return ih; + } + InstructionHandle getRealEnd() { + return getRealEnd(end); + } + + static InstructionHandle getRealPrev(InstructionHandle ih) { + InstructionHandle ret = ih.getPrev(); + while (isRangeHandle(ret)) { + ret = ret.getPrev(); + } + return ret; + } + + // ---- + + InstructionHandle insert(Instruction i, Where where) { + InstructionList il = new InstructionList(); + InstructionHandle ret = il.insert(i); + insert(il, where); + return ret; + } + void insert(InstructionList freshIl, Where where) { + InstructionHandle h; + if (where == InsideBefore || where == OutsideBefore) { + h = getStart(); + } else { + h = getEnd(); + } + if (where == InsideBefore || where == OutsideAfter) { + body.append(h, freshIl); + } else { + InstructionHandle newStart = body.insert(h, freshIl); + if (where == OutsideBefore) { + // XXX this is slow. There's a better design than this. We should + // never have to retarget branches apart from the creation of ranges. + // basically, we should never weave OutsideBefore. + BcelShadow.retargetAllBranches(h, newStart); + } + } + + } + InstructionHandle append(Instruction i) { + return insert(i, InsideAfter); + } + void append(InstructionList i) { + insert(i, InsideAfter); + } + + static InstructionHandle remap(InstructionHandle h, Map m) { + return (InstructionHandle) m.get(h); + } + + private static void setLineNumberFromNext(InstructionHandle ih) { + int lineNumber = Utility.getSourceLine(ih.getNext()); + if (lineNumber != -1) { + Utility.setSourceLine(ih, lineNumber); + } + } + + static InstructionHandle genStart(InstructionList body) { + InstructionHandle ih = body.insert(Range.RANGEINSTRUCTION); + setLineNumberFromNext(ih); + return ih; + } + + static InstructionHandle genEnd(InstructionList body) { + return body.append(Range.RANGEINSTRUCTION); + } + static InstructionHandle genStart(InstructionList body, InstructionHandle ih) { + if (ih == null) return genStart(body); + InstructionHandle freshIh = body.insert(ih, Range.RANGEINSTRUCTION); + setLineNumberFromNext(freshIh); + return freshIh; + } + + static InstructionHandle genEnd(InstructionList body, InstructionHandle ih) { + if (ih == null) return genEnd(body); + return body.append(ih, Range.RANGEINSTRUCTION); + } + + // ----- + + public boolean containsTarget(InstructionHandle ih) { + return false; + } + + public final void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) { + throw new RuntimeException("Ranges must be updated with an enclosing instructionList"); + } + + protected void updateTarget( + InstructionHandle old_ih, + InstructionHandle new_ih, + InstructionList new_il) + { + old_ih.removeTargeter(this); + if (new_ih != null) + new_ih.addTargeter(this); + body = new_il; + + if (old_ih == start) { + start = new_ih; + } + if (old_ih == end) { + end = new_ih; + } + } + + public static final boolean isRangeHandle(InstructionHandle ih) { + if (ih == null) return false; + return ih.getInstruction() == Range.RANGEINSTRUCTION; + } + + protected static final Range getRange(InstructionHandle ih) { + // assert isRangeHandle(ih) + Range ret = null; + InstructionTargeter[] targeters = ih.getTargeters(); + for (int i = targeters.length - 1; i >= 0; i--) { + if (targeters[i] instanceof Range) { + Range r = (Range) targeters[i]; + if (r.getStart() != ih && r.getEnd() != ih) continue; + if (ret != null) throw new BCException("multiple ranges on same range handle: " + ret + ", " + targeters[i]); + ret = (Range) targeters[i]; + } + } + if (ret == null) throw new BCException("shouldn't happen"); + return ret; + } + + // ---- + + static final Where InsideBefore = new Where("insideBefore"); + static final Where InsideAfter = new Where("insideAfter"); + static final Where OutsideBefore = new Where("outsideBefore"); + static final Where OutsideAfter = new Where("outsideAfter"); + + // ---- constants + + // note that this is STUPIDLY copied by Instruction.copy(), so don't do that. + + public static final Instruction RANGEINSTRUCTION = new IMPDEP1(); + + // ---- + + static class Where { + private String name; + public Where(String name) { this.name = name; } + public String toString() { return name; } + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/ShadowRange.java b/weaver/src/org/aspectj/weaver/bcel/ShadowRange.java new file mode 100644 index 000000000..edd22db95 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/ShadowRange.java @@ -0,0 +1,199 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; + +final class ShadowRange extends Range { + + private BcelShadow shadow; + + // ---- initialization + + /** + * After this constructor is called, this range is not well situated unless both + * {@link #associateWithTargets} and {@link #associateWithShadow} are called. + */ + public ShadowRange(InstructionList body) { + super(body); + } + protected void associateWithTargets(InstructionHandle start, InstructionHandle end) { + // assert body.contains(start) && body.contains(end); + this.start = start; + this.end = end; + start.addTargeter(this); + end.addTargeter(this); + } + public void associateWithShadow(BcelShadow shadow) { + this.shadow = shadow; + shadow.setRange(this); + } + + // ---- + + public Shadow.Kind getKind() { + return shadow.getKind(); + } + + public String toString() { + return shadow.toString(); + } + + void extractInstructionsInto(LazyMethodGen freshMethod, IntMap remap, boolean addReturn) { + LazyMethodGen.assertGoodBody(getBody(), toString()); + freshMethod.assertGoodBody(); + InstructionList freshBody = freshMethod.getBody(); + + for (InstructionHandle oldIh = start.getNext(); oldIh != end; oldIh = oldIh.getNext()) { + // first we copy the instruction itself. + Instruction oldI = oldIh.getInstruction(); + Instruction freshI = (oldI == RANGEINSTRUCTION) ? oldI : oldI.copy(); + + // Now we add it to the new instruction list. + InstructionHandle freshIh; + if (freshI instanceof BranchInstruction) { + //If it's a targeting instruction, + // update the target(s) to point to the new copy instead of the old copy. + BranchInstruction oldBranch = (BranchInstruction) oldI; + BranchInstruction freshBranch = (BranchInstruction) freshI; + InstructionHandle oldTarget = oldBranch.getTarget(); + oldTarget.removeTargeter(oldBranch); + oldTarget.addTargeter(freshBranch); + if (freshBranch instanceof Select) { + Select oldSelect = (Select) oldI; + Select freshSelect = (Select) freshI; + InstructionHandle[] oldTargets = freshSelect.getTargets(); + for (int k = oldTargets.length - 1; k >= 0; k--) { + oldTargets[k].removeTargeter(oldSelect); + oldTargets[k].addTargeter(freshSelect); + } + } + freshIh = freshBody.append(freshBranch); + } else { + freshIh = freshBody.append(freshI); + } + + // if source comes before target: + // source <--> target + // --> [process: target.removeTargeter(source); target.addTargeter(sourcecopy)] + // source ---------\ + // v + // sourcecopy <--> target + // --> [ process: sourcecopy.updateTarget(target, targetcopy) ] + // source ----> target + // sourcecopy <--> targetcopy + + // if target comes before source + + // target <--> source + // --> [process: source.updateTarget(target, targetcopy) ] + // target + // targetcopy <--> source + // --> [process: targetcopy.removeTargeter(source); targetcopy.addTargeter(sourcecopy)] + // target source + // v + // targetcopy <--> sourcecopy + + // now deal with the old instruction's targeters. Update them all to point to us + // instead of the old instruction. We use updateTarget to do this. One goal is + // to make sure we remove all targeters from the old guy, so we can successfully + // delete it. + InstructionTargeter[] sources = oldIh.getTargeters(); + if (sources != null) { + for (int j = sources.length - 1; j >= 0; j--) { + InstructionTargeter source = sources[j]; + if (source instanceof LocalVariableTag) { + // XXX destroying local variable info + source.updateTarget(oldIh, null); + } else if (source instanceof Range) { + // exceptions and shadows are just moved + ((Range)source).updateTarget(oldIh, freshIh, freshBody); + } else { + // line numbers can be shared, + // branches will be copied along with us. + source.updateTarget(oldIh, freshIh); + } + } + } + // we're now done with the old instruction entirely, and will ignore them through + // the rest of this loop. The only time we'll see them again is a second pass to + // delete them. + + // now deal with local variable instructions. If this points to a remapped + // frame location, update the instruction's index. If this doesn't, + // do compaction/expansion: allocate a new local variable, and modify the remap + // to handle it. XXX We're doing the safe thing and allocating ALL these local variables + // as double-wides, in case the location is found to hold a double-wide later. + if (freshI instanceof LocalVariableInstruction || freshI instanceof RET) { + IndexedInstruction indexedI = (IndexedInstruction) freshI; + int oldIndex = indexedI.getIndex(); + int freshIndex; + if (! remap.hasKey(oldIndex)) { + freshIndex = freshMethod.allocateLocal(2); + remap.put(oldIndex, freshIndex); + } else { + freshIndex = remap.get(oldIndex); + } + indexedI.setIndex(freshIndex); + } +// System.err.println("JUST COPIED: " + oldIh.getInstruction().toString(freshMethod.getEnclosingClass().getConstantPoolGen().getConstantPool()) +// + " INTO " + freshIh.getInstruction().toString(freshMethod.getEnclosingClass().getConstantPoolGen().getConstantPool())); + } + + // we've now copied out all the instructions. + // now delete the instructions... we've already taken care of the damn + // targets, but since TargetLostException is checked, we have to do this stuff. + try { + for (InstructionHandle oldIh = start.getNext(); oldIh != end; ) { + InstructionHandle next = oldIh.getNext(); + body.delete(oldIh); + oldIh = next; + } + } catch (TargetLostException e) { + throw new BCException("shouldn't have gotten a target lost"); + } + + // now add the return, if one is warranted. + InstructionHandle ret = null; + if (addReturn) { + // we really should pull this out somewhere... + ret = freshBody.append( + new InstructionFactory(freshMethod.getEnclosingClass().getConstantPoolGen()) + .createReturn(freshMethod.getReturnType())); + } + // and remap all the old targeters of the end handle of the range to the return. + InstructionTargeter[] ts = end.getTargeters(); + if (ts != null) { // shouldn't be the case, but let's test for paranoia + for (int j = ts.length - 1; j >= 0; j--) { + InstructionTargeter t = ts[j]; + if (t == this) continue; + if (! addReturn) { + throw new BCException("range has target, but we aren't adding a return"); + } else { + t.updateTarget(end, ret); + } + } + } + + LazyMethodGen.assertGoodBody(getBody(), toString()); + freshMethod.assertGoodBody(); + } + + public BcelShadow getShadow() { + return shadow; + } + + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/Tag.java b/weaver/src/org/aspectj/weaver/bcel/Tag.java new file mode 100644 index 000000000..cfa5eb41f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/Tag.java @@ -0,0 +1,42 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import org.apache.bcel.generic.*; + +/** A tag is an instruction-targeter that doesn't bother remembering its target(s) */ +abstract class Tag implements InstructionTargeter, Cloneable { + + public Tag() { + } + + // ---- from InstructionTargeter + public boolean containsTarget(InstructionHandle ih) { + return false; + } + + public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) { + old_ih.removeTargeter(this); + if (new_ih != null) + new_ih.addTargeter(this); + } + + public Tag copy() { + try { + return (Tag)clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException("Sanity check, can't clone me"); + } + } +} diff --git a/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java b/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java new file mode 100644 index 000000000..9ea49d53f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/UnwovenClassFile.java @@ -0,0 +1,181 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.util.*; + +import org.apache.bcel.classfile.JavaClass; +import org.aspectj.util.FileUtil; + +public class UnwovenClassFile { + protected String filename; + protected byte[] bytes; +// protected JavaClass javaClass = null; + protected byte[] writtenBytes = null; + protected List /* ChildClass */ writtenChildClasses = new ArrayList(0); + protected String className = null; + + public UnwovenClassFile(String filename, byte[] bytes) { + this.filename = filename; + this.bytes = bytes; + } + + public String getFilename() { + return filename; + } + + public String makeInnerFileName(String innerName) { + String prefix = filename.substring(0, filename.length()-6); // strip the .class + return prefix + "$" + innerName + ".class"; + } + + public byte[] getBytes() { +// if (bytes == null) bytes = javaClass.getBytes(); + return bytes; + } + + public JavaClass getJavaClass() { + //XXX need to know when to make a new class and when not to + //XXX this is an important optimization + if (getBytes() == null) { + System.out.println("no bytes for: " + getFilename()); + Thread.currentThread().dumpStack(); + } + return Utility.makeJavaClass(filename, getBytes()); +// if (javaClass == null) javaClass = Utility.makeJavaClass(filename, getBytes()); +// return javaClass; + } + + public boolean exists() { + return getBytes() != null; + } + + + public void writeUnchangedBytes() throws IOException { + writeWovenBytes(getBytes(), Collections.EMPTY_LIST); + } + + public void writeWovenBytes(byte[] bytes, List childClasses) throws IOException { + writeChildClasses(childClasses); + + //System.err.println("about to write: " + this + ", " + writtenBytes + ", "); +// + writtenBytes != null + " && " + unchanged(bytes, writtenBytes) ); + + if (writtenBytes != null && !unchanged(bytes, writtenBytes)) return; + + BufferedOutputStream os = FileUtil.makeOutputStream(new File(filename)); + os.write(bytes); + os.close(); + + writtenBytes = bytes; + } + + private void writeChildClasses(List childClasses) throws IOException { + //??? we only really need to delete writtenChildClasses whose + //??? names aren't in childClasses; however, it's unclear + //??? how much that will affect performance + deleteAllChildClasses(); + + childClasses.removeAll(writtenChildClasses); //XXX is this right + + for (Iterator iter = childClasses.iterator(); iter.hasNext();) { + ChildClass childClass = (ChildClass) iter.next(); + writeChildClassFile(childClass.name, childClass.bytes); + + } + + writtenChildClasses = childClasses; + + } + + private void writeChildClassFile(String innerName, byte[] bytes) throws IOException { + BufferedOutputStream os = + FileUtil.makeOutputStream(new File(makeInnerFileName(innerName))); + os.write(bytes); + os.close(); + } + + + protected void deleteAllChildClasses() { + for (Iterator iter = writtenChildClasses.iterator(); iter.hasNext();) { + ChildClass childClass = (ChildClass) iter.next(); + deleteChildClassFile(childClass.name); + } + } + + protected void deleteChildClassFile(String innerName) { + File childClassFile = new File(makeInnerFileName(innerName)); + childClassFile.delete(); + } + + + + private static boolean unchanged(byte[] b1, byte[] b2) { + int len = b1.length; + if (b2.length != len) return false; + for (int i=0; i < len; i++) { + if (b1[i] != b2[i]) return false; + } + return true; + } + + + public String getClassName() { + if (className == null) className = getJavaClass().getClassName(); + return className; + } + public byte[] getWrittenBytes() { + return writtenBytes; + } + + public String toString() { + return "UnwovenClassFile(" + filename + ", " + getClassName() + ")"; + } + + public void deleteRealFile() throws IOException { + new File(filename).delete(); + } + + + + + // record + public static class ChildClass { + public final String name; + public final byte[] bytes; + + ChildClass(String name, byte[] bytes) { + this.name = name; + this.bytes = bytes; + } + + public boolean equals(Object other) { + if (! (other instanceof ChildClass)) return false; + ChildClass o = (ChildClass) other; + return o.name.equals(name) && unchanged(o.bytes, bytes); + } + public int hashCode() { + return name.hashCode(); + } + + public String toString() { + return "(ChildClass " + name + ")"; + } + } +} + + + + diff --git a/weaver/src/org/aspectj/weaver/bcel/UnwovenZipClassFile.java b/weaver/src/org/aspectj/weaver/bcel/UnwovenZipClassFile.java new file mode 100644 index 000000000..2c4c760a9 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/UnwovenZipClassFile.java @@ -0,0 +1,45 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; +import java.util.List; +import java.util.zip.*; + +//XXX we believe this is now unneeded +public class UnwovenZipClassFile extends UnwovenClassFile { + private ZipOutputStream zipOutputStream; + + public UnwovenZipClassFile(ZipOutputStream zipOutputStream, String filename, byte[] bytes) { + super(filename, bytes); + this.zipOutputStream = zipOutputStream; + } + + + public void writeWovenBytes(byte[] bytes, List childClasses) throws IOException { + //??? we rewrite this every time + if (!childClasses.isEmpty()) { + throw new RuntimeException("unimplemented"); + } + + ZipEntry newEntry = new ZipEntry(filename); //??? get compression scheme right + + zipOutputStream.putNextEntry(newEntry); + zipOutputStream.write(bytes); + zipOutputStream.closeEntry(); + + writtenBytes = bytes; + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/Utility.java b/weaver/src/org/aspectj/weaver/bcel/Utility.java new file mode 100644 index 000000000..9da48c01f --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/Utility.java @@ -0,0 +1,442 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.lang.reflect.Modifier; + +import org.apache.bcel.Constants; +import org.apache.bcel.classfile.*; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; + +public class Utility { + + private Utility() { + super(); + } + + + public static Instruction createSuperInvoke( + InstructionFactory fact, + BcelWorld world, + Member signature) { + short kind; + if (signature.isInterface()) { + throw new RuntimeException("bad"); + } else if (signature.isPrivate() || signature.getName().equals("<init>")) { + throw new RuntimeException("unimplemented, possibly bad"); + } else if (signature.isStatic()) { + throw new RuntimeException("bad"); + } else { + kind = Constants.INVOKESPECIAL; + } + + return fact.createInvoke( + signature.getDeclaringType().getName(), + signature.getName(), + world.makeBcelType(signature.getReturnType()), + world.makeBcelTypes(signature.getParameterTypes()), + kind); + } + + // XXX don't need the world now + public static Instruction createInvoke( + InstructionFactory fact, + BcelWorld world, + Member signature) { + short kind; + if (signature.isInterface()) { + kind = Constants.INVOKEINTERFACE; + } else if (signature.isPrivate() || signature.getName().equals("<init>")) { + kind = Constants.INVOKESPECIAL; + } else if (signature.isStatic()) { + kind = Constants.INVOKESTATIC; + } else { + kind = Constants.INVOKEVIRTUAL; + } + + return fact.createInvoke( + signature.getDeclaringType().getName(), + signature.getName(), + BcelWorld.makeBcelType(signature.getReturnType()), + BcelWorld.makeBcelTypes(signature.getParameterTypes()), + kind); + } + + public static Instruction createGet(InstructionFactory fact, Member signature) { + short kind; + if (signature.isStatic()) { + kind = Constants.GETSTATIC; + } else { + kind = Constants.GETFIELD; + } + + return fact.createFieldAccess( + signature.getDeclaringType().getName(), + signature.getName(), + BcelWorld.makeBcelType(signature.getReturnType()), + kind); + } + + public static Instruction createSet(InstructionFactory fact, Member signature) { + short kind; + if (signature.isStatic()) { + kind = Constants.PUTSTATIC; + } else { + kind = Constants.PUTFIELD; + } + + return fact.createFieldAccess( + signature.getDeclaringType().getName(), + signature.getName(), + BcelWorld.makeBcelType(signature.getReturnType()), + kind); + } + + public static Instruction createInvoke( + InstructionFactory fact, + JavaClass declaringClass, + Method newMethod) { + short kind; + if (newMethod.isInterface()) { + kind = Constants.INVOKEINTERFACE; + } else if (newMethod.isPrivate() || newMethod.getName().equals("<init>")) { + kind = Constants.INVOKESPECIAL; + } else if (newMethod.isStatic()) { + kind = Constants.INVOKESTATIC; + } else { + kind = Constants.INVOKEVIRTUAL; + } + + return fact.createInvoke( + declaringClass.getClassName(), + newMethod.getName(), + Type.getReturnType(newMethod.getSignature()), + Type.getArgumentTypes(newMethod.getSignature()), + kind); + } + + public static Instruction createInstanceof(InstructionFactory fact, ObjectType t) { + return new INSTANCEOF(fact.getConstantPool().addClass(t)); + } + + + public static Instruction createInvoke( + InstructionFactory fact, + LazyMethodGen m) { + short kind; + if (m.getEnclosingClass().isInterface()) { + kind = Constants.INVOKEINTERFACE; + } else if (m.isPrivate() || m.getName().equals("<init>")) { + kind = Constants.INVOKESPECIAL; + } else if (m.isStatic()) { + kind = Constants.INVOKESTATIC; + } else { + kind = Constants.INVOKEVIRTUAL; + } + + return fact.createInvoke( + m.getClassName(), + m.getName(), + m.getReturnType(), + m.getArgumentTypes(), + kind); + } + + + // ??? these should perhaps be cached. Remember to profile this to see if it's a problem. + public static String[] makeArgNames(int n) { + String[] ret = new String[n]; + for (int i=0; i<n; i++) { + ret[i] = "arg" + i; + } + return ret; + } + + public static void appendConversion( + InstructionList il, + InstructionFactory fact, + ResolvedTypeX fromType, + ResolvedTypeX toType) + { + if (! toType.isConvertableFrom(fromType)) { + throw new BCException("can't convert from " + fromType + " to " + toType); + } + if (toType.needsNoConversionFrom(fromType)) return; + + if (toType.equals(ResolvedTypeX.VOID)) { + // assert fromType.equals(TypeX.OBJECT) + il.append(fact.createPop(fromType.getSize())); + } else if (fromType.equals(ResolvedTypeX.VOID)) { + // assert toType.equals(TypeX.OBJECT) + il.append(fact.createNull(Type.OBJECT)); + return; + } else if (fromType.equals(TypeX.OBJECT)) { + Type to = BcelWorld.makeBcelType(toType); + if (toType.isPrimitive()) { + String name = toType.toString() + "Value"; + il.append( + fact.createInvoke( + "org.aspectj.runtime.internal.Conversions", + name, + to, + new Type[] { Type.OBJECT }, + Constants.INVOKESTATIC)); + } else { + il.append(fact.createCheckCast((ReferenceType)to)); + } + } else if (toType.equals(TypeX.OBJECT)) { + // assert fromType.isPrimitive() + Type from = BcelWorld.makeBcelType(fromType); + String name = fromType.toString() + "Object"; + il.append( + fact.createInvoke( + "org.aspectj.runtime.internal.Conversions", + name, + Type.OBJECT, + new Type[] { from }, + Constants.INVOKESTATIC)); + } else if (fromType.isPrimitive()) { + // assert toType.isPrimitive() + Type from = BcelWorld.makeBcelType(fromType); + Type to = BcelWorld.makeBcelType(toType); + try { + il.append(fact.createCast(from, to)); + } catch (RuntimeException e) { + il.append(fact.createCast(from, Type.INT)); + il.append(fact.createCast(Type.INT, to)); + } + } else { + Type to = BcelWorld.makeBcelType(toType); + // assert ! fromType.isPrimitive() && ! toType.isPrimitive() + il.append(fact.createCheckCast((ReferenceType) to)); + } + } + + + public static InstructionList createConversion( + InstructionFactory fact, + Type fromType, + Type toType) { + //System.out.println("cast to: " + toType); + + InstructionList il = new InstructionList(); + if (fromType.equals(toType)) + return il; + if (toType.equals(Type.VOID)) { + il.append(fact.createPop(fromType.getSize())); + return il; + } + + if (fromType.equals(Type.VOID)) { + if (toType instanceof BasicType) + throw new BCException("attempting to cast from void to basic type"); + il.append(fact.createNull(Type.OBJECT)); + return il; + } + + if (fromType.equals(Type.OBJECT)) { + if (toType instanceof BasicType) { + String name = toType.toString() + "Value"; + il.append( + fact.createInvoke( + "org.aspectj.runtime.internal.Conversions", + name, + toType, + new Type[] { Type.OBJECT }, + Constants.INVOKESTATIC)); + return il; + } + } + + if (toType.equals(Type.OBJECT)) { + if (fromType instanceof BasicType) { + String name = fromType.toString() + "Object"; + il.append( + fact.createInvoke( + "org.aspectj.runtime.internal.Conversions", + name, + Type.OBJECT, + new Type[] { fromType }, + Constants.INVOKESTATIC)); + return il; + } else if (fromType instanceof ReferenceType) { + return il; + } else { + throw new RuntimeException(); + } + } + + if (fromType instanceof ReferenceType + && ((ReferenceType)fromType).isAssignmentCompatibleWith(toType)) { + return il; + } + + il.append(fact.createCast(fromType, toType)); + return il; + } + + public static Instruction createConstant( + InstructionFactory fact, + int i) { + Instruction inst; + switch(i) { + case -1: inst = fact.ICONST_M1; break; + case 0: inst = fact.ICONST_0; break; + case 1: inst = fact.ICONST_1; break; + case 2: inst = fact.ICONST_2; break; + case 3: inst = fact.ICONST_3; break; + case 4: inst = fact.ICONST_4; break; + case 5: inst = fact.ICONST_5; break; + } + if (i <= Byte.MAX_VALUE && i >= Byte.MIN_VALUE) { + inst = new BIPUSH((byte)i); + } else if (i <= Short.MAX_VALUE && i >= Short.MIN_VALUE) { + inst = new SIPUSH((short)i); + } else { + inst = new LDC(fact.getClassGen().getConstantPool().addInteger(i)); + } + return inst; + } + + public static JavaClass makeJavaClass(String filename, byte[] bytes) { + try { + ClassParser parser = new ClassParser(new ByteArrayInputStream(bytes), filename); + return parser.parse(); + } catch (IOException e) { + throw new BCException("malformed class file"); + } + } + + public static String arrayToString(int[] a) { + int len = a.length; + if (len == 0) return "[]"; + StringBuffer buf = new StringBuffer("["); + buf.append(a[0]); + for (int i = 1; i < len; i++) { + buf.append(", "); + buf.append(a[i]); + } + buf.append("]"); + return buf.toString(); + } + + /** + * replace an instruction handle with another instruction, in this case, a branch instruction. + * + * @param ih the instruction handle to replace. + * @param branchInstruction the branch instruction to replace ih with + * @param enclosingMethod where to find ih's instruction list. + */ + public static void replaceInstruction( + InstructionHandle ih, + BranchInstruction branchInstruction, + LazyMethodGen enclosingMethod) + { + + InstructionList il = enclosingMethod.getBody(); + InstructionHandle fresh = il.append(ih, branchInstruction); + deleteInstruction(ih, fresh, enclosingMethod); + } + + /** delete an instruction handle and retarget all targeters of the deleted instruction + * to the next instruction. Obviously, this should not be used to delete + * a control transfer instruction unless you know what you're doing. + * + * @param ih the instruction handle to delete. + * @param enclosingMethod where to find ih's instruction list. + */ + public static void deleteInstruction( + InstructionHandle ih, + LazyMethodGen enclosingMethod) + { + deleteInstruction(ih, ih.getNext(), enclosingMethod); + } + + + /** delete an instruction handle and retarget all targeters of the deleted instruction + * to the provided target. + * + * @param ih the instruction handle to delete + * @param retargetTo the instruction handle to retarget targeters of ih to. + * @param enclosingMethod where to find ih's instruction list. + */ + public static void deleteInstruction( + InstructionHandle ih, + InstructionHandle retargetTo, + LazyMethodGen enclosingMethod) + { + InstructionList il = enclosingMethod.getBody(); + InstructionTargeter[] targeters = ih.getTargeters(); + if (targeters != null) { + for (int i = targeters.length - 1; i >= 0; i--) { + InstructionTargeter targeter = targeters[i]; + targeter.updateTarget(ih, retargetTo); + } + ih.removeAllTargeters(); + } + try { + il.delete(ih); + } catch (TargetLostException e) { + throw new BCException("this really can't happen"); + } + } + + /** returns -1 if no source line attribute */ + public static int getSourceLine(InstructionHandle ih) { + InstructionTargeter[] ts = ih.getTargeters(); + if (ts != null) { + for (int j = ts.length - 1; j >= 0; j--) { + InstructionTargeter t = ts[j]; + if (t instanceof LineNumberTag) { + return ((LineNumberTag)t).getLineNumber(); + } + } + } + return -1; + } + + // assumes that there is no already extant source line tag. Otherwise we'll have to be better. + public static void setSourceLine(InstructionHandle ih, int lineNumber) { + ih.addTargeter(new LineNumberTag(lineNumber)); + } + + public static int makePublic(int i) { + return i & ~(Modifier.PROTECTED | Modifier.PRIVATE) | Modifier.PUBLIC; + } + public static int makePrivate(int i) { + return i & ~(Modifier.PROTECTED | Modifier.PUBLIC) | Modifier.PRIVATE; + } + public static BcelVar[] pushAndReturnArrayOfVars( + ResolvedTypeX[] proceedParamTypes, + InstructionList il, + InstructionFactory fact, + LazyMethodGen enclosingMethod) + { + int len = proceedParamTypes.length; + BcelVar[] ret = new BcelVar[len]; + + for (int i = len - 1; i >= 0; i--) { + ResolvedTypeX typeX = proceedParamTypes[i]; + Type type = BcelWorld.makeBcelType(typeX); + int local = enclosingMethod.allocateLocal(type); + + il.append(fact.createStore(type, local)); + ret[i] = new BcelVar(typeX, local); + } + return ret; + } + +} diff --git a/weaver/src/org/aspectj/weaver/bcel/ZipFileWeaver.java b/weaver/src/org/aspectj/weaver/bcel/ZipFileWeaver.java new file mode 100644 index 000000000..c243ec6bf --- /dev/null +++ b/weaver/src/org/aspectj/weaver/bcel/ZipFileWeaver.java @@ -0,0 +1,41 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.util.zip.*; + +import org.aspectj.util.FileUtil; + + +//XXX delete very soon +public class ZipFileWeaver { + File inFile; + public ZipFileWeaver(File inFile) { + super(); + this.inFile = inFile; + } + + public void weave(BcelWeaver weaver, File outFile) throws IOException { + int count = 0; + long startTime = System.currentTimeMillis(); + weaver.addJarFile(inFile, new File(".")); + weaver.weave(outFile); + long stopTime = System.currentTimeMillis(); + + + System.out.println("handled " + count + " entries, in " + + (stopTime-startTime)/1000. + " seconds"); + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java b/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java new file mode 100644 index 000000000..96a2b4ce2 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/AndPointcut.java @@ -0,0 +1,84 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.Map; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.util.*; + +public class AndPointcut extends Pointcut { + Pointcut left, right; // exposed for testing + + public AndPointcut(Pointcut left, Pointcut right) { + super(); + this.left = left; + this.right = right; + setLocation(left.getSourceContext(), left.getStart(), right.getEnd()); + } + + public FuzzyBoolean match(Shadow shadow) { + return left.match(shadow).and(right.match(shadow)); + } + + public String toString() { + return "(" + left.toString() + " && " + right.toString() + ")"; + } + + public boolean equals(Object other) { + if (!(other instanceof AndPointcut)) return false; + AndPointcut o = (AndPointcut)other; + return o.left.equals(left) && o.right.equals(right); + } + + public int hashCode() { + int result = 19; + result = 37*result + left.hashCode(); + result = 37*result + right.hashCode(); + return result; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + left.resolveBindings(scope, bindings); + right.resolveBindings(scope, bindings); + } + + + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.AND); + left.write(s); + right.write(s); + writeLocation(s); + } + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + AndPointcut ret = new AndPointcut(Pointcut.read(s, context), Pointcut.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + + public Test findResidue(Shadow shadow, ExposedState state) { + return Test.makeAnd(left.findResidue(shadow, state), right.findResidue(shadow, state)); + } + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + return new AndPointcut(left.concretize1(inAspect, bindings), + right.concretize1(inAspect, bindings)); + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java new file mode 100644 index 000000000..86a63f971 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/AndTypePattern.java @@ -0,0 +1,79 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; + +/** + * left && right + * + * <p>any binding to formals is explicitly forbidden for any composite by the language + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public class AndTypePattern extends TypePattern { + private TypePattern left, right; + + public AndTypePattern(TypePattern left, TypePattern right) { + super(false); //??? we override all methods that care about includeSubtypes + this.left = left; + this.right = right; + setLocation(left.getSourceContext(), left.getStart(), right.getEnd()); + } + + public FuzzyBoolean matchesInstanceof(ResolvedTypeX type) { + return left.matchesInstanceof(type).and(right.matchesInstanceof(type)); + } + + protected boolean matchesExactly(ResolvedTypeX type) { + //??? if these had side-effects, this sort-circuit could be a mistake + return left.matchesExactly(type) && right.matchesExactly(type); + } + + public boolean matchesStatically(ResolvedTypeX type) { + return left.matchesStatically(type) && right.matchesStatically(type); + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(TypePattern.AND); + left.write(s); + right.write(s); + writeLocation(s); + } + + public static TypePattern read(DataInputStream s, ISourceContext context) throws IOException { + TypePattern ret = new AndTypePattern(TypePattern.read(s, context), TypePattern.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + public TypePattern resolveBindings( + IScope scope, + Bindings bindings, + boolean allowBinding) { + left = left.resolveBindings(scope, bindings, false); + right = right.resolveBindings(scope, bindings, false); + return this; + } + + public String toString() { + return "(" + left.toString() + " && " + right.toString() + ")"; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java new file mode 100644 index 000000000..4c3d22449 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ArgsPointcut.java @@ -0,0 +1,140 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; + +/** + * args(arguments) + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public class ArgsPointcut extends NameBindingPointcut { + TypePatternList arguments; + + public ArgsPointcut(TypePatternList arguments) { + this.arguments = arguments; + } + + public FuzzyBoolean match(Shadow shadow) { + int n = shadow.getArgCount(); + TypeX[] argTypes = new TypeX[n]; + for (int i=0; i < n; i++) { + argTypes[i] = shadow.getArgType(i); + } + FuzzyBoolean ret = + arguments.matches(shadow.getIWorld().resolve(argTypes), TypePattern.DYNAMIC); + return ret; + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.ARGS); + arguments.write(s); + writeLocation(s); + } + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + ArgsPointcut ret = new ArgsPointcut(TypePatternList.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + + public boolean equals(Object other) { + if (!(other instanceof ArgsPointcut)) return false; + ArgsPointcut o = (ArgsPointcut)other; + return o.arguments.equals(this.arguments); + } + + public int hashCode() { + return arguments.hashCode(); + } + + public void resolveBindings(IScope scope, Bindings bindings) { + arguments.resolveBindings(scope, bindings, true); + } + + public void postRead(ResolvedTypeX enclosingType) { + arguments.postRead(enclosingType); + } + + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + return new ArgsPointcut(arguments.resolveReferences(bindings)); + } + + private Test findResidueNoEllipsis(Shadow shadow, ExposedState state, TypePattern[] patterns) { + int len = shadow.getArgCount(); + //System.err.println("boudn to : " + len + ", " + patterns.length); + if (patterns.length != len) { + throw new RuntimeException("this should never happen"); + //return Literal.FALSE; //??? this should never happen + } + + Test ret = Literal.TRUE; + + for (int i=0; i < len; i++) { + TypeX argType = shadow.getArgType(i); + TypePattern type = patterns[i]; + if (!(type instanceof BindingTypePattern)) { + if (type.matchesInstanceof(shadow.getIWorld().resolve(argType)).alwaysTrue()) { + continue; + } + } + ret = Test.makeAnd(ret, + exposeStateForVar(shadow.getArgVar(i), type, state,shadow.getIWorld())); + } + + return ret; + } + + public Test findResidue(Shadow shadow, ExposedState state) { + int ellipsisCount = arguments.ellipsisCount; + if (ellipsisCount == 0) { + return findResidueNoEllipsis(shadow, state, arguments.getTypePatterns()); + } else if (ellipsisCount == 1) { + TypePattern[] patternsWithEllipsis = arguments.getTypePatterns(); + TypePattern[] patternsWithoutEllipsis = new TypePattern[shadow.getArgCount()]; + int lenWithEllipsis = patternsWithEllipsis.length; + int lenWithoutEllipsis = patternsWithoutEllipsis.length; + // l1+1 >= l0 + int indexWithEllipsis = 0; + int indexWithoutEllipsis = 0; + while (indexWithoutEllipsis < lenWithoutEllipsis) { + TypePattern p = patternsWithEllipsis[indexWithEllipsis++]; + if (p == TypePattern.ELLIPSIS) { + int newLenWithoutEllipsis = + lenWithoutEllipsis - (lenWithEllipsis-indexWithEllipsis); + while (indexWithoutEllipsis < newLenWithoutEllipsis) { + patternsWithoutEllipsis[indexWithoutEllipsis++] = TypePattern.ANY; + } + } else { + patternsWithoutEllipsis[indexWithoutEllipsis++] = p; + } + } + return findResidueNoEllipsis(shadow, state, patternsWithoutEllipsis); + } else { + throw new BetaException("unimplemented"); + } + } + + public String toString() { + return "args" + arguments.toString() + ""; + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/BasicToken.java b/weaver/src/org/aspectj/weaver/patterns/BasicToken.java new file mode 100644 index 000000000..9a36b35e7 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/BasicToken.java @@ -0,0 +1,75 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + + +public class BasicToken implements IToken { + private String value; + private boolean isIdentifier; + private String literalKind; + + private int start; + private int end; + + public static BasicToken makeOperator(String value, int start, int end) { + return new BasicToken(value.intern(), false, null, start, end); + } + + public static BasicToken makeIdentifier(String value, int start, int end) { + return new BasicToken(value, true, null, start, end); + } + + public static BasicToken makeLiteral(String value, String kind, int start, int end) { + return new BasicToken(value, false, kind.intern(), start, end); + } + + + private BasicToken(String value, boolean isIdentifier, String literalKind, int start, int end) { + this.value = value; + this.isIdentifier = isIdentifier; + this.literalKind = literalKind; + this.start = start; + this.end = end; + } + + public int getStart() { return start; } + public int getEnd() { return end; } + public String getFileName() { return "unknown"; } + + public String getString() { + return value; + } + + public boolean isIdentifier() { + return isIdentifier; + } + + public Pointcut maybeGetParsedPointcut() { + return null; + } + + + + public String toString() { + String s; + if (isIdentifier) s = value; + else s = "'" + value + "'"; + + return s + "@" + start + ":" + end; + } + public String getLiteralKind() { + return literalKind; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/BasicTokenSource.java b/weaver/src/org/aspectj/weaver/patterns/BasicTokenSource.java new file mode 100644 index 000000000..ef4db5bf8 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/BasicTokenSource.java @@ -0,0 +1,153 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.util.*; + +import org.aspectj.weaver.*; + + +public class BasicTokenSource implements ITokenSource { + private int index = 0; + private IToken[] tokens; + private ISourceContext sourceContext; + + public BasicTokenSource(IToken[] tokens, ISourceContext sourceContext) { + this.tokens = tokens; + this.sourceContext = sourceContext; + } + + public int getIndex() { + return index; + } + + public void setIndex(int newIndex) { + this.index = newIndex; + } + + public IToken next() { + try { + return tokens[index++]; + } catch (ArrayIndexOutOfBoundsException e) { + return IToken.EOF; + } + } + + public IToken peek() { + try { + return tokens[index]; + } catch (ArrayIndexOutOfBoundsException e) { + return IToken.EOF; + } + } + + public IToken peek(int offset) { + try { + return tokens[index+offset]; + } catch (ArrayIndexOutOfBoundsException e) { + return IToken.EOF; + } + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("["); + for (int i = 0; i < tokens.length; i++) { + IToken t = tokens[i]; + if (t == null) + break; + if (i > 0) + buf.append(", "); + buf.append(t.toString()); + } + buf.append("]"); + return buf.toString(); + } + + + ////////////////////////////////////////////////////// + // Convenience, maybe just for testing + static ITokenSource makeTokenSource(String input) { + char[] chars = input.toCharArray(); + + int i = 0; + List tokens = new ArrayList(); + + while (i < chars.length) { + char ch = chars[i++]; + switch(ch) { + case ' ': + case '\t': + case '\n': + case '\r': + continue; + case '*': + case '.': + case '(': + case ')': + case '+': + case '[': + case ']': + case ',': + case '!': + case ':': + tokens.add(BasicToken.makeOperator(makeString(ch), i-1, i-1)); + continue; + case '&': + case '|': + if (i == chars.length) { + throw new BCException("bad " + ch); + } + char nextChar = chars[i++]; + if (nextChar == ch) { + tokens.add(BasicToken.makeOperator(makeString(ch, 2), i-2, i-1)); + } else { + throw new RuntimeException("bad " + ch); + } + continue; + + case '\"': + int start0 = i-1; + while (i < chars.length && !(chars[i]=='\"')) i++; + i += 1; + tokens.add(BasicToken.makeLiteral(new String(chars, start0+1, i-start0-2), "string", start0, i-1)); + default: + int start = i-1; + while (i < chars.length && Character.isJavaIdentifierPart(chars[i])) { i++; } + tokens.add(BasicToken.makeIdentifier(new String(chars, start, i-start), start, i-1)); + + } + } + + //System.out.println(tokens); + + return new BasicTokenSource((IToken[])tokens.toArray(new IToken[tokens.size()]), null); + } + + private static String makeString(char ch) { + // slightly inefficient ;-) + return new String(new char[] {ch}); + } + + private static String makeString(char ch, int count) { + // slightly inefficient ;-) + char[] chars = new char[count]; + for (int i=0; i<count; i++) { chars[i] = ch; } + return new String(chars); + } + public ISourceContext getSourceContext() { + return sourceContext; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/BindingTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/BindingTypePattern.java new file mode 100644 index 000000000..836b6ac4c --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/BindingTypePattern.java @@ -0,0 +1,74 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.*; + +public class BindingTypePattern extends ExactTypePattern { + private int formalIndex; + + public BindingTypePattern(TypeX type, int index) { + super(type, false); + this.formalIndex = index; + } + + public BindingTypePattern(FormalBinding binding) { + this(binding.getType(), binding.getIndex()); + } + + public int getFormalIndex() { + return formalIndex; + } + + public boolean equals(Object other) { + if (!(other instanceof BindingTypePattern)) return false; + BindingTypePattern o = (BindingTypePattern)other; + return o.type.equals(this.type) && o.formalIndex == this.formalIndex; + } + public int hashCode() { + int result = 17; + result = 37*result + type.hashCode(); + result = 37*result + formalIndex; + return result; + } + + public void write(DataOutputStream out) throws IOException { + out.writeByte(TypePattern.BINDING); + type.write(out); + out.writeShort((short)formalIndex); + writeLocation(out); + } + + public static TypePattern read(DataInputStream s, ISourceContext context) throws IOException { + TypePattern ret = new BindingTypePattern(TypeX.read(s), s.readShort()); + ret.readLocation(context, s); + return ret; + } + + public TypePattern remapAdviceFormals(IntMap bindings) { + if (!bindings.hasKey(formalIndex)) { + return new ExactTypePattern(type, false); + } else { + int newFormalIndex = bindings.get(formalIndex); + return new BindingTypePattern(type, newFormalIndex); + } + } + + public String toString() { + //Thread.currentThread().dumpStack(); + return "BindingTypePattern(" + type.toString() + ", " + formalIndex + ")"; + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/Bindings.java b/weaver/src/org/aspectj/weaver/patterns/Bindings.java new file mode 100644 index 000000000..b0a1e4eda --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/Bindings.java @@ -0,0 +1,127 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import org.aspectj.weaver.BCException; +import org.aspectj.bridge.IMessage; + +public class Bindings { + public static final Bindings NONE = new Bindings(0); + + private BindingTypePattern[] bindings; + + public Bindings(BindingTypePattern[] bindings) { + this.bindings = bindings; + } + + public Bindings(int count) { + this(new BindingTypePattern[count]); + } + + public void register(BindingTypePattern binding, IScope scope) { + int index = binding.getFormalIndex(); + BindingTypePattern existingBinding = bindings[index]; + if (existingBinding != null) { + scope.message(IMessage.ERROR, existingBinding, binding, + "multiple bindings" + index + ", " + binding); + } + bindings[index] = binding; + } + + public void mergeIn(Bindings other, IScope scope) { + for (int i=0, len=other.bindings.length; i < len; i++) { + if (other.bindings[i] != null) { + register(other.bindings[i], scope); + } + } + } + + + + /** + * signals an error if one has a binding and other doesn't + */ + public void checkEquals(Bindings other, IScope scope) { + BindingTypePattern[] b1 = this.bindings; + BindingTypePattern[] b2 = other.bindings; + int len = b1.length; + if (len != b2.length) { + throw new BCException("INSANE"); + } + + for (int i=0; i < len; i++) { + if (b1[i] == null && b2[i] != null) { + scope.message(IMessage.ERROR, b2[i], "inconsistent binding"); + b1[i] = b2[i]; // done just to produce fewer error messages + } else if (b2[i] == null && b1[i] != null) { + scope.message(IMessage.ERROR, b1[i], "inconsistent binding"); + b2[i] = b1[i]; // done just to produce fewer error messages + } + } + } + + public String toString() { + StringBuffer buf = new StringBuffer("Bindings("); + for (int i=0, len=bindings.length; i < len; i++) { + if (i > 0) buf.append(", "); + buf.append(bindings[i]); + } + buf.append(")"); + return buf.toString(); + } + + + public int[] getUsedFormals() { + //System.out.println("used: " + this); + int[] ret = new int[bindings.length]; + int index = 0; + for (int i=0, len=bindings.length; i < len; i++) { + if (bindings[i] != null) { + ret[index++] = i; + } + } + int[] newRet = new int[index]; + System.arraycopy(ret, 0, newRet, 0, index); + //System.out.println("ret: " + index); + return newRet; + } + + + public Bindings copy() { +// int len = bindings.length; +// boolean[] a = new boolean[len]; +// System.arraycopy(bindings, 0, a, 0, len); + return new Bindings((BindingTypePattern[])bindings.clone()); + } + + public void checkAllBound(IScope scope) { + for (int i=0, len=bindings.length; i < len; i++) { + if (bindings[i] == null) { + scope.message(IMessage.ERROR, scope.getFormal(i), "formal unbound in pointcut"); + } + } + + } + + public int size() { return bindings.length; } + + public void checkEmpty(IScope scope, String message) { + for (int i=0, len=bindings.length; i < len; i++) { + if (bindings[i] != null) { + scope.message(IMessage.ERROR, bindings[i], message); + } + } + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java b/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java new file mode 100644 index 000000000..72348d45b --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/CflowPointcut.java @@ -0,0 +1,165 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.bcel.BcelTypeMunger; +import org.aspectj.util.*; + + +public class CflowPointcut extends Pointcut { + private Pointcut entry; + private boolean isBelow; + private int[] freeVars; + + /** + * Used to indicate that we're in the context of a cflow when concretizing if's + * + * Will be removed or replaced with something better when we handle this + * as a non-error + */ + public static final ResolvedPointcutDefinition CFLOW_MARKER = + new ResolvedPointcutDefinition(null, 0, null, TypeX.NONE, Pointcut.makeMatchesNothing(Pointcut.RESOLVED)); + + + public CflowPointcut(Pointcut entry, boolean isBelow, int[] freeVars) { + this.entry = entry; + this.isBelow = isBelow; + this.freeVars = freeVars; + } + + public FuzzyBoolean match(Shadow shadow) { + //??? this is not maximally efficient + return FuzzyBoolean.MAYBE; + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.CFLOW); + entry.write(s); + s.writeBoolean(isBelow); + FileUtil.writeIntArray(s, freeVars); + writeLocation(s); + } + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + + CflowPointcut ret = new CflowPointcut(Pointcut.read(s, context), s.readBoolean(), FileUtil.readIntArray(s)); + ret.readLocation(context, s); + return ret; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + if (bindings == null) { + entry.resolveBindings(scope, null); + entry.state = RESOLVED; + freeVars = new int[0]; + } else { + //??? for if's sake we might need to be more careful here + Bindings entryBindings = new Bindings(bindings.size()); + + entry.resolveBindings(scope, entryBindings); + entry.state = RESOLVED; + + freeVars = entryBindings.getUsedFormals(); + + bindings.mergeIn(entryBindings, scope); + } + } + + public boolean equals(Object other) { + if (!(other instanceof CflowPointcut)) return false; + CflowPointcut o = (CflowPointcut)other; + return o.entry.equals(this.entry) && o.isBelow == this.isBelow; + } + public int hashCode() { + int result = 17; + result = 37*result + entry.hashCode(); + result = 37*result + (isBelow ? 0 : 1); + return result; + } + public String toString() { + return "cflow" + (isBelow ? "below" : "") + "(" + entry + ")"; + } + + public Test findResidue(Shadow shadow, ExposedState state) { + throw new RuntimeException("unimplemented"); + } + + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + //make this remap from formal positions to arrayIndices + IntMap entryBindings = new IntMap(); + for (int i=0, len=freeVars.length; i < len; i++) { + int freeVar = freeVars[i]; + //int formalIndex = bindings.get(freeVar); + entryBindings.put(freeVar, i); + } + entryBindings.copyContext(bindings); + //System.out.println(this + " bindings: " + entryBindings); + + World world = inAspect.getWorld(); + + Pointcut concreteEntry; + + CrosscuttingMembers xcut = inAspect.crosscuttingMembers; + Collection previousCflowEntries = xcut.getCflowEntries(); + + entryBindings.pushEnclosingDefinition(CFLOW_MARKER); + try { + concreteEntry = entry.concretize(inAspect, entryBindings); + } finally { + entryBindings.popEnclosingDefinitition(); + } + + List innerCflowEntries = new ArrayList(xcut.getCflowEntries()); + innerCflowEntries.removeAll(previousCflowEntries); + + + ResolvedMember cflowField = new ResolvedMember( + Member.FIELD, inAspect, Modifier.STATIC | Modifier.PUBLIC | Modifier.FINAL, + NameMangler.cflowStack(xcut), + TypeX.forName(NameMangler.CFLOW_STACK_TYPE).getSignature()); + + // add field and initializer to inAspect + //XXX and then that info above needs to be mapped down here to help with + //XXX getting the exposed state right + inAspect.crosscuttingMembers.addConcreteShadowMunger( + Advice.makeCflowEntry(world, concreteEntry, isBelow, cflowField, freeVars.length, innerCflowEntries)); + + inAspect.crosscuttingMembers.addTypeMunger( + world.makeCflowStackFieldAdder(cflowField)); + + + List slots = new ArrayList(); + for (int i=0, len=freeVars.length; i < len; i++) { + int freeVar = freeVars[i]; + int formalIndex = bindings.get(freeVar); + ResolvedTypeX formalType = + bindings.getAdviceSignature().getParameterTypes()[formalIndex].resolve(world); + + ConcreteCflowPointcut.Slot slot = + new ConcreteCflowPointcut.Slot(formalIndex, formalType, i); + slots.add(slot); + } + + return new ConcreteCflowPointcut(cflowField, slots); + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java new file mode 100644 index 000000000..3d3301b41 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ConcreteCflowPointcut.java @@ -0,0 +1,116 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.bcel.BcelTypeMunger; +import org.aspectj.util.*; + + +public class ConcreteCflowPointcut extends Pointcut { + private Member cflowStackField; + List/*Slot*/ slots; // exposed for testing + + + public ConcreteCflowPointcut(Member cflowStackField, List slots) { + this.cflowStackField = cflowStackField; + this.slots = slots; + } + + public FuzzyBoolean match(Shadow shadow) { + //??? this is not maximally efficient + return FuzzyBoolean.MAYBE; + } + + public void write(DataOutputStream s) throws IOException { + throw new RuntimeException("unimplemented"); + } + + + public void resolveBindings(IScope scope, Bindings bindings) { + throw new RuntimeException("unimplemented"); + } + + + public boolean equals(Object other) { + if (!(other instanceof ConcreteCflowPointcut)) return false; + ConcreteCflowPointcut o = (ConcreteCflowPointcut)other; + return o.cflowStackField.equals(this.cflowStackField); + } + public int hashCode() { + int result = 17; + result = 37*result + cflowStackField.hashCode(); + return result; + } + public String toString() { + return "concretecflow(" + cflowStackField + ")"; + } + + public Test findResidue(Shadow shadow, ExposedState state) { + //System.out.println("find residue: " + this); + for (Iterator i = slots.iterator(); i.hasNext();) { + Slot slot = (Slot) i.next(); + //System.out.println("slot: " + slot.formalIndex); + state.set(slot.formalIndex, + new BcelCflowAccessVar(slot.formalType, cflowStackField, slot.arrayIndex)); + } + + return Test.makeFieldGetCall(cflowStackField, cflowStackIsValidMethod, Expr.NONE); + } + + private static final Member cflowStackIsValidMethod = + Member.method(TypeX.forName(NameMangler.CFLOW_STACK_TYPE), 0, "isValid", "()Z"); + + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + throw new RuntimeException("unimplemented"); + } + + + public static class Slot { + int formalIndex; + ResolvedTypeX formalType; + int arrayIndex; + + public Slot( + int formalIndex, + ResolvedTypeX formalType, + int arrayIndex) { + this.formalIndex = formalIndex; + this.formalType = formalType; + this.arrayIndex = arrayIndex; + } + + public boolean equals(Object other) { + if (!(other instanceof Slot)) return false; + + Slot o = (Slot)other; + return o.formalIndex == this.formalIndex && + o.arrayIndex == this.arrayIndex && + o.formalType.equals(this.formalType); + } + + public String toString() { + return "Slot(" + formalIndex + ", " + formalType + ", " + arrayIndex + ")"; + } + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/Declare.java b/weaver/src/org/aspectj/weaver/patterns/Declare.java new file mode 100644 index 000000000..1dcb38bc0 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/Declare.java @@ -0,0 +1,54 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.ISourceContext; + +public abstract class Declare extends PatternNode { + public static final byte ERROR_OR_WARNING = 1; + public static final byte PARENTS = 2; + public static final byte SOFT = 3; + public static final byte DOMINATES = 4; + + public static Declare read(DataInputStream s, ISourceContext context) throws IOException { + byte kind = s.readByte(); + switch (kind) { + case ERROR_OR_WARNING: + return DeclareErrorOrWarning.read(s, context); + case DOMINATES: + return DeclareDominates.read(s, context); + case PARENTS: + return DeclareParents.read(s, context); + case SOFT: + return DeclareSoft.read(s, context); + default: + throw new RuntimeException("unimplemented"); + } + } + + /** + * Returns this declare mutated + */ + public abstract void resolve(IScope scope); + + /** + * Indicates if this declare should be treated like advice. If true, the + * declare will have no effect in an abstract aspect. It will be inherited by + * any concrete aspects and will have an effect for each concrete aspect it + * is ultimately inherited by. + */ + public abstract boolean isAdviceLike(); +} diff --git a/weaver/src/org/aspectj/weaver/patterns/DeclareDominates.java b/weaver/src/org/aspectj/weaver/patterns/DeclareDominates.java new file mode 100644 index 000000000..964f6659d --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/DeclareDominates.java @@ -0,0 +1,110 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.List; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; + +public class DeclareDominates extends Declare { + private TypePatternList patterns; + + + public DeclareDominates(List patterns) { + this(new TypePatternList(patterns)); + } + + private DeclareDominates(TypePatternList patterns) { + this.patterns = patterns; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("declare dominates: "); + buf.append(patterns); + buf.append(";"); + return buf.toString(); + } + + public boolean equals(Object other) { + if (!(other instanceof DeclareDominates)) return false; + DeclareDominates o = (DeclareDominates)other; + return o.patterns.equals(patterns); + } + + public int hashCode() { + return patterns.hashCode(); + } + + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Declare.DOMINATES); + patterns.write(s); + writeLocation(s); + } + + public static Declare read(DataInputStream s, ISourceContext context) throws IOException { + Declare ret = new DeclareDominates(TypePatternList.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + public void resolve(IScope scope) { + patterns = patterns.resolveBindings(scope, Bindings.NONE, false); + } + + public TypePatternList getPatterns() { + return patterns; + } + + private int matchingIndex(ResolvedTypeX a) { + int knownMatch = -1; + int starMatch = -1; + for (int i=0, len=patterns.size(); i < len; i++) { + TypePattern p = patterns.get(i); + if (p.isStar()) { + starMatch = i; + } else if (p.matchesExactly(a)) { + if (knownMatch != -1) { + throw new BCException("multiple matches: " + this + " with " + a); + } else { + knownMatch = i; + } + } + } + if (knownMatch == -1) return starMatch; + else return knownMatch; + } + + + public int compare(ResolvedTypeX aspect1, ResolvedTypeX aspect2) { + int index1 = matchingIndex(aspect1); + int index2 = matchingIndex(aspect2); + + //System.out.println("a1: " + aspect1 + ", " + aspect2 + " = " + index1 + ", " + index2); + + if (index1 == -1 || index2 == -1) return 0; + + if (index1 == index2) return 0; + else if (index1 > index2) return -1; + else return +1; + } + + public boolean isAdviceLike() { + return false; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/DeclareErrorOrWarning.java b/weaver/src/org/aspectj/weaver/patterns/DeclareErrorOrWarning.java new file mode 100644 index 000000000..f1e84cfa3 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/DeclareErrorOrWarning.java @@ -0,0 +1,99 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.ISourceContext; + +public class DeclareErrorOrWarning extends Declare { + private boolean isError; + private Pointcut pointcut; + private String message; + + public DeclareErrorOrWarning(boolean isError, Pointcut pointcut, String message) { + this.isError = isError; + this.pointcut = pointcut; + this.message = message; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("declare "); + if (isError) buf.append("error: "); + else buf.append("warning: "); + buf.append(pointcut); + buf.append(": "); + buf.append("\""); + buf.append(message); + buf.append("\";"); + return buf.toString(); + } + + public boolean equals(Object other) { + if (!(other instanceof DeclareErrorOrWarning)) return false; + DeclareErrorOrWarning o = (DeclareErrorOrWarning)other; + return (o.isError == isError) && + o.pointcut.equals(pointcut) && + o.message.equals(message); + } + + public int hashCode() { + int result = isError ? 19 : 23; + result = 37*result + pointcut.hashCode(); + result = 37*result + message.hashCode(); + return result; + } + + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Declare.ERROR_OR_WARNING); + s.writeBoolean(isError); + pointcut.write(s); + s.writeUTF(message); + writeLocation(s); + } + + public static Declare read(DataInputStream s, ISourceContext context) throws IOException { + Declare ret = new DeclareErrorOrWarning( + s.readBoolean(), + Pointcut.read(s, context), + s.readUTF() + ); + ret.readLocation(context, s); + return ret; + } + + + public boolean isError() { + return isError; + } + + public String getMessage() { + return message; + } + + public Pointcut getPointcut() { + return pointcut; + } + + public void resolve(IScope scope) { + pointcut = pointcut.resolve(scope); + } + + public boolean isAdviceLike() { + return true; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/DeclareParents.java b/weaver/src/org/aspectj/weaver/patterns/DeclareParents.java new file mode 100644 index 000000000..d34d69ab1 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/DeclareParents.java @@ -0,0 +1,100 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.List; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; + +public class DeclareParents extends Declare { + private TypePattern child; + private TypePatternList parents; + + + public DeclareParents(TypePattern child, List parents) { + this(child, new TypePatternList(parents)); + } + + private DeclareParents(TypePattern child, TypePatternList parents) { + this.child = child; + this.parents = parents; + } + + public boolean match(ResolvedTypeX typeX) { + return child.matchesStatically(typeX); + } + + + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("declare parents: "); + buf.append(child); + buf.append(" extends "); //extends and implements are treated equivalently + buf.append(parents); + buf.append(";"); + return buf.toString(); + } + + public boolean equals(Object other) { + if (!(other instanceof DeclareParents)) return false; + DeclareParents o = (DeclareParents)other; + return o.child.equals(child) && o.parents.equals(parents); + } + + //??? cache this + public int hashCode() { + int result = 23; + result = 37*result + child.hashCode(); + result = 37*result + parents.hashCode(); + return result; + } + + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Declare.PARENTS); + child.write(s); + parents.write(s); + writeLocation(s); + } + + public static Declare read(DataInputStream s, ISourceContext context) throws IOException { + Declare ret = new DeclareParents(TypePattern.read(s, context), TypePatternList.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + public void resolve(IScope scope) { + child = child.resolveBindings(scope, Bindings.NONE, false); + parents = parents.resolveBindings(scope, Bindings.NONE, false); + for (int i=0; i < parents.size(); i++) { + parents.get(i).assertExactType(scope.getMessageHandler()); + } + } + + public TypePatternList getParents() { + return parents; + } + + public TypePattern getChild() { + return child; + } + + public boolean isAdviceLike() { + return false; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/DeclareSoft.java b/weaver/src/org/aspectj/weaver/patterns/DeclareSoft.java new file mode 100644 index 000000000..b80c17a21 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/DeclareSoft.java @@ -0,0 +1,87 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.ISourceContext; + +public class DeclareSoft extends Declare { + private TypePattern exception; + private Pointcut pointcut; + + public DeclareSoft(TypePattern exception, Pointcut pointcut) { + this.exception = exception; + this.pointcut = pointcut; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("declare soft: "); + buf.append(exception); + buf.append(": "); + buf.append(pointcut); + buf.append(";"); + return buf.toString(); + } + + public boolean equals(Object other) { + if (!(other instanceof DeclareSoft)) return false; + DeclareSoft o = (DeclareSoft)other; + return + o.pointcut.equals(pointcut) && + o.exception.equals(exception); + } + + public int hashCode() { + int result = 19; + result = 37*result + pointcut.hashCode(); + result = 37*result + exception.hashCode(); + return result; + } + + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Declare.SOFT); + exception.write(s); + pointcut.write(s); + writeLocation(s); + } + + public static Declare read(DataInputStream s, ISourceContext context) throws IOException { + Declare ret = new DeclareSoft( + TypePattern.read(s, context), + Pointcut.read(s, context) + ); + ret.readLocation(context, s); + return ret; + } + + public Pointcut getPointcut() { + return pointcut; + } + + public TypePattern getException() { + return exception; + } + + public void resolve(IScope scope) { + exception = exception.resolveBindings(scope, null, false); + pointcut = pointcut.resolve(scope); + } + + public boolean isAdviceLike() { + return true; + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java new file mode 100644 index 000000000..b98463ead --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ExactTypePattern.java @@ -0,0 +1,82 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.*; +import org.aspectj.util.*; + +public class ExactTypePattern extends TypePattern { + protected TypeX type; + + public ExactTypePattern(TypeX type, boolean includeSubtypes) { + super(includeSubtypes); + this.type = type; + } + + protected boolean matchesExactly(ResolvedTypeX matchType) { + return this.type.equals(matchType); + } + + public TypeX getType() { return type; } + + public FuzzyBoolean matchesInstanceof(ResolvedTypeX matchType) { + // in our world, Object is assignable from anything + if (type.equals(ResolvedTypeX.OBJECT)) return FuzzyBoolean.YES; + + if (type.isAssignableFrom(matchType, matchType.getWorld())) { + return FuzzyBoolean.YES; + } + + return matchType.isCoerceableFrom(type) ? FuzzyBoolean.MAYBE : FuzzyBoolean.NO; + } + + public boolean equals(Object other) { + if (!(other instanceof ExactTypePattern)) return false; + ExactTypePattern o = (ExactTypePattern)other; + return o.type.equals(this.type); + } + + public int hashCode() { + return type.hashCode(); + } + + public void write(DataOutputStream out) throws IOException { + out.writeByte(TypePattern.EXACT); + type.write(out); + out.writeBoolean(includeSubtypes); + writeLocation(out); + } + + public static TypePattern read(DataInputStream s, ISourceContext context) throws IOException { + TypePattern ret = new ExactTypePattern(TypeX.read(s), s.readBoolean()); + ret.readLocation(context, s); + return ret; + } + + public String toString() { + //Thread.currentThread().dumpStack(); + return "ExactTypePattern(" + type.toString() + (includeSubtypes ? "+" : "") + ")"; + } + public TypePattern resolveBindings( + IScope scope, + Bindings bindings, + boolean allowBinding) + { + throw new BCException("trying to re-resolve"); + + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ExposedState.java b/weaver/src/org/aspectj/weaver/patterns/ExposedState.java new file mode 100644 index 000000000..e5b35a03c --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ExposedState.java @@ -0,0 +1,57 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.util.Arrays; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; + +public class ExposedState { + public Var[] vars; + private Expr aspectInstance; + + public ExposedState(int size) { + super(); + vars = new Var[size]; + } + + public ExposedState(Member signature) { + // XXX there maybe something about target for non-static sigs + this(signature.getParameterTypes().length); + } + + public void set(int i, Var var) { + //XXX add sanity checks + vars[i] = var; + } + public Var get(int i) { + return vars[i]; + } + public int size() { + return vars.length; + } + + public Expr getAspectInstance() { + return aspectInstance; + } + + public void setAspectInstance(Expr aspectInstance) { + this.aspectInstance = aspectInstance; + } + + public String toString() { + return "ExposedState(" + Arrays.asList(vars) + ", " + aspectInstance + ")"; + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/FormalBinding.java b/weaver/src/org/aspectj/weaver/patterns/FormalBinding.java new file mode 100644 index 000000000..be34d4848 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/FormalBinding.java @@ -0,0 +1,76 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import org.aspectj.weaver.*; + +public class FormalBinding implements IHasPosition { + private final TypeX type; + private final String name; + private final int index; + private final int start, end; + private final String fileName; + + public FormalBinding(TypeX type, String name, int index, int start, int end, String fileName) { + this.type = type; + this.name = name; + this.index = index; + this.start = start; + this.end = end; + this.fileName = fileName; + } + + public FormalBinding(TypeX type, int index) { + this(type, "unknown", index, 0, 0, "unknown"); + } + + public FormalBinding(TypeX type, String name, int index) { + this(type, name, index, 0, 0, "unknown"); + } + + // ---- + + public String toString() { + return type.toString() + ":" + index; + } + + public String getFileName() { + return fileName; + } + + public int getEnd() { + return end; + } + + public int getStart() { + return start; + } + + public int getIndex() { + return index; + } + + public String getName() { + return name; + } + + public TypeX getType() { + return type; + } + + // ---- + + public static final FormalBinding[] NONE = new FormalBinding[0]; + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java b/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java new file mode 100644 index 000000000..4f9d16596 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/HandlerPointcut.java @@ -0,0 +1,94 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.apache.bcel.classfile.JavaClass; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.bridge.MessageUtil; +import org.aspectj.util.FuzzyBoolean; + +/** + * This is a kind of KindedPointcut. This belongs either in + * a hierarchy with it or in a new place to share code + * with other potential future statement-level pointcuts like + * synchronized and throws + */ +public class HandlerPointcut extends Pointcut { + TypePattern exceptionType; + + public HandlerPointcut(TypePattern exceptionType) { + this.exceptionType = exceptionType; + } + + + public FuzzyBoolean match(Shadow shadow) { + if (shadow.getKind() != Shadow.ExceptionHandler) return FuzzyBoolean.NO; + + // we know we have exactly one parameter since we're checking an exception handler + return exceptionType.matches( + shadow.getSignature().getParameterTypes()[0].resolve(shadow.getIWorld()), + TypePattern.STATIC); + } + + public boolean equals(Object other) { + if (!(other instanceof HandlerPointcut)) return false; + HandlerPointcut o = (HandlerPointcut)other; + return o.exceptionType.equals(this.exceptionType); } + + public int hashCode() { + int result = 17; + result = 37*result + exceptionType.hashCode(); + return result; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("handler("); + buf.append(exceptionType.toString()); + buf.append(")"); + return buf.toString(); + } + + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.HANDLER); + exceptionType.write(s); + writeLocation(s); + } + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + HandlerPointcut ret = new HandlerPointcut(TypePattern.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + // XXX note: there is no namebinding in any kinded pointcut. + // still might want to do something for better error messages + // We want to do something here to make sure we don't sidestep the parameter + // list in capturing type identifiers. + public void resolveBindings(IScope scope, Bindings bindings) { + exceptionType = exceptionType.resolveBindings(scope, bindings, false); + //XXX add error if exact binding and not an exception + } + public Test findResidue(Shadow shadow, ExposedState state) { + return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE; + } + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + return new HandlerPointcut(exceptionType); + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/IScope.java b/weaver/src/org/aspectj/weaver/patterns/IScope.java new file mode 100644 index 000000000..d815326cd --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/IScope.java @@ -0,0 +1,47 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import org.aspectj.weaver.*; +import org.aspectj.bridge.*; +import org.aspectj.bridge.IMessageHandler; + +public interface IScope { + + /** returns the type corresponding to the name in this scope + * returns ResolvedTypeX.MISSING if no such type exists and reports a problem + */ + TypeX lookupType(String name, IHasPosition location); + + World getWorld(); + + ResolvedTypeX getEnclosingType(); + + // these next three are used to create {@link BindingTypePattern} objects. + IMessageHandler getMessageHandler(); + /** returns the formal associated with the name, or null if no such formal exists */ + FormalBinding lookupFormal(String name); + /** returns the formal with the index. Throws ArrayOutOfBounds exception if out of bounds */ + FormalBinding getFormal(int i); + + int getFormalCount(); + + String[] getImportedPrefixes(); + String[] getImportedNames(); + + void message(IMessage.Kind kind, IHasPosition location, String message); + void message(IMessage.Kind kind, IHasPosition location1, IHasPosition location2, String message); + + //ISourceLocation makeSourceLocation(ILocation location); +} diff --git a/weaver/src/org/aspectj/weaver/patterns/IToken.java b/weaver/src/org/aspectj/weaver/patterns/IToken.java new file mode 100644 index 000000000..e7403287a --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/IToken.java @@ -0,0 +1,53 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import org.aspectj.weaver.*; + +public interface IToken extends IHasPosition { + public static final IToken EOF = BasicToken.makeOperator("<eof>", 0, 0); + + /** + * Returns the string value of this token. + * + * If isIdentifier is false, then this string must be intern'd + * so that == matching can be used. + * + * If isIdentifier is true, interning is not required. + */ + public String getString(); + + /** + * Whether this should be treated as a token or a generic identifier + */ + public boolean isIdentifier(); + + /** + * Whether this should be treated as a literal value + * + * Kinds == "string", ??? + * + * returns null if this isn't a literal + */ + public String getLiteralKind(); + + + /** + * If this token represents a pre-parsed Pointcut, then return it; + * otherwise returns null. + * + * Needed for the implementation of 'if' + */ + public Pointcut maybeGetParsedPointcut(); +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ITokenSource.java b/weaver/src/org/aspectj/weaver/patterns/ITokenSource.java new file mode 100644 index 000000000..4410e60d8 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ITokenSource.java @@ -0,0 +1,26 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import org.aspectj.weaver.ISourceContext; + + +public interface ITokenSource { + public IToken next(); + public IToken peek(); + public IToken peek(int offset); + public int getIndex(); + public void setIndex(int newIndex); + public ISourceContext getSourceContext(); +} diff --git a/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java b/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java new file mode 100644 index 000000000..8a5d54ea9 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/IfPointcut.java @@ -0,0 +1,137 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.*; +import java.util.List; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.bridge.MessageUtil; +import org.aspectj.util.*; + + +public class IfPointcut extends Pointcut { + public ResolvedMember testMethod; + public int extraParameterFlags; + + public Pointcut residueSource; + int baseArgsCount; + + //XXX some way to compute args + + + public IfPointcut(ResolvedMember testMethod, int extraParameterFlags) { + this.testMethod = testMethod; + this.extraParameterFlags = extraParameterFlags; + } + + public FuzzyBoolean match(Shadow shadow) { + //??? this is not maximally efficient + return FuzzyBoolean.MAYBE; + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.IF); + testMethod.write(s); + s.writeByte(extraParameterFlags); + writeLocation(s); + } + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + IfPointcut ret = new IfPointcut(ResolvedMember.readResolvedMember(s, context), s.readByte()); + ret.readLocation(context, s); + return ret; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + //??? all we need is good error messages in here in cflow contexts + } + + public boolean equals(Object other) { + if (!(other instanceof IfPointcut)) return false; + IfPointcut o = (IfPointcut)other; + return o.testMethod.equals(this.testMethod); + } + public int hashCode() { + int result = 17; + result = 37*result + testMethod.hashCode(); + return result; + } + public String toString() { + return "if(" + testMethod + ")"; + } + + public Test findResidue(Shadow shadow, ExposedState state) { + if (residueSource == null) return Literal.TRUE; //??? + + ExposedState myState = new ExposedState(baseArgsCount); + //System.out.println(residueSource); + residueSource.findResidue(shadow, myState); // don't care about Test + + //System.out.println(myState); + + List args = new ArrayList(); + for (int i=0; i < baseArgsCount; i++) { + args.add(myState.get(i)); + } + + // handle thisJoinPoint parameters + if ((extraParameterFlags & Advice.ThisJoinPoint) != 0) { + args.add(shadow.getThisJoinPointVar()); + } + + if ((extraParameterFlags & Advice.ThisJoinPointStaticPart) != 0) { + args.add(shadow.getThisJoinPointStaticPartVar()); + } + + if ((extraParameterFlags & Advice.ThisEnclosingJoinPointStaticPart) != 0) { + args.add(shadow.getThisEnclosingJoinPointStaticPartVar()); + } + + return Test.makeCall(testMethod, (Expr[])args.toArray(new Expr[args.size()])); + } + + + public Pointcut concretize(ResolvedTypeX inAspect, IntMap bindings) { + return this.concretize1(inAspect, bindings); + } + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + IfPointcut ret = new IfPointcut(testMethod, extraParameterFlags); + if (this.state == CONCRETE) return ret; + this.state = CONCRETE; + if (bindings.directlyInAdvice()) { + Advice advice = bindings.getEnclosingAdvice(); + ret.baseArgsCount = advice.getBaseParameterCount(); + ret.residueSource = advice.getPointcut().concretize(inAspect, ret.baseArgsCount, advice); + } else { + ResolvedPointcutDefinition def = bindings.peekEnclosingDefinitition(); + if (def == CflowPointcut.CFLOW_MARKER) { + inAspect.getWorld().getMessageHandler().handleMessage( + MessageUtil.error("if not supported lexically within cflow (compiler limitation)", + null)); + return Pointcut.makeMatchesNothing(Pointcut.CONCRETE); + } + ret.baseArgsCount = def.getParameterTypes().length; + + IntMap newBindings = IntMap.idMap(ret.baseArgsCount); + newBindings.copyContext(bindings); + ret.residueSource = def.getPointcut().concretize(inAspect, newBindings); + } + + return ret; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java b/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java new file mode 100644 index 000000000..2720596f5 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/KindedPointcut.java @@ -0,0 +1,115 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.apache.bcel.classfile.JavaClass; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.bridge.MessageUtil; +import org.aspectj.util.FuzzyBoolean; + +public class KindedPointcut extends Pointcut { + Shadow.Kind kind; + SignaturePattern signature; + + public KindedPointcut( + Shadow.Kind kind, + SignaturePattern signature) { + this.kind = kind; + this.signature = signature; + } + + public boolean fastMatch(JavaClass jc) { return true; } + + public FuzzyBoolean match(Shadow shadow) { + + + if (shadow.getKind() != kind) return FuzzyBoolean.NO; + + if (!signature.matches(shadow.getSignature(), shadow.getIWorld())) return FuzzyBoolean.NO; + + return FuzzyBoolean.YES; + } + + public boolean equals(Object other) { + if (!(other instanceof KindedPointcut)) return false; + KindedPointcut o = (KindedPointcut)other; + return o.kind == this.kind && o.signature.equals(this.signature); + } + + public int hashCode() { + int result = 17; + result = 37*result + kind.hashCode(); + result = 37*result + signature.hashCode(); + return result; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append(kind.getSimpleName()); + buf.append("("); + buf.append(signature.toString()); + buf.append(")"); + return buf.toString(); + } + + + public void postRead(ResolvedTypeX enclosingType) { + signature.postRead(enclosingType); + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.KINDED); + kind.write(s); + signature.write(s); + writeLocation(s); + } + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + Shadow.Kind kind = Shadow.Kind.read(s); + SignaturePattern sig = SignaturePattern.read(s, context); + KindedPointcut ret = new KindedPointcut(kind, sig); + ret.readLocation(context, s); + return ret; + } + + // XXX note: there is no namebinding in any kinded pointcut. + // still might want to do something for better error messages + // We want to do something here to make sure we don't sidestep the parameter + // list in capturing type identifiers. + public void resolveBindings(IScope scope, Bindings bindings) { + if (kind == Shadow.Initialization) { +// scope.getMessageHandler().handleMessage( +// MessageUtil.error( +// "initialization unimplemented in 1.1beta1", +// this.getSourceLocation())); + } + signature = signature.resolveBindings(scope, bindings); + } + public Test findResidue(Shadow shadow, ExposedState state) { + return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE; + } + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + return new KindedPointcut(kind, signature); + //return this; //??? no pointers out of here so we're okay + } + + public Shadow.Kind getKind() { + return kind; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ModifiersPattern.java b/weaver/src/org/aspectj/weaver/patterns/ModifiersPattern.java new file mode 100644 index 000000000..dc146a0ef --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ModifiersPattern.java @@ -0,0 +1,92 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; + +public class ModifiersPattern extends PatternNode { + private int requiredModifiers; + private int forbiddenModifiers; + + public static final ModifiersPattern ANY = new ModifiersPattern(0, 0); + + public ModifiersPattern(int requiredModifiers, int forbiddenModifiers) { + this.requiredModifiers = requiredModifiers; + this.forbiddenModifiers = forbiddenModifiers; + } + + public String toString() { + if (this == ANY) return ""; + + String ret = Modifier.toString(requiredModifiers); + if (forbiddenModifiers == 0) return ret; + else return ret + " !" + Modifier.toString(forbiddenModifiers); + } + + public boolean equals(Object other) { + if (!(other instanceof ModifiersPattern)) return false; + ModifiersPattern o = (ModifiersPattern)other; + return o.requiredModifiers == this.requiredModifiers && + o.forbiddenModifiers == this.forbiddenModifiers; + } + public int hashCode() { + int result = 17; + result = 37*result + requiredModifiers; + result = 37*result + forbiddenModifiers; + return result; + } + + public boolean matches(int modifiers) { + return ((modifiers & requiredModifiers) == requiredModifiers) && + ((modifiers & forbiddenModifiers) == 0); + } + + + public static ModifiersPattern read(DataInputStream s) throws IOException { + int requiredModifiers = s.readShort(); + int forbiddenModifiers = s.readShort(); + if (requiredModifiers == 0 && forbiddenModifiers == 0) return ANY; + return new ModifiersPattern(requiredModifiers, forbiddenModifiers); + } + + /** + * @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream) + */ + public void write(DataOutputStream s) throws IOException { + //s.writeByte(MODIFIERS_PATTERN); + s.writeShort(requiredModifiers); + s.writeShort(forbiddenModifiers); + } + + + private static Map modifierFlags = null; + + public static int getModifierFlag(String name) { + if (modifierFlags == null) { + modifierFlags = new HashMap(); + int flag = 1; + while (flag <= Modifier.STRICT) { + String flagName = Modifier.toString(flag); + modifierFlags.put(flagName, new Integer(flag)); + flag = flag << 1; + } + } + Integer flag = (Integer)modifierFlags.get(name); + if (flag == null) return -1; + return flag.intValue(); + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/NameBindingPointcut.java b/weaver/src/org/aspectj/weaver/patterns/NameBindingPointcut.java new file mode 100644 index 000000000..0a043ad51 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/NameBindingPointcut.java @@ -0,0 +1,47 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; + +/** + * Common super type for Pointcuts that can bind formal parameters. + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public abstract class NameBindingPointcut extends Pointcut { + + public NameBindingPointcut() { + super(); + } + + protected Test exposeStateForVar(Var var,TypePattern type, ExposedState state, World world) { + if (type instanceof BindingTypePattern) { + BindingTypePattern b = (BindingTypePattern)type; + state.set(b.getFormalIndex(), var); + } + TypeX myType = type.getExactType(); //should have failed earlier + + return Test.makeInstanceof(var, myType.resolve(world)); + } + + + + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/NamePattern.java b/weaver/src/org/aspectj/weaver/patterns/NamePattern.java new file mode 100644 index 000000000..043376fc1 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/NamePattern.java @@ -0,0 +1,158 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +public class NamePattern extends PatternNode { + char[] pattern; + int starCount = 0; + + public static final NamePattern ELLIPSIS = new NamePattern(""); + public static final NamePattern ANY = new NamePattern("*"); + + public NamePattern(String name) { + this(name.toCharArray()); + } + + public NamePattern(char[] pattern) { + this.pattern = pattern; + + for (int i=0, len=pattern.length; i<len; i++) { + if (pattern[i] == '*') starCount++; + } + } + + public boolean matches(char[] a2) { + char[] a1 = pattern; + int len1 = a1.length; + int len2 = a2.length; + if (starCount == 0) { + if (len1 != len2) return false; + for (int i=0; i<len1; i++) { + if (a1[i] != a2[i]) return false; + } + return true; + } else if (starCount == 1) { + // just '*' matches anything + if (len1 == 1) return true; + if (len1 > len2+1) return false; + + int i2=0; + for (int i1=0; i1<len1; i1++) { + char c1 = a1[i1]; + if (c1 == '*') { + i2 = len2 - (len1-(i1+1)); + } else if (c1 != a2[i2++]) { + return false; + } + } + return true; + } else { +// String pattern = new String(a1); +// String target = new String(a2); +// System.err.print("match(\"" + pattern + "\", \"" + target + "\") -> "); + boolean b = outOfStar(a1, a2, 0, 0, len1 - starCount, len2, starCount); +// System.err.println(b); + return b; + } + } + private static boolean outOfStar(final char[] pattern, final char[] target, + int pi, int ti, + int pLeft, int tLeft, + final int starsLeft) { + if (pLeft > tLeft) return false; + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length) + if (tLeft == 0) return true; + if (pLeft == 0) { + return (starsLeft > 0); + } + if (pattern[pi] == '*') { + return inStar(pattern, target, pi+1, ti, pLeft, tLeft, starsLeft-1); + } + if (target[ti] != pattern[pi]) { + return false; + } + pi++; ti++; pLeft--; tLeft--; + } + } + private static boolean inStar(final char[] pattern, final char[] target, + int pi, int ti, + final int pLeft, int tLeft, + int starsLeft) { + // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern + char patternChar = pattern[pi]; + while (patternChar == '*') { + starsLeft--; + patternChar = pattern[++pi]; + } + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length) + if (pLeft > tLeft) return false; + if (target[ti] == patternChar) { + if (outOfStar(pattern, target, pi+1, ti+1, pLeft-1, tLeft-1, starsLeft)) return true; + } + ti++; tLeft--; + } + } + + public boolean matches(String other) { + return matches(other.toCharArray()); + } + + public String toString() { + return new String(pattern); + } + + public boolean equals(Object other) { + if (other instanceof NamePattern) { + NamePattern otherPat = (NamePattern)other; + return otherPat.starCount == this.starCount && + new String(otherPat.pattern).equals(new String(this.pattern)); + } + return false; + } + public int hashCode() { + return new String(pattern).hashCode(); + } + + + public void write(DataOutputStream out) throws IOException { + out.writeUTF(new String(pattern)); + } + + public static NamePattern read(DataInputStream in) throws IOException { + String s = in.readUTF(); + if (s.length() == 0) return ELLIPSIS; + return new NamePattern(s); + } + /** + * Method maybeGetSimpleName. + * @return String + */ + public String maybeGetSimpleName() { + if (starCount == 0 && pattern.length > 0) return new String(pattern); + return null; + } + + /** + * Method isAny. + * @return boolean + */ + public boolean isAny() { + return starCount == 1 && pattern.length == 1; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java b/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java new file mode 100644 index 000000000..64b919f69 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/NotPointcut.java @@ -0,0 +1,96 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.util.*; + +public class NotPointcut extends Pointcut { + private Pointcut body; + public NotPointcut(Pointcut left) { + super(); + this.body = left; + } + + /** + * Constructor NotPointcut. + * @param pointcut + * @param startPos + */ + public NotPointcut(Pointcut pointcut, int startPos) { + this(pointcut); + setLocation(pointcut.getSourceContext(), startPos, pointcut.getEnd()); + } + + + /** + * @see org.aspectj.weaver.patterns.Pointcut#match(BcelShadow) + */ + public FuzzyBoolean match(Shadow shadow) { + return body.match(shadow).not(); + } + + public String toString() { + return "!" + body.toString(); + + } + + public boolean equals(Object other) { + if (!(other instanceof NotPointcut)) return false; + NotPointcut o = (NotPointcut)other; + return o.body.equals(body); + } + public int hashCode() { + return 37*23 + body.hashCode(); + } + + + public void resolveBindings(IScope scope, Bindings bindings) { + //Bindings old = bindings.copy(); + + //Bindings newBindings = new Bindings(bindings.size()); + + + body.resolveBindings(scope, null); + + //newBindings.checkEmpty(scope, "negation does not allow binding"); + //bindings.checkEquals(old, scope); + + } + + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.NOT); + body.write(s); + writeLocation(s); + } + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + NotPointcut ret = new NotPointcut(Pointcut.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + public Test findResidue(Shadow shadow, ExposedState state) { + return Test.makeNot(body.findResidue(shadow, state)); + } + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + return new NotPointcut(body.concretize1(inAspect, bindings)); + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java new file mode 100644 index 000000000..f62d693c7 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/NotTypePattern.java @@ -0,0 +1,75 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; + +/** + * !TypePattern + * + * <p>any binding to formals is explicitly forbidden for any composite, ! is + * just the most obviously wrong case. + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public class NotTypePattern extends TypePattern { + private TypePattern pattern; + + public NotTypePattern(TypePattern pattern) { + super(false); //??? we override all methods that care about includeSubtypes + this.pattern = pattern; + setLocation(pattern.getSourceContext(), pattern.getStart(), pattern.getEnd()); + } + + public FuzzyBoolean matchesInstanceof(ResolvedTypeX type) { + return pattern.matchesInstanceof(type).not(); + } + + protected boolean matchesExactly(ResolvedTypeX type) { + return !pattern.matchesExactly(type); + } + + public boolean matchesStatically(ResolvedTypeX type) { + return !pattern.matchesStatically(type); + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(TypePattern.NOT); + pattern.write(s); + writeLocation(s); + } + + public static TypePattern read(DataInputStream s, ISourceContext context) throws IOException { + TypePattern ret = new NotTypePattern(TypePattern.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + public TypePattern resolveBindings( + IScope scope, + Bindings bindings, + boolean allowBinding) { + pattern = pattern.resolveBindings(scope, bindings, false); + return this; + } + + public String toString() { + return "!" + pattern; + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java b/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java new file mode 100644 index 000000000..fc389acaf --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/OrPointcut.java @@ -0,0 +1,89 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.util.*; + +public class OrPointcut extends Pointcut { + private Pointcut left, right; + /** + * Constructor for AndPointcut. + */ + public OrPointcut(Pointcut left, Pointcut right) { + super(); + this.left = left; + this.right = right; + setLocation(left.getSourceContext(), left.getStart(), right.getEnd()); + } + + /** + * @see org.aspectj.weaver.patterns.Pointcut#match(BcelShadow) + */ + public FuzzyBoolean match(Shadow shadow) { + return left.match(shadow).or(right.match(shadow)); + } + + public String toString() { + return "(" + left.toString() + " || " + right.toString() + ")"; + } + + public boolean equals(Object other) { + if (!(other instanceof OrPointcut)) return false; + OrPointcut o = (OrPointcut)other; + return o.left.equals(left) && o.right.equals(right); + } + public int hashCode() { + int result = 31; + result = 37*result + left.hashCode(); + result = 37*result + right.hashCode(); + return result; + } + /** + * @see org.aspectj.weaver.patterns.Pointcut#resolveBindings(IScope, Bindings) + */ + public void resolveBindings(IScope scope, Bindings bindings) { + Bindings old = bindings == null ? null : bindings.copy(); + + left.resolveBindings(scope, bindings); + right.resolveBindings(scope, old); + if (bindings != null) bindings.checkEquals(old, scope); + + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.OR); + left.write(s); + right.write(s); + writeLocation(s); + } + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + OrPointcut ret = new OrPointcut(Pointcut.read(s, context), Pointcut.read(s, context)); + ret.readLocation(context, s); + return ret; + + } + public Test findResidue(Shadow shadow, ExposedState state) { + return Test.makeOr(left.findResidue(shadow, state), right.findResidue(shadow, state)); + } + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + return new OrPointcut(left.concretize1(inAspect, bindings), + right.concretize1(inAspect, bindings)); + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java new file mode 100644 index 000000000..6cb043bc5 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/OrTypePattern.java @@ -0,0 +1,79 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; + +/** + * left || right + * + * <p>any binding to formals is explicitly forbidden for any composite by the language + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public class OrTypePattern extends TypePattern { + private TypePattern left, right; + + public OrTypePattern(TypePattern left, TypePattern right) { + super(false); //??? we override all methods that care about includeSubtypes + this.left = left; + this.right = right; + setLocation(left.getSourceContext(), left.getStart(), right.getEnd()); + } + + public FuzzyBoolean matchesInstanceof(ResolvedTypeX type) { + return left.matchesInstanceof(type).or(right.matchesInstanceof(type)); + } + + protected boolean matchesExactly(ResolvedTypeX type) { + //??? if these had side-effects, this sort-circuit could be a mistake + return left.matchesExactly(type) || right.matchesExactly(type); + } + + public boolean matchesStatically(ResolvedTypeX type) { + return left.matchesStatically(type) || right.matchesStatically(type); + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(TypePattern.OR); + left.write(s); + right.write(s); + writeLocation(s); + } + + public static TypePattern read(DataInputStream s, ISourceContext context) throws IOException { + TypePattern ret = new OrTypePattern(TypePattern.read(s, context), TypePattern.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + public TypePattern resolveBindings( + IScope scope, + Bindings bindings, + boolean allowBinding) { + left = left.resolveBindings(scope, bindings, false); + right = right.resolveBindings(scope, bindings, false); + return this; + } + + public String toString() { + return "(" + left.toString() + " || " + right.toString() + ")"; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ParserException.java b/weaver/src/org/aspectj/weaver/patterns/ParserException.java new file mode 100644 index 000000000..af6f0cb49 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ParserException.java @@ -0,0 +1,31 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import org.aspectj.weaver.*; + + +public class ParserException extends RuntimeException { + private IHasPosition token; + + public ParserException(String message, IHasPosition token) { + super(message); + this.token = token; + } + + public IHasPosition getLocation() { + return token; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/PatternNode.java b/weaver/src/org/aspectj/weaver/patterns/PatternNode.java new file mode 100644 index 000000000..4c09ad4b7 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/PatternNode.java @@ -0,0 +1,82 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.bridge.*; +import org.aspectj.bridge.ISourceLocation; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ISourceContext; + +public abstract class PatternNode implements IHasSourceLocation { + protected int start, end; + protected ISourceContext sourceContext; + + public PatternNode() { + super(); + start = end = -1; + } + + public int getStart() { + return start; + } + + public int getEnd() { + return end; + } + + public ISourceContext getSourceContext() { + return sourceContext; + } + + public String getFileName() { + return "unknown"; + } + + public void setLocation(ISourceContext sourceContext, int start, int end) { + this.sourceContext = sourceContext; + this.start = start; + this.end = end; + } + + public void copyLocationFrom(PatternNode other) { + this.start = other.start; + this.end = other.end; + this.sourceContext = other.sourceContext; + } + + public ISourceLocation getSourceLocation() { + //System.out.println("get context: " + this + " is " + sourceContext); + if (sourceContext == null) { + //System.err.println("no context: " + this); + return null; + } + return sourceContext.makeSourceLocation(this); + } + + public abstract void write(DataOutputStream s) throws IOException; + + + public void writeLocation(DataOutputStream s) throws IOException { + s.writeInt(start); + s.writeInt(end); + } + + public void readLocation(ISourceContext context, DataInputStream s) throws IOException { + start = s.readInt(); + end = s.readInt(); + this.sourceContext = context; + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/PatternParser.java b/weaver/src/org/aspectj/weaver/patterns/PatternParser.java new file mode 100644 index 000000000..eaeb71f20 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/PatternParser.java @@ -0,0 +1,781 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.util.*; + +import org.aspectj.weaver.*; + +//XXX doesn't handle errors for extra tokens very well (sometimes ignores) +public class PatternParser { + private ITokenSource tokenSource; + + private ISourceContext sourceContext; + + /** + * Constructor for PatternParser. + */ + public PatternParser(ITokenSource tokenSource) { + super(); + this.tokenSource = tokenSource; + this.sourceContext = tokenSource.getSourceContext(); + } + + public PerClause maybeParsePerClause() { + IToken tok = tokenSource.peek(); + if (tok == IToken.EOF) return null; + if (tok.isIdentifier()) { + String name = tok.getString(); + if (name.equals("issingleton")) { + return parsePerSingleton(); + } else if (name.equals("perthis")) { + return parsePerObject(true); + } else if (name.equals("pertarget")) { + return parsePerObject(false); + } else if (name.equals("percflow")) { + return parsePerCflow(false); + } else if (name.equals("percflowbelow")) { + return parsePerCflow(true); + } else { + return null; + } + } + return null; + } + + private PerClause parsePerCflow(boolean isBelow) { + parseIdentifier(); + eat("("); + Pointcut entry = parsePointcut(); + eat(")"); + return new PerCflow(entry, isBelow); + } + + + private PerClause parsePerObject(boolean isThis) { + parseIdentifier(); + eat("("); + Pointcut entry = parsePointcut(); + eat(")"); + return new PerObject(entry, isThis); + } + + + private PerClause parsePerSingleton() { + parseIdentifier(); + eat("("); + eat(")"); + return new PerSingleton(); + } + + + public Declare parseDeclare() { + int startPos = tokenSource.peek().getStart(); + + eatIdentifier("declare"); + String kind = parseIdentifier(); + eat(":"); + Declare ret; + //XXX beta add soft, dominates + if (kind.equals("error")) { + ret = parseErrorOrWarning(true); + } else if (kind.equals("warning")) { + ret = parseErrorOrWarning(false); + } else if (kind.equals("dominates")) { + ret = parseDominates(); + } else if (kind.equals("parents")) { + ret = parseParents(); + } else if (kind.equals("soft")) { + ret = parseSoft(); + } else { + throw new ParserException("expected one of error, warning, parents, soft, dominates", + tokenSource.peek(-1)); + } + int endPos = tokenSource.peek(-1).getEnd(); + ret.setLocation(sourceContext, startPos, endPos); + return ret; + } + + public DeclareDominates parseDominates() { + List l = new ArrayList(); + do { + l.add(parseTypePattern()); + } while (maybeEat(",")); + + return new DeclareDominates(l); + } + + private Declare parseParents() { + TypePattern p = parseTypePattern(); + IToken t = tokenSource.next(); + if (!(t.getString().equals("extends") || t.getString().equals("implements"))) { + throw new ParserException("extends or implements", t); + } + + List l = new ArrayList(); + do { + l.add(parseTypePattern()); + } while (maybeEat(",")); + + //XXX somewhere in the chain we need to enforce that we have only ExactTypePatterns + + return new DeclareParents(p, l); + } + + private Declare parseSoft() { + TypePattern p = parseTypePattern(); + eat(":"); + Pointcut pointcut = parsePointcut(); + return new DeclareSoft(p, pointcut); + } + + + + private Declare parseErrorOrWarning(boolean isError) { + Pointcut pointcut = parsePointcut(); + eat(":"); + String message = parseStringLiteral(); + return new DeclareErrorOrWarning(isError, pointcut, message); + } + + public Pointcut parsePointcut() { + Pointcut p = parseAtomicPointcut(); + if (maybeEat("&&")) { + p = new AndPointcut(p, parseNotOrPointcut()); + } + + if (maybeEat("||")) { + p = new OrPointcut(p, parsePointcut()); + } + return p; + } + + private Pointcut parseNotOrPointcut() { + Pointcut p = parseAtomicPointcut(); + if (maybeEat("&&")) { + p = new AndPointcut(p, parsePointcut()); + } + return p; + } + + private Pointcut parseAtomicPointcut() { + if (maybeEat("!")) { + int startPos = tokenSource.peek(-1).getStart(); + Pointcut p = new NotPointcut(parseAtomicPointcut(), startPos); + return p; + } + if (maybeEat("(")) { + Pointcut p = parsePointcut(); + eat(")"); + return p; + } + int startPos = tokenSource.peek().getStart(); + Pointcut p = parseSinglePointcut(); + int endPos = tokenSource.peek(-1).getEnd(); + p.setLocation(sourceContext, startPos, endPos); + return p; + } + + + + public Pointcut parseSinglePointcut() { + int start = tokenSource.getIndex(); + IToken t = tokenSource.peek(); + Pointcut p = t.maybeGetParsedPointcut(); + if (p != null) { + tokenSource.next(); + return p; + } + + String kind = parseIdentifier(); + tokenSource.setIndex(start); + if (kind.equals("execution") || kind.equals("call") || + kind.equals("get") || kind.equals("set")) { + return parseKindedPointcut(); + } else if (kind.equals("args")) { + return parseArgsPointcut(); + } else if (kind.equals("this") || kind.equals("target")) { + return parseThisOrTargetPointcut(); + } else if (kind.equals("within")) { + return parseWithinPointcut(); + } else if (kind.equals("withincode")) { + return parseWithinCodePointcut(); + } else if (kind.equals("cflow")) { + return parseCflowPointcut(false); + } else if (kind.equals("cflowbelow")) { + return parseCflowPointcut(true); + } else if (kind.equals("adviceexecution")) { + parseIdentifier(); eat("("); + eat(")"); + return new KindedPointcut(Shadow.AdviceExecution, + new SignaturePattern(Member.ADVICE, ModifiersPattern.ANY, + TypePattern.ANY, TypePattern.ANY, NamePattern.ANY, + TypePatternList.ANY, + ThrowsPattern.ANY)); + } else if (kind.equals("handler")) { + parseIdentifier(); eat("("); + TypePattern typePat = parseTypePattern(); + eat(")"); + return new HandlerPointcut(typePat); + } else if (kind.equals("initialization")) { + parseIdentifier(); eat("("); + SignaturePattern sig = parseConstructorSignaturePattern(); + eat(")"); + return new KindedPointcut(Shadow.Initialization, sig); + } else if (kind.equals("staticinitialization")) { + parseIdentifier(); eat("("); + TypePattern typePat = parseTypePattern(); + eat(")"); + return new KindedPointcut(Shadow.StaticInitialization, + new SignaturePattern(Member.STATIC_INITIALIZATION, ModifiersPattern.ANY, + TypePattern.ANY, typePat, NamePattern.ANY, TypePatternList.EMPTY, + ThrowsPattern.ANY)); + } else if (kind.equals("preinitialization")) { + parseIdentifier(); eat("("); + SignaturePattern sig = parseConstructorSignaturePattern(); + eat(")"); + return new KindedPointcut(Shadow.PreInitialization, sig); + } else { + return parseReferencePointcut(); + } + } + + private SignaturePattern parseConstructorSignaturePattern() { + SignaturePattern ret = parseMethodOrConstructorSignaturePattern(); + if (ret.getKind() == Member.CONSTRUCTOR) return ret; + + throw new ParserException("constructor pattern required, found method pattern", + ret); + } + + + private Pointcut parseWithinCodePointcut() { + parseIdentifier(); + eat("("); + SignaturePattern sig = parseMethodOrConstructorSignaturePattern(); + eat(")"); + return new WithincodePointcut(sig); + } + + private Pointcut parseCflowPointcut(boolean isBelow) { + parseIdentifier(); + eat("("); + Pointcut entry = parsePointcut(); + eat(")"); + return new CflowPointcut(entry, isBelow, null); + } + + /** + * Method parseWithinPointcut. + * @return Pointcut + */ + private Pointcut parseWithinPointcut() { + parseIdentifier(); + eat("("); + TypePattern type = parseTypePattern(); + eat(")"); + return new WithinPointcut(type); + } + + + /** + * Method parseThisOrTargetPointcut. + * @return Pointcut + */ + private Pointcut parseThisOrTargetPointcut() { + String kind = parseIdentifier(); + eat("("); + TypePattern type = parseTypePattern(); + eat(")"); + return new ThisOrTargetPointcut(kind.equals("this"), type); + } + + + /** + * Method parseArgsPointcut. + * @return Pointcut + */ + private Pointcut parseArgsPointcut() { + parseIdentifier(); + TypePatternList arguments = parseArgumentsPattern(); + return new ArgsPointcut(arguments); + } + + + private Pointcut parseReferencePointcut() { + TypePattern onType = parseTypePattern(); + NamePattern name = tryToExtractName(onType); + if (name == null) { + throw new ParserException("name pattern", tokenSource.peek()); + } + if (onType.toString().equals("")) { + onType = null; + } + + TypePatternList arguments = parseArgumentsPattern(); + return new ReferencePointcut(onType, name.maybeGetSimpleName(), arguments); + } + + + public List parseDottedIdentifier() { + List ret = new ArrayList(); + ret.add(parseIdentifier()); + while (maybeEat(".")) { + ret.add(parseIdentifier()); + } + return ret; + } + + + + private KindedPointcut parseKindedPointcut() { + String kind = parseIdentifier(); + eat("("); + SignaturePattern sig; + + Shadow.Kind shadowKind = null; + if (kind.equals("execution")) { + sig = parseMethodOrConstructorSignaturePattern(); + if (sig.getKind() == Member.METHOD) { + shadowKind = Shadow.MethodExecution; + } else if (sig.getKind() == Member.CONSTRUCTOR) { + shadowKind = Shadow.ConstructorExecution; + } + } else if (kind.equals("call")) { + sig = parseMethodOrConstructorSignaturePattern(); + if (sig.getKind() == Member.METHOD) { + shadowKind = Shadow.MethodCall; + } else if (sig.getKind() == Member.CONSTRUCTOR) { + shadowKind = Shadow.ConstructorCall; + } + } else if (kind.equals("get")) { + sig = parseFieldSignaturePattern(); + shadowKind = Shadow.FieldGet; + } else if (kind.equals("set")) { + sig = parseFieldSignaturePattern(); + shadowKind = Shadow.FieldSet; + } else { + throw new ParserException("bad kind: " + kind, tokenSource.peek()); + } + eat(")"); + return new KindedPointcut(shadowKind, sig); + } + + public TypePattern parseTypePattern() { + TypePattern p = parseAtomicTypePattern(); + if (maybeEat("&&")) { + p = new AndTypePattern(p, parseNotOrTypePattern()); + } + + if (maybeEat("||")) { + p = new OrTypePattern(p, parseTypePattern()); + } + return p; + } + + private TypePattern parseNotOrTypePattern() { + TypePattern p = parseAtomicTypePattern(); + if (maybeEat("&&")) { + p = new AndTypePattern(p, parseTypePattern()); + } + return p; + } + + private TypePattern parseAtomicTypePattern() { + if (maybeEat("!")) { + int startPos = tokenSource.peek(-1).getStart(); + //??? we lose source location for true start of !type + TypePattern p = new NotTypePattern(parseAtomicTypePattern()); + return p; + } + if (maybeEat("(")) { + TypePattern p = parseTypePattern(); + eat(")"); + return p; + } + int startPos = tokenSource.peek().getStart(); + TypePattern p = parseSingleTypePattern(); + int endPos = tokenSource.peek(-1).getEnd(); + p.setLocation(sourceContext, startPos, endPos); + return p; + } + + public TypePattern parseSingleTypePattern() { + List names = parseDottedNamePattern(); +// new ArrayList(); +// NamePattern p1 = parseNamePattern(); +// names.add(p1); +// while (maybeEat(".")) { +// if (maybeEat(".")) { +// names.add(NamePattern.ELLIPSIS); +// } +// NamePattern p2 = parseNamePattern(); +// names.add(p2); +// } + int dim = 0; + while (maybeEat("[")) { + eat("]"); + dim++; + } + + + boolean includeSubtypes = maybeEat("+"); + int endPos = tokenSource.peek(-1).getEnd(); + + //??? what about the source location of any's???? + if (names.size() == 1 && ((NamePattern)names.get(0)).isAny() && dim == 0) return TypePattern.ANY; + + return new WildTypePattern(names, includeSubtypes, dim, endPos); + } + + public List parseDottedNamePattern() { + List names = new ArrayList(); + StringBuffer buf = new StringBuffer(); + IToken previous = null; + while (true) { + IToken tok; + int startPos = tokenSource.peek().getStart(); + String afterDot = null; + while (true) { + tok = tokenSource.peek(); + if (previous != null) { + if (!isAdjacent(previous, tok)) break; + } + if (tok.getString() == "*" || tok.isIdentifier()) { + buf.append(tok.getString()); + } else if (tok.getLiteralKind() != null) { + //System.err.println("literal kind: " + tok.getString()); + String s = tok.getString(); + int dot = s.indexOf('.'); + if (dot != -1) { + buf.append(s.substring(0, dot)); + afterDot = s.substring(dot+1); + previous = tokenSource.next(); + break; + } + buf.append(s); // ??? so-so + } else { + break; + } + previous = tokenSource.next(); + //XXX need to handle floats and other fun stuff + } + int endPos = tokenSource.peek(-1).getEnd(); + if (buf.length() == 0 && names.isEmpty()) { + throw new ParserException("expected name pattern", tok); + } + + if (buf.length() == 0) { + names.add(NamePattern.ELLIPSIS); + } else { + checkLegalName(buf.toString(), previous); + NamePattern ret = new NamePattern(buf.toString()); + ret.setLocation(sourceContext, startPos, endPos); + names.add(ret); + } + + if (afterDot == null) { + buf.setLength(0); + if (!maybeEat(".")) break; + else previous = tokenSource.peek(-1); + } else { + buf.setLength(0); + buf.append(afterDot); + afterDot = null; + } + } + //System.err.println("parsed: " + names); + return names; + } + + + + public NamePattern parseNamePattern() { + StringBuffer buf = new StringBuffer(); + IToken previous = null; + IToken tok; + int startPos = tokenSource.peek().getStart(); + while (true) { + tok = tokenSource.peek(); + if (previous != null) { + if (!isAdjacent(previous, tok)) break; + } + if (tok.getString() == "*" || tok.isIdentifier()) { + buf.append(tok.getString()); + } else if (tok.getLiteralKind() != null) { + //System.err.println("literal kind: " + tok.getString()); + String s = tok.getString(); + if (s.indexOf('.') != -1) break; + buf.append(s); // ??? so-so + } else { + break; + } + previous = tokenSource.next(); + //XXX need to handle floats and other fun stuff + } + int endPos = tokenSource.peek(-1).getEnd(); + if (buf.length() == 0) { + throw new ParserException("expected name pattern", tok); + } + + checkLegalName(buf.toString(), previous); + NamePattern ret = new NamePattern(buf.toString()); + ret.setLocation(sourceContext, startPos, endPos); + return ret; + } + + private void checkLegalName(String s, IToken tok) { + char ch = s.charAt(0); + if (!(ch == '*' || Character.isJavaIdentifierStart(ch))) { + throw new ParserException("illegal identifier start (" + ch + ")", tok); + } + + for (int i=1, len=s.length(); i < len; i++) { + ch = s.charAt(i); + if (!(ch == '*' || Character.isJavaIdentifierPart(ch))) { + throw new ParserException("illegal identifier character (" + ch + ")", tok); + } + } + + } + + + private boolean isAdjacent(IToken first, IToken second) { + return first.getEnd() == second.getStart()-1; + } + + + public ModifiersPattern parseModifiersPattern() { + int requiredFlags = 0; + int forbiddenFlags = 0; + int start; + while (true) { + start = tokenSource.getIndex(); + boolean isForbidden = false; + isForbidden = maybeEat("!"); + IToken t = tokenSource.next(); + int flag = ModifiersPattern.getModifierFlag(t.getString()); + if (flag == -1) break; + if (isForbidden) forbiddenFlags |= flag; + else requiredFlags |= flag; + } + + tokenSource.setIndex(start); + if (requiredFlags == 0 && forbiddenFlags == 0) { + return ModifiersPattern.ANY; + } else { + return new ModifiersPattern(requiredFlags, forbiddenFlags); + } + } + + public TypePatternList parseArgumentsPattern() { + List patterns = new ArrayList(); + eat("("); + if (maybeEat(")")) { + return new TypePatternList(); + } + + do { + if (maybeEat(".")) { + eat("."); + patterns.add(TypePattern.ELLIPSIS); + } else { + patterns.add(parseTypePattern()); + } + } while (maybeEat(",")); + eat(")"); + return new TypePatternList(patterns); + } + + public ThrowsPattern parseOptionalThrowsPattern() { + IToken t = tokenSource.peek(); + if (t.isIdentifier() && t.getString().equals("throws")) { + tokenSource.next(); + List required = new ArrayList(); + List forbidden = new ArrayList(); + do { + boolean isForbidden = maybeEat("!"); + //???might want an error for a second ! without a paren + TypePattern p = parseTypePattern(); + if (isForbidden) forbidden.add(p); + else required.add(p); + } while (maybeEat(",")); + return new ThrowsPattern(new TypePatternList(required), new TypePatternList(forbidden)); + } + return ThrowsPattern.ANY; + } + + + public SignaturePattern parseMethodOrConstructorSignaturePattern() { + ModifiersPattern modifiers = parseModifiersPattern(); + TypePattern returnType = parseTypePattern(); + + TypePattern declaringType; + NamePattern name = null; + Member.Kind kind; + // here we can check for 'new' + if (maybeEatNew(returnType)) { + kind = Member.CONSTRUCTOR; + if (returnType.toString().length() == 0) { + declaringType = TypePattern.ANY; + } else { + declaringType = returnType; + } + returnType = TypePattern.ANY; + name = NamePattern.ANY; + } else { + kind = Member.METHOD; + declaringType = parseTypePattern(); + if (maybeEat(".")) { + name = parseNamePattern(); + } else { + name = tryToExtractName(declaringType); + if (name == null) { + throw new ParserException("name pattern", tokenSource.peek()); + } + String simpleName = name.maybeGetSimpleName(); + //XXX should add check for any Java keywords + if (simpleName != null && simpleName.equals("new")) { + throw new ParserException("constructor patterns have no return type", + tokenSource.peek()); + } + if (declaringType.toString().equals("")) { + declaringType = declaringType.ANY; + } + } + } + + TypePatternList parameterTypes = parseArgumentsPattern(); + + ThrowsPattern throwsPattern = parseOptionalThrowsPattern(); + + return new SignaturePattern(kind, modifiers, returnType, declaringType, name, parameterTypes, throwsPattern); + } + + private boolean maybeEatNew(TypePattern returnType) { + if (returnType instanceof WildTypePattern) { + WildTypePattern p = (WildTypePattern)returnType; + if (p.maybeExtractName("new")) return true; + } + int start = tokenSource.getIndex(); + if (maybeEat(".")) { + String id = maybeEatIdentifier(); + if (id != null && id.equals("new")) return true; + tokenSource.setIndex(start); + } + + return false; + } + + + public SignaturePattern parseFieldSignaturePattern() { + ModifiersPattern modifiers = parseModifiersPattern(); + TypePattern returnType = parseTypePattern(); + TypePattern declaringType = parseTypePattern(); + NamePattern name; + //System.err.println("parsed field: " + declaringType.toString()); + if (maybeEat(".")) { + name = parseNamePattern(); + } else { + name = tryToExtractName(declaringType); + if (declaringType.toString().equals("")) { + declaringType = declaringType.ANY; + } + } + return new SignaturePattern(Member.FIELD, modifiers, returnType, + declaringType, name, TypePatternList.ANY, ThrowsPattern.ANY); + } + + + private NamePattern tryToExtractName(TypePattern nextType) { + if (nextType == TypePattern.ANY) { + return NamePattern.ANY; + } else if (nextType instanceof WildTypePattern) { + WildTypePattern p = (WildTypePattern)nextType; + return p.extractName(); + } else { + return null; + } + } + + public String parseStringLiteral() { + IToken token = tokenSource.next(); + String literalKind = token.getLiteralKind(); + if (literalKind == "string") { + return token.getString(); + } + + throw new ParserException("string", token); + } + + public String parseIdentifier() { + IToken token = tokenSource.next(); + if (token.isIdentifier()) return token.getString(); + throw new ParserException("identifier", token); + } + + public void eatIdentifier(String expectedValue) { + IToken next = tokenSource.next(); + if (!next.getString().equals(expectedValue)) { + throw new ParserException(expectedValue, next); + } + } + + public boolean maybeEatIdentifier(String expectedValue) { + IToken next = tokenSource.peek(); + if (next.getString().equals(expectedValue)) { + tokenSource.next(); + return true; + } else { + return false; + } + } + + public void eat(String expectedValue) { + IToken next = tokenSource.next(); + if (next.getString() != expectedValue) { + throw new ParserException(expectedValue, next); + } + } + + public boolean maybeEat(String token) { + IToken next = tokenSource.peek(); + if (next.getString() == token) { + tokenSource.next(); + return true; + } else { + return false; + } + } + + public String maybeEatIdentifier() { + IToken next = tokenSource.peek(); + if (next.isIdentifier()) { + tokenSource.next(); + return next.getString(); + } else { + return null; + } + } + + public boolean peek(String token) { + IToken next = tokenSource.peek(); + return next.getString() == token; + } + + + public PatternParser(String data) { + this(BasicTokenSource.makeTokenSource(data)); + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/PerCflow.java b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java new file mode 100644 index 000000000..35614041a --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/PerCflow.java @@ -0,0 +1,98 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.util.FuzzyBoolean; + +public class PerCflow extends PerClause { + private boolean isBelow; + private Pointcut entry; + + public PerCflow(Pointcut entry, boolean isBelow) { + this.entry = entry; + this.isBelow = isBelow; + } + + // ----- + + public FuzzyBoolean match(Shadow shadow) { + return FuzzyBoolean.YES; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + // assert bindings == null; + entry.resolve(scope); + } + + public Test findResidue(Shadow shadow, ExposedState state) { + Expr myInstance = + Expr.makeCallExpr(AjcMemberMaker.perCflowAspectOfMethod(inAspect), + Expr.NONE, inAspect); + state.setAspectInstance(myInstance); + return Test.makeCall(AjcMemberMaker.perCflowHasAspectMethod(inAspect), Expr.NONE); + } + + + public PerClause concretize(ResolvedTypeX inAspect) { + PerCflow ret = new PerCflow(entry, isBelow); + ret.inAspect = inAspect; + if (inAspect.isAbstract()) return ret; + + Member cflowStackField = new ResolvedMember( + Member.FIELD, inAspect, Modifier.STATIC|Modifier.PUBLIC|Modifier.FINAL, + TypeX.forName(NameMangler.CFLOW_STACK_TYPE), NameMangler.PERCFLOW_FIELD_NAME, TypeX.NONE); + + World world = inAspect.getWorld(); + + CrosscuttingMembers xcut = inAspect.crosscuttingMembers; + + Collection previousCflowEntries = xcut.getCflowEntries(); + Pointcut concreteEntry = entry.concretize(inAspect, IntMap.EMPTY); + List innerCflowEntries = new ArrayList(xcut.getCflowEntries()); + innerCflowEntries.removeAll(previousCflowEntries); + + xcut.addConcreteShadowMunger( + Advice.makePerCflowEntry(world, concreteEntry, isBelow, cflowStackField, + inAspect, innerCflowEntries)); + return ret; + } + + public void write(DataOutputStream s) throws IOException { + PERCFLOW.write(s); + entry.write(s); + s.writeBoolean(isBelow); + writeLocation(s); + } + + public static PerClause readPerClause(DataInputStream s, ISourceContext context) throws IOException { + PerCflow ret = new PerCflow(Pointcut.read(s, context), s.readBoolean()); + ret.readLocation(context, s); + return ret; + } + + public PerClause.Kind getKind() { + return PERCFLOW; + } + + public String toString() { + return "percflow(" + inAspect + " on " + entry + ")"; + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/PerClause.java b/weaver/src/org/aspectj/weaver/patterns/PerClause.java new file mode 100644 index 000000000..7ff029818 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/PerClause.java @@ -0,0 +1,67 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.List; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.Test; +import org.aspectj.util.*; +import org.aspectj.util.FuzzyBoolean; + +public abstract class PerClause extends Pointcut { + protected ResolvedTypeX inAspect; + + public static PerClause readPerClause(DataInputStream s, ISourceContext context) throws IOException { + Kind kind = Kind.read(s); + if (kind == SINGLETON) return PerSingleton.readPerClause(s, context); + else if (kind == PERCFLOW) return PerCflow.readPerClause(s, context); + else if (kind == PEROBJECT) return PerObject.readPerClause(s, context); + else if (kind == FROMSUPER) return PerFromSuper.readPerClause(s, context); + + throw new BCException("unknown kind: " + kind); + } + + public final Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + throw new RuntimeException("unimplemented: wrong concretize"); + } + + public abstract PerClause concretize(ResolvedTypeX inAspect); + + + public abstract PerClause.Kind getKind(); + + + public static class Kind extends TypeSafeEnum { + public Kind(String name, int key) { super(name, key); } + + public static Kind read(DataInputStream s) throws IOException { + int key = s.readByte(); + switch(key) { + case 1: return SINGLETON; + case 2: return PERCFLOW; + case 3: return PEROBJECT; + case 4: return FROMSUPER; + } + throw new BCException("weird kind " + key); + } + } + + public static final Kind SINGLETON = new Kind("issingleton", 1); + public static final Kind PERCFLOW = new Kind("percflow", 2); + public static final Kind PEROBJECT = new Kind("perobject", 3); + public static final Kind FROMSUPER = new Kind("fromsuper", 4); +} diff --git a/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java b/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java new file mode 100644 index 000000000..e0fa53166 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/PerFromSuper.java @@ -0,0 +1,94 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.bridge.MessageUtil; +import org.aspectj.util.FuzzyBoolean; + +public class PerFromSuper extends PerClause { + private PerClause.Kind kind; + + public PerFromSuper(PerClause.Kind kind) { + this.kind = kind; + } + + public FuzzyBoolean match(Shadow shadow) { + throw new RuntimeException("unimplemented"); + } + + public void resolveBindings(IScope scope, Bindings bindings) { + // this method intentionally left blank + } + + public Test findResidue(Shadow shadow, ExposedState state) { + throw new RuntimeException("unimplemented"); + } + + + public PerClause concretize(ResolvedTypeX inAspect) { + PerClause p = lookupConcretePerClause(inAspect.getSuperclass()); + if (p == null) { + inAspect.getWorld().getMessageHandler().handleMessage( + MessageUtil.error("expected per clause on super aspect not found on " + + inAspect.getSuperclass(), getSourceLocation()) + ); + } + if (p.getKind() != kind) { + inAspect.getWorld().getMessageHandler().handleMessage( + MessageUtil.error("wrong kind of per clause on super, expected " + + kind + " but found " + p.getKind(), + getSourceLocation()) + ); + } + return p.concretize(inAspect); + } + + + + private PerClause lookupConcretePerClause(ResolvedTypeX lookupType) { + PerClause ret = lookupType.getPerClause(); + if (ret == null) return null; + if (ret instanceof PerFromSuper) { + return lookupConcretePerClause(lookupType.getSuperclass()); + } + return ret; + } + + + public void write(DataOutputStream s) throws IOException { + FROMSUPER.write(s); + kind.write(s); + writeLocation(s); + } + + public static PerClause readPerClause(DataInputStream s, ISourceContext context) throws IOException { + PerFromSuper ret = new PerFromSuper(Kind.read(s)); + ret.readLocation(context, s); + return ret; + } + + public String toString() { + return "perFromSuper(" + kind + ", " + inAspect + ")"; + } + + public PerClause.Kind getKind() { + return kind; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/PerObject.java b/weaver/src/org/aspectj/weaver/patterns/PerObject.java new file mode 100644 index 000000000..de73e7066 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/PerObject.java @@ -0,0 +1,104 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.List; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.util.FuzzyBoolean; + +public class PerObject extends PerClause { + private boolean isThis; + private Pointcut entry; + + public PerObject(Pointcut entry, boolean isThis) { + this.entry = entry; + this.isThis = isThis; + } + + // ----- + + public FuzzyBoolean match(Shadow shadow) { + //System.err.println("matches " + this + " ? " + shadow + ", " + shadow.hasTarget()); + //??? could probably optimize this better by testing could match + if (isThis) return FuzzyBoolean.fromBoolean(shadow.hasThis()); + else return FuzzyBoolean.fromBoolean(shadow.hasTarget()); + } + + public void resolveBindings(IScope scope, Bindings bindings) { + // assert bindings == null; + entry.resolve(scope); + } + + private Var getVar(Shadow shadow) { + return isThis ? shadow.getThisVar() : shadow.getTargetVar(); + } + + public Test findResidue(Shadow shadow, ExposedState state) { + Expr myInstance = + Expr.makeCallExpr(AjcMemberMaker.perObjectAspectOfMethod(inAspect), + new Expr[] {getVar(shadow)}, inAspect); + state.setAspectInstance(myInstance); + return Test.makeCall(AjcMemberMaker.perObjectHasAspectMethod(inAspect), + new Expr[] { getVar(shadow) }); + } + + + + public PerClause concretize(ResolvedTypeX inAspect) { + PerObject ret = new PerObject(entry, isThis); + + ret.inAspect = inAspect; + if (inAspect.isAbstract()) return ret; + + + World world = inAspect.getWorld(); + + Pointcut concreteEntry = entry.concretize(inAspect, IntMap.EMPTY); + //concreteEntry = new AndPointcut(this, concreteEntry); + //concreteEntry.state = Pointcut.CONCRETE; + inAspect.crosscuttingMembers.addConcreteShadowMunger( + Advice.makePerObjectEntry(world, concreteEntry, isThis, inAspect)); + ResolvedTypeMunger munger = + new PerObjectInterfaceTypeMunger(inAspect, concreteEntry); + inAspect.crosscuttingMembers.addTypeMunger(world.concreteTypeMunger(munger, inAspect)); + return ret; + } + + public void write(DataOutputStream s) throws IOException { + PEROBJECT.write(s); + entry.write(s); + s.writeBoolean(isThis); + writeLocation(s); + } + + public static PerClause readPerClause(DataInputStream s, ISourceContext context) throws IOException { + PerClause ret = new PerObject(Pointcut.read(s, context), s.readBoolean()); + ret.readLocation(context, s); + return ret; + } + + public PerClause.Kind getKind() { + return PEROBJECT; + } + + public String toString() { + return "per" + (isThis ? "this" : "target") + + "(" + entry + ")"; + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java b/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java new file mode 100644 index 000000000..e95065ece --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/PerSingleton.java @@ -0,0 +1,68 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.util.FuzzyBoolean; + +public class PerSingleton extends PerClause { + public PerSingleton() { + } + + public FuzzyBoolean match(Shadow shadow) { + return FuzzyBoolean.YES; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + // this method intentionally left blank + } + + public Test findResidue(Shadow shadow, ExposedState state) { + state.setAspectInstance( + Expr.makeFieldGet(AjcMemberMaker.perSingletonField(inAspect), inAspect)); + // XXX we need to think about whether it's null... + return Literal.TRUE; + } + + public PerClause concretize(ResolvedTypeX inAspect) { + PerSingleton ret = new PerSingleton(); + ret.inAspect = inAspect; + return ret; + } + + public void write(DataOutputStream s) throws IOException { + SINGLETON.write(s); + writeLocation(s); + } + + public static PerClause readPerClause(DataInputStream s, ISourceContext context) throws IOException { + PerSingleton ret = new PerSingleton(); + ret.readLocation(context, s); + return ret; + } + + + public PerClause.Kind getKind() { + return SINGLETON; + } + + public String toString() { + return "persingleton(" + inAspect + ")"; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/Pointcut.java b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java new file mode 100644 index 000000000..99f7f6bc8 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/Pointcut.java @@ -0,0 +1,228 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.Map; + +import org.apache.bcel.classfile.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.util.*; + +/** + * The lifecycle of Pointcuts is modeled by Pointcut.State. It has three things: + * + * <p>Creation -- SYMBOLIC -- then resolve(IScope) -- RESOLVED -- concretize(...) -- CONCRETE + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public abstract class Pointcut extends PatternNode { + public static final class State extends TypeSafeEnum { + public State(String name, int key) { + super(name, key); + } + } + + public static final State SYMBOLIC = new State("symbolic", 0); + public static final State RESOLVED = new State("resolved", 1); + public static final State CONCRETE = new State("concrete", 2); + + + public State state; + + /** + * Constructor for Pattern. + */ + public Pointcut() { + super(); + this.state = SYMBOLIC; + } + + + /** + * Could I match any shadows in this JavaClass + */ + public boolean fastMatch(JavaClass jc) { return true; } + + /** + * Do I really match this shadow? + * XXX implementors need to handle state + */ + public abstract FuzzyBoolean match(Shadow shadow); + + + public static final byte KINDED = 1; + public static final byte WITHIN = 2; + public static final byte THIS_OR_TARGET = 3; + public static final byte ARGS = 4; + public static final byte AND = 5; + public static final byte OR = 6; + public static final byte NOT = 7; + public static final byte REFERENCE = 8; + public static final byte IF = 9; + public static final byte CFLOW = 10; + public static final byte WITHINCODE = 12; + public static final byte HANDLER = 13; + + public static final byte NONE = 20; + + + // internal, only called from resolve + protected abstract void resolveBindings(IScope scope, Bindings bindings); + + /** + * Returns this pointcut mutated + */ + public Pointcut resolve(IScope scope) { + assertState(SYMBOLIC); + Bindings bindingTable = new Bindings(scope.getFormalCount()); + this.resolveBindings(scope, bindingTable); + bindingTable.checkAllBound(scope); + this.state = RESOLVED; + return this; + } + + /** + * Returns a new pointcut + */ + public Pointcut concretize(ResolvedTypeX inAspect, int arity) { + return concretize(inAspect, IntMap.idMap(arity)); + } + + + //XXX this is the signature we're moving to + public Pointcut concretize(ResolvedTypeX inAspect, int arity, Advice advice) { + //if (state == CONCRETE) return this; //??? + IntMap map = IntMap.idMap(arity); + map.setEnclosingAdvice(advice); + return concretize(inAspect, map); + } + + + + public Pointcut concretize(ResolvedTypeX inAspect, IntMap bindings) { + assertState(RESOLVED); + Pointcut ret = this.concretize1(inAspect, bindings); + ret.state = CONCRETE; + return ret; + } + + + /** + * Resolves and removes ReferencePointcuts, replacing with basic ones + * + * @param inAspect the aspect to resolve relative to + * @param bindings a Map from formal index in the current lexical context + * -> formal index in the concrete advice that will run + * + * ??? does this return a new pointcut + * XXX fix implementors to handle state + */ + protected abstract Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings); + + + //XXX implementors need to handle state + /** + * This can be called from NotPointcut even for Pointcuts that + * don't match the shadow + */ + public abstract Test findResidue(Shadow shadow, ExposedState state); + + //XXX we're not sure whether or not this is needed + //XXX currently it's unused we're keeping it around as a stub + public void postRead(ResolvedTypeX enclosingType) {} + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + byte kind = s.readByte(); + Pointcut ret; + + switch(kind) { + case KINDED: ret = KindedPointcut.read(s, context); break; + case WITHIN: ret = WithinPointcut.read(s, context); break; + case THIS_OR_TARGET: ret = ThisOrTargetPointcut.read(s, context); break; + case ARGS: ret = ArgsPointcut.read(s, context); break; + case AND: ret = AndPointcut.read(s, context); break; + case OR: ret = OrPointcut.read(s, context); break; + case NOT: ret = NotPointcut.read(s, context); break; + case REFERENCE: ret = ReferencePointcut.read(s, context); break; + case IF: ret = IfPointcut.read(s, context); break; + case CFLOW: ret = CflowPointcut.read(s, context); break; + case WITHINCODE: ret = WithincodePointcut.read(s, context); break; + case HANDLER: ret = HandlerPointcut.read(s, context); break; + + case NONE: ret = makeMatchesNothing(RESOLVED); break; + default: + throw new BCException("unknown kind: " + kind); + } + ret.state = RESOLVED; + return ret; + } + + + //public void prepare(Shadow shadow) {} + + // ---- test method + + public static Pointcut fromString(String str) { + PatternParser parser = new PatternParser(str); + return parser.parsePointcut(); + } + + private static class MatchesNothingPointcut extends Pointcut { + public Test findResidue(Shadow shadow, ExposedState state) { + return Literal.FALSE; // can only get here if an earlier error occurred + } + + public FuzzyBoolean match(Shadow shadow) { + return FuzzyBoolean.NO; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + } + + public void postRead(ResolvedTypeX enclosingType) { + } + + public Pointcut concretize1( + ResolvedTypeX inAspect, + IntMap bindings) { + return this; + } + + + public void write(DataOutputStream s) throws IOException { + s.writeByte(NONE); + } + + public String toString() { return ""; } + } + + //public static Pointcut MatchesNothing = new MatchesNothingPointcut(); + //??? there could possibly be some good optimizations to be done at this point + public static Pointcut makeMatchesNothing(State state) { + Pointcut ret = new MatchesNothingPointcut(); + ret.state = state; + return ret; + } + + public void assertState(State state) { + if (this.state != state) { + throw new BCException("expected state: " + state + " got: " + this.state); + } + } + + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java b/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java new file mode 100644 index 000000000..518172ed5 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ReferencePointcut.java @@ -0,0 +1,266 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; +import java.util.Map; + +import org.apache.bcel.classfile.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.bridge.*; +import org.aspectj.bridge.MessageUtil; +import org.aspectj.util.*; + +/** + */ + +//XXX needs check that arguments contains no WildTypePatterns +public class ReferencePointcut extends Pointcut { + public TypeX onType; + public TypePattern onTypeSymbolic; + public String name; + public TypePatternList arguments; + + //public ResolvedPointcut binding; + + public ReferencePointcut(TypePattern onTypeSymbolic, String name, TypePatternList arguments) { + this.onTypeSymbolic = onTypeSymbolic; + this.name = name; + this.arguments = arguments; + } + + public ReferencePointcut(TypeX onType, String name, TypePatternList arguments) { + this.onType = onType; + this.name = name; + this.arguments = arguments; + } + + /** + * Could I match any shadows in this JavaClass + */ + public boolean fastMatch(JavaClass jc) { return true; } + + /** + * Do I really match this shadow? + */ + public FuzzyBoolean match(Shadow shadow) { + return FuzzyBoolean.NO; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + if (onType != null) { + buf.append(onType); + buf.append("."); +// for (int i=0, len=fromType.length; i < len; i++) { +// buf.append(fromType[i]); +// buf.append("."); +// } + } + buf.append(name); + buf.append(arguments.toString()); + return buf.toString(); + } + + + public void write(DataOutputStream s) throws IOException { + //XXX ignores onType + s.writeByte(Pointcut.REFERENCE); + if (onType != null) { + s.writeBoolean(true); + onType.write(s); + } else { + s.writeBoolean(false); + } + + s.writeUTF(name); + arguments.write(s); + writeLocation(s); + } + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + TypeX onType = null; + if (s.readBoolean()) { + onType = TypeX.read(s); + } + ReferencePointcut ret = new ReferencePointcut(onType, s.readUTF(), + TypePatternList.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + if (onTypeSymbolic != null) { + onType = onTypeSymbolic.resolveExactType(scope, bindings); + } + + ResolvedTypeX searchType; + if (onType != null) { + searchType = scope.getWorld().resolve(onType); + } else { + searchType = scope.getEnclosingType(); + } + + + arguments.resolveBindings(scope, bindings, true); + //XXX ensure that arguments has no ..'s in it + + // check that I refer to a real pointcut declaration and that I match + + ResolvedPointcutDefinition pointcutDef = searchType.findPointcut(name); + // if we're not a static reference, then do a lookup of outers + if (onType == null) { + while (true) { + TypeX declaringType = searchType.getDeclaringType(); + if (declaringType == null) break; + searchType = declaringType.resolve(scope.getWorld()); + pointcutDef = searchType.findPointcut(name); + if (pointcutDef != null) { + // make this a static reference + onType = searchType; + break; + } + } + } + + if (pointcutDef == null) { + scope.message(IMessage.ERROR, this, "can't find referenced pointcut"); + return; + } + + if (Modifier.isAbstract(pointcutDef.getModifiers())) { + if (onType != null) { + scope.message(IMessage.ERROR, this, + "can't make static reference to abstract pointcut"); + return; + } else if (!searchType.isAbstract()) { + scope.message(IMessage.ERROR, this, + "can't use abstract pointcut in concrete context"); + return; + } + } + + + ResolvedTypeX[] parameterTypes = + scope.getWorld().resolve(pointcutDef.getParameterTypes()); + + if (parameterTypes.length != arguments.size()) { + scope.message(IMessage.ERROR, this, "incompatible number of arguments to pointcut, expected " + + parameterTypes.length + " found " + arguments.size()); + return; + } + + + + for (int i=0,len=arguments.size(); i < len; i++) { + TypePattern p = arguments.get(i); + //we are allowed to bind to pointcuts which use subtypes as this is type safe + if (!p.matchesSubtypes(parameterTypes[i])) { + scope.message(IMessage.ERROR, p, "incompatible type, expected " + + parameterTypes[i] + " found " + p); + return; + } + } + } + + public void postRead(ResolvedTypeX enclosingType) { + arguments.postRead(enclosingType); + } + + public Test findResidue(Shadow shadow, ExposedState state) { + throw new RuntimeException("shouldn't happen"); + } + + + //??? This is not thread safe, but this class is not designed for multi-threading + private boolean concretizing = false; + public Pointcut concretize1(ResolvedTypeX searchStart, IntMap bindings) { + if (concretizing) { + Thread.currentThread().dumpStack(); + searchStart.getWorld().getMessageHandler().handleMessage( + MessageUtil.error("circular pointcut declaration involving: " + this, + getSourceLocation())); + return Pointcut.makeMatchesNothing(Pointcut.CONCRETE); + } + + try { + concretizing = true; + + ResolvedPointcutDefinition pointcutDec; + if (onType != null) { + searchStart = onType.resolve(searchStart.getWorld()); + if (searchStart == ResolvedTypeX.MISSING) { + return Pointcut.makeMatchesNothing(Pointcut.CONCRETE); + } + } + pointcutDec = searchStart.findPointcut(name); + if (pointcutDec == null) { + searchStart.getWorld().getMessageHandler().handleMessage( + MessageUtil.error("can't find pointcut \'" + name + "\' on " + searchStart.getName(), + getSourceLocation()) + ); + return Pointcut.makeMatchesNothing(Pointcut.CONCRETE); + } + //??? error if we don't find + + //System.err.println("start: " + searchStart); + ResolvedTypeX[] parameterTypes = searchStart.getWorld().resolve(pointcutDec.getParameterTypes()); + + arguments = arguments.resolveReferences(bindings); + + IntMap newBindings = new IntMap(); + for (int i=0,len=arguments.size(); i < len; i++) { + TypePattern p = arguments.get(i); + //we are allowed to bind to pointcuts which use subtypes as this is type safe + if (!p.matchesSubtypes(parameterTypes[i])) { + throw new BCException("illegal change to pointcut declaration: " + this); + } + + if (p instanceof BindingTypePattern) { + newBindings.put(i, ((BindingTypePattern)p).getFormalIndex()); + } + } + + newBindings.copyContext(bindings); + newBindings.pushEnclosingDefinition(pointcutDec); + try { + return pointcutDec.getPointcut().concretize1(searchStart, newBindings); + } finally { + newBindings.popEnclosingDefinitition(); + } + + } finally { + concretizing = false; + } + } + + public boolean equals(Object other) { + if (!(other instanceof ReferencePointcut)) return false; + ReferencePointcut o = (ReferencePointcut)other; + return o.name.equals(name) && o.arguments.equals(arguments) + && ((o.onType == null) ? (onType == null) : o.onType.equals(onType)); + } + public int hashCode() { + int result = 17; + result = 37*result + ((onType == null) ? 0 : onType.hashCode()); + result = 37*result + arguments.hashCode(); + result = 37*result + name.hashCode(); + return result; + } + + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java new file mode 100644 index 000000000..fe47e13f4 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/SignaturePattern.java @@ -0,0 +1,224 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.*; +import java.util.Collection; + +import org.aspectj.weaver.*; + + +public class SignaturePattern extends PatternNode { + private Member.Kind kind; + private ModifiersPattern modifiers; + private TypePattern returnType; + private TypePattern declaringType; + private NamePattern name; + private TypePatternList parameterTypes; + private ThrowsPattern throwsPattern; + + public SignaturePattern(Member.Kind kind, ModifiersPattern modifiers, + TypePattern returnType, TypePattern declaringType, + NamePattern name, TypePatternList parameterTypes, + ThrowsPattern throwsPattern) { + this.kind = kind; + this.modifiers = modifiers; + this.returnType = returnType; + this.name = name; + this.declaringType = declaringType; + this.parameterTypes = parameterTypes; + this.throwsPattern = throwsPattern; + } + + + public SignaturePattern resolveBindings(IScope scope, Bindings bindings) { + if (returnType != null) { + returnType = returnType.resolveBindings(scope, bindings, false); + } + if (declaringType != null) { + declaringType = declaringType.resolveBindings(scope, bindings, false); + } + if (parameterTypes != null) { + parameterTypes = parameterTypes.resolveBindings(scope, bindings, false); + } + if (throwsPattern != null) { + throwsPattern = throwsPattern.resolveBindings(scope, bindings); + } + + return this; + } + + + public void postRead(ResolvedTypeX enclosingType) { + if (returnType != null) { + returnType.postRead(enclosingType); + } + if (declaringType != null) { + declaringType.postRead(enclosingType); + } + if (parameterTypes != null) { + parameterTypes.postRead(enclosingType); + } + } + + public boolean matches(Member member, World world) { + //XXX performance gains would come from matching on name before resolving + // to fail fast + ResolvedMember sig = member.resolve(world); + if (sig == null) { + //XXX + if (member.getName().startsWith(NameMangler.PREFIX)) { + return false; + } + world.getLint().unresolvableMember.signal(member.toString(), getSourceLocation()); + return false; + } + if (!modifiers.matches(sig.getModifiers())) return false; + + if (kind == Member.STATIC_INITIALIZATION) { + //System.err.println("match static init: " + sig.getDeclaringType() + " with " + this); + return declaringType.matchesStatically(sig.getDeclaringType().resolve(world)); + } else if (kind == Member.FIELD) { + + if (!returnType.matchesStatically(sig.getReturnType().resolve(world))) return false; + if (!name.matches(sig.getName())) return false; + boolean ret = declaringTypeMatch(member.getDeclaringType(), member, world); + //System.out.println(" ret: " + ret); + return ret; + } else if (kind == Member.METHOD) { + if (!returnType.matchesStatically(sig.getReturnType().resolve(world))) return false; + if (!name.matches(sig.getName())) return false; + if (!parameterTypes.matches(world.resolve(sig.getParameterTypes()), TypePattern.STATIC).alwaysTrue()) { + return false; + } + if (!throwsPattern.matches(sig.getExceptions(), world)) return false; + return declaringTypeMatch(member.getDeclaringType(), member, world); + } else if (kind == Member.CONSTRUCTOR) { + if (!parameterTypes.matches(world.resolve(sig.getParameterTypes()), TypePattern.STATIC).alwaysTrue()) { + return false; + } + if (!throwsPattern.matches(sig.getExceptions(), world)) return false; + return declaringType.matchesStatically(member.getDeclaringType().resolve(world)); + //return declaringTypeMatch(member.getDeclaringType(), member, world); + } + + return false; + } + + private boolean declaringTypeMatch(TypeX onTypeUnresolved, Member member, World world) { + ResolvedTypeX onType = onTypeUnresolved.resolve(world); + + // fastmatch + if (declaringType.matchesStatically(onType)) return true; + + Collection declaringTypes = member.getDeclaringTypes(world); + + for (Iterator i = declaringTypes.iterator(); i.hasNext(); ) { + ResolvedTypeX type = (ResolvedTypeX)i.next(); + if (declaringType.matchesStatically(type)) return true; + } + return false; + } + + + public NamePattern getName() { return name; } + public TypePattern getDeclaringType() { return declaringType; } + + public Member.Kind getKind() { + return kind; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + if (modifiers != ModifiersPattern.ANY) { + buf.append(modifiers.toString()); + buf.append(' '); + } + + if (kind == Member.STATIC_INITIALIZATION) { + buf.append(declaringType.toString()); + buf.append(".<clinit>()"); + } else if (kind == Member.HANDLER) { + buf.append("handler("); + buf.append(parameterTypes.get(0)); + buf.append(")"); + } else { + if (!(kind == Member.CONSTRUCTOR)) { + buf.append(returnType.toString()); + buf.append(' '); + } + if (declaringType != TypePattern.ANY) { + buf.append(declaringType.toString()); + buf.append('.'); + } + if (kind == Member.CONSTRUCTOR) { + buf.append("new"); + } else { + buf.append(name.toString()); + } + if (kind == Member.METHOD || kind == Member.CONSTRUCTOR) { + buf.append(parameterTypes.toString()); + } + } + return buf.toString(); + } + + public boolean equals(Object other) { + if (!(other instanceof SignaturePattern)) return false; + SignaturePattern o = (SignaturePattern)other; + return o.kind.equals(this.kind) + && o.modifiers.equals(this.modifiers) + && o.returnType.equals(this.returnType) + && o.declaringType.equals(this.declaringType) + && o.name.equals(this.name) + && o.parameterTypes.equals(this.parameterTypes); + } + public int hashCode() { + int result = 17; + result = 37*result + kind.hashCode(); + result = 37*result + modifiers.hashCode(); + result = 37*result + returnType.hashCode(); + result = 37*result + declaringType.hashCode(); + result = 37*result + name.hashCode(); + result = 37*result + parameterTypes.hashCode(); + return result; + } + + public void write(DataOutputStream s) throws IOException { + kind.write(s); + modifiers.write(s); + returnType.write(s); + declaringType.write(s); + name.write(s); + parameterTypes.write(s); + throwsPattern.write(s); + writeLocation(s); + } + + public static SignaturePattern read(DataInputStream s, ISourceContext context) throws IOException { + Member.Kind kind = Member.Kind.read(s); + ModifiersPattern modifiers = ModifiersPattern.read(s); + TypePattern returnType = TypePattern.read(s, context); + TypePattern declaringType = TypePattern.read(s, context); + NamePattern name = NamePattern.read(s); + TypePatternList parameterTypes = TypePatternList.read(s, context); + ThrowsPattern throwsPattern = ThrowsPattern.read(s, context); + SignaturePattern ret = new SignaturePattern(kind, modifiers, returnType, declaringType, + name, parameterTypes, throwsPattern); + ret.readLocation(context, s); + return ret; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/SimpleScope.java b/weaver/src/org/aspectj/weaver/patterns/SimpleScope.java new file mode 100644 index 000000000..2821e67ae --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/SimpleScope.java @@ -0,0 +1,137 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import org.aspectj.weaver.*; +import org.aspectj.bridge.*; +import org.aspectj.bridge.IMessageHandler; + +public class SimpleScope implements IScope { + + private World world; + private ResolvedTypeX enclosingType; + private FormalBinding[] bindings; + + private String[] importedPrefixes = javaLangPrefixArray; + private String[] importedNames = ZERO_STRINGS; + + public SimpleScope(World world, FormalBinding[] bindings) { + super(); + this.world = world; + this.bindings = bindings; + } + + // ---- impl + + //XXX doesn't report any problems + public TypeX lookupType(String name, IHasPosition location) { + for (int i=0; i<importedNames.length; i++) { + String importedName = importedNames[i]; + if (importedName.endsWith(name)) { + return world.resolve(importedName); + } + } + + for (int i=0; i<importedPrefixes.length; i++) { + String importedPrefix = importedPrefixes[i]; + TypeX tryType = world.resolve(TypeX.forName(importedPrefix + name), true); + if (tryType != ResolvedTypeX.MISSING) { + return tryType; + } + } + + return world.resolve(TypeX.forName(name), true); + } + + + public IMessageHandler getMessageHandler() { + return world.getMessageHandler(); + } + public FormalBinding lookupFormal(String name) { + for (int i = 0, len = bindings.length; i < len; i++) { + if (bindings[i].getName().equals(name)) return bindings[i]; + } + return null; + } + public FormalBinding getFormal(int i) { + return bindings[i]; + } + + public int getFormalCount() { + return bindings.length; + } + + public String[] getImportedNames() { + return importedNames; + } + public String[] getImportedPrefixes() { + return importedPrefixes; + } + + public void setImportedNames(String[] importedNames) { + this.importedNames = importedNames; + } + public void setImportedPrefixes(String[] importedPrefixes) { + this.importedPrefixes = importedPrefixes; + } + + public static FormalBinding[] makeFormalBindings(TypeX[] types, String[] names) { + int len = types.length; + FormalBinding[] bindings = new FormalBinding[len]; + for (int i = 0; i < len; i++) { + bindings[i] = new FormalBinding(types[i], names[i], i); + } + return bindings; + } + + // ---- fields + + public static final String[] ZERO_STRINGS = new String[0]; + + public static final String[] javaLangPrefixArray = + new String[] { "java.lang.", }; + + + + public ISourceLocation makeSourceLocation(IHasPosition location) { + return new SourceLocation(ISourceLocation.NO_FILE, 0); + } + + public void message( + IMessage.Kind kind, + IHasPosition location1, + IHasPosition location2, + String message) { + message(kind, location1, message); + message(kind, location2, message); + } + + public void message( + IMessage.Kind kind, + IHasPosition location, + String message) { + getMessageHandler() + .handleMessage(new Message(message, kind, null, makeSourceLocation(location))); + + } + + public World getWorld() { + return world; + } + + public ResolvedTypeX getEnclosingType() { + return enclosingType; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java new file mode 100644 index 000000000..9baf92e10 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ThisOrTargetPointcut.java @@ -0,0 +1,108 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.util.FuzzyBoolean; +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; + +// + +/** + * Corresponds to target or this pcd. + * + * <p>type is initially a WildTypePattern. If it stays that way, it's a this(Foo) + * type deal. + * however, the resolveBindings method may convert it to a BindingTypePattern, + * in which + * case, it's a this(foo) type deal. + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public class ThisOrTargetPointcut extends NameBindingPointcut { + private boolean isThis; + private TypePattern type; + + public ThisOrTargetPointcut(boolean isThis, TypePattern type) { + this.isThis = isThis; + this.type = type; + } + + private boolean couldMatch(Shadow shadow) { + return isThis ? shadow.hasThis() : shadow.hasTarget(); + } + + public FuzzyBoolean match(Shadow shadow) { + if (!couldMatch(shadow)) return FuzzyBoolean.NO; + TypeX typeToMatch = isThis ? shadow.getThisType() : shadow.getTargetType(); + //if (typeToMatch == ResolvedTypeX.MISSING) return FuzzyBoolean.NO; + + return type.matches(typeToMatch.resolve(shadow.getIWorld()), TypePattern.DYNAMIC); + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.THIS_OR_TARGET); + s.writeBoolean(isThis); + type.write(s); + writeLocation(s); + } + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + boolean isThis = s.readBoolean(); + TypePattern type = TypePattern.read(s, context); + ThisOrTargetPointcut ret = new ThisOrTargetPointcut(isThis, type); + ret.readLocation(context, s); + return ret; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + type = type.resolveBindings(scope, bindings, true); + // ??? handle non-formal + } + + public void postRead(ResolvedTypeX enclosingType) { + type.postRead(enclosingType); + } + + public boolean equals(Object other) { + if (!(other instanceof ThisOrTargetPointcut)) return false; + ThisOrTargetPointcut o = (ThisOrTargetPointcut)other; + return o.isThis == this.isThis && o.type.equals(this.type); + } + public int hashCode() { + int result = 17; + result = 37*result + (isThis ? 0 : 1); + result = 37*result + type.hashCode(); + return result; + } + public String toString() { + return (isThis ? "this(" : "target(") + type + ")"; + } + + public Test findResidue(Shadow shadow, ExposedState state) { + if (!couldMatch(shadow)) return Literal.FALSE; + + if (type == TypePattern.ANY) return Literal.TRUE; + + Var var = isThis ? shadow.getThisVar() : shadow.getTargetVar(); + return exposeStateForVar(var, type, state, shadow.getIWorld()); + } + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + return new ThisOrTargetPointcut(isThis, type.remapAdviceFormals(bindings)); + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java b/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java new file mode 100644 index 000000000..591787911 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/ThrowsPattern.java @@ -0,0 +1,110 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.*; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.TypeX; + + +public class ThrowsPattern extends PatternNode { + private TypePatternList required; + private TypePatternList forbidden; + + public static final ThrowsPattern ANY = + new ThrowsPattern(TypePatternList.EMPTY, TypePatternList.EMPTY); + + public ThrowsPattern(TypePatternList required, TypePatternList forbidden) { + this.required = required; + this.forbidden = forbidden; + } + + public String toString() { + if (this == ANY) return ""; + + + String ret = "throws " + required.toString(); + if (forbidden.size() > 0) { + ret = ret + " !(" + forbidden.toString() + ")"; + } + return ret; + } + + public boolean equals(Object other) { + if (!(other instanceof ThrowsPattern)) return false; + ThrowsPattern o = (ThrowsPattern)other; + return o.required.equals(this.required) && + o.forbidden.equals(this.forbidden); + } + public int hashCode() { + int result = 17; + result = 37*result + required.hashCode(); + result = 37*result + forbidden.hashCode(); + return result; + } + + public ThrowsPattern resolveBindings(IScope scope, Bindings bindings) { + if (this == ANY) return this; + required = required.resolveBindings(scope, bindings, false); + forbidden = forbidden.resolveBindings(scope, bindings, false); + return this; + } + + public boolean matches(TypeX[] tys, World world) { + if (this == ANY) return true; + + //System.out.println("matching: " + this + " with " + Arrays.asList(tys)); + + ResolvedTypeX[] types = world.resolve(tys); + int len = types.length; + for (int j=0, lenj = required.size(); j < lenj; j++) { + if (! matchesAny(required.get(j), types)) { + return false; + } + } + for (int j=0, lenj = forbidden.size(); j < lenj; j++) { + if (matchesAny(forbidden.get(j), types)) { + return false; + } + } + return true; + } + + private boolean matchesAny( + TypePattern typePattern, + ResolvedTypeX[] types) + { + for (int i = types.length - 1; i >= 0; i--) { + if (typePattern.matchesExactly(types[i])) return true; + } + return false; + } + + public static ThrowsPattern read(DataInputStream s, ISourceContext context) throws IOException { + TypePatternList required = TypePatternList.read(s, context); + TypePatternList forbidden = TypePatternList.read(s, context); + if (required.size() == 0 && forbidden.size() == 0) return ANY; + ThrowsPattern ret = new ThrowsPattern(required, forbidden); + //XXXret.readLocation(context, s); + return ret; + } + + public void write(DataOutputStream s) throws IOException { + required.write(s); + forbidden.write(s); + //XXXwriteLocation(s); + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/TypePattern.java b/weaver/src/org/aspectj/weaver/patterns/TypePattern.java new file mode 100644 index 000000000..341138756 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/TypePattern.java @@ -0,0 +1,263 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.*; + +import org.aspectj.weaver.*; +import org.aspectj.bridge.*; +import org.aspectj.bridge.IMessageHandler; +import org.aspectj.util.*; +/** + * On creation, type pattern only contains WildTypePattern nodes, not BindingType or ExactType. + * + * <p>Then we call resolveBindings() during compilation + * During concretization of enclosing pointcuts, we call remapAdviceFormals + * + * @author Erik Hilsdale + * @author Jim Hugunin + */ +public abstract class TypePattern extends PatternNode { + public static class MatchKind { + private String name; + public MatchKind(String name) { this.name = name; } + public String toString() { return name; } + } + + public static final MatchKind STATIC = new MatchKind("STATIC"); + public static final MatchKind DYNAMIC = new MatchKind("DYNAMIC"); + + public static final TypePattern ELLIPSIS = new EllipsisTypePattern(); + public static final TypePattern ANY = new AnyTypePattern(); + + + protected boolean includeSubtypes; + + protected TypePattern(boolean includeSubtypes) { + this.includeSubtypes = includeSubtypes; + } + + //XXX non-final for Not, && and || + public boolean matchesStatically(ResolvedTypeX type) { + if (includeSubtypes) { + return matchesSubtypes(type); + } else { + return matchesExactly(type); + } + } + public abstract FuzzyBoolean matchesInstanceof(ResolvedTypeX type); + + + public final FuzzyBoolean matches(ResolvedTypeX type, MatchKind kind) { + if (kind == STATIC) { + return FuzzyBoolean.fromBoolean(matchesStatically(type)); + } else if (kind == DYNAMIC) { + //System.err.println("matching: " + this + " with " + type); + FuzzyBoolean ret = matchesInstanceof(type); + //System.err.println(" got: " + ret); + return ret; + } else { + throw new IllegalArgumentException("kind must be DYNAMIC or STATIC"); + } + } + + + protected abstract boolean matchesExactly(ResolvedTypeX type); + protected boolean matchesSubtypes(ResolvedTypeX type) { + //System.out.println("matching: " + this + " to " + type); + if (matchesExactly(type)) { + //System.out.println(" true"); + return true; + } + + FuzzyBoolean ret = FuzzyBoolean.NO; // ??? -eh + for (Iterator i = type.getDirectSupertypes(); i.hasNext(); ) { + ResolvedTypeX superType = (ResolvedTypeX)i.next(); + if (matchesSubtypes(superType)) return true; + } + return false; + } + + public TypeX resolveExactType(IScope scope, Bindings bindings) { + TypePattern p = resolveBindings(scope, bindings, false); + if (!p.assertExactType(scope.getMessageHandler())) return ResolvedTypeX.MISSING; + + return ((ExactTypePattern)p).getType(); + } + + public TypeX getExactType() { + if (this instanceof ExactTypePattern) return ((ExactTypePattern)this).getType(); + else return ResolvedTypeX.MISSING; + } + + public boolean assertExactType(IMessageHandler m) { + if (this instanceof ExactTypePattern) return true; + + //XXX should try harder to avoid multiple errors for one problem + m.handleMessage(MessageUtil.error("exact type pattern required", getSourceLocation())); + return false; + } + + /** + * This can modify in place, or return a new TypePattern if the type changes. + */ + public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) { + return this; + } + + public void postRead(ResolvedTypeX enclosingType) { + } + + public boolean isStar() { + return false; + } + + + + /** + * This is called during concretization of pointcuts, it is used by BindingTypePattern + * to return a new BindingTypePattern with a formal index appropiate for the advice, + * rather than for the lexical declaration, i.e. this handles transforamtions through + * named pointcuts. + * <pre> + * pointcut foo(String name): args(name); + * --> This makes a BindingTypePattern(0) pointing to the 0th formal + * + * before(Foo f, String n): this(f) && foo(n) { ... } + * --> when resolveReferences is called on the args from the above, it + * will return a BindingTypePattern(1) + * + * before(Foo f): this(f) && foo(*) { ... } + * --> when resolveReferences is called on the args from the above, it + * will return an ExactTypePattern(String) + * </pre> + */ + public TypePattern remapAdviceFormals(IntMap bindings) { + return this; + } + + + public static final byte WILD = 1; + public static final byte EXACT = 2; + public static final byte BINDING = 3; + public static final byte ELLIPSIS_KEY = 4; + public static final byte ANY_KEY = 5; + public static final byte NOT = 6; + public static final byte OR = 7; + public static final byte AND = 8; + + public static TypePattern read(DataInputStream s, ISourceContext context) throws IOException { + byte key = s.readByte(); + switch(key) { + case WILD: return WildTypePattern.read(s, context); + case EXACT: return ExactTypePattern.read(s, context); + case BINDING: return BindingTypePattern.read(s, context); + case ELLIPSIS_KEY: return ELLIPSIS; + case ANY_KEY: return ANY; + case NOT: return NotTypePattern.read(s, context); + case OR: return OrTypePattern.read(s, context); + case AND: return AndTypePattern.read(s, context); + } + throw new BCException("unknown TypePattern kind: " + key); + } +} + +class EllipsisTypePattern extends TypePattern { + + /** + * Constructor for EllipsisTypePattern. + * @param includeSubtypes + */ + public EllipsisTypePattern() { + super(false); + } + + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType) + */ + protected boolean matchesExactly(ResolvedTypeX type) { + return false; + } + + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType) + */ + public FuzzyBoolean matchesInstanceof(ResolvedTypeX type) { + return FuzzyBoolean.NO; + } + + /** + * @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream) + */ + public void write(DataOutputStream s) throws IOException { + s.writeByte(ELLIPSIS_KEY); + } + + public String toString() { return ".."; } +} + +class AnyTypePattern extends TypePattern { + + /** + * Constructor for EllipsisTypePattern. + * @param includeSubtypes + */ + public AnyTypePattern() { + super(false); + } + + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesExactly(IType) + */ + protected boolean matchesExactly(ResolvedTypeX type) { + return true; + } + + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesInstanceof(IType) + */ + public FuzzyBoolean matchesInstanceof(ResolvedTypeX type) { + return FuzzyBoolean.YES; + } + + /** + * @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream) + */ + public void write(DataOutputStream s) throws IOException { + s.writeByte(ANY_KEY); + } + + /** + * @see org.aspectj.weaver.patterns.TypePattern#matches(IType, MatchKind) + */ +// public FuzzyBoolean matches(IType type, MatchKind kind) { +// return FuzzyBoolean.YES; +// } + + /** + * @see org.aspectj.weaver.patterns.TypePattern#matchesSubtypes(IType) + */ + protected boolean matchesSubtypes(ResolvedTypeX type) { + return true; + } + + + public boolean isStar() { + return true; + } + + public String toString() { return "*"; } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/TypePatternList.java b/weaver/src/org/aspectj/weaver/patterns/TypePatternList.java new file mode 100644 index 000000000..1f7abffc0 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/TypePatternList.java @@ -0,0 +1,234 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.*; + +import org.aspectj.weaver.*; +import org.aspectj.util.*; + +public class TypePatternList extends PatternNode { + private TypePattern[] typePatterns; + int ellipsisCount = 0; + + public static final TypePatternList EMPTY = + new TypePatternList(new TypePattern[] {}); + + public static final TypePatternList ANY = + new TypePatternList(new TypePattern[] {TypePattern.ELLIPSIS}); + + public TypePatternList() { + typePatterns = new TypePattern[0]; + ellipsisCount = 0; + } + + public TypePatternList(TypePattern[] arguments) { + this.typePatterns = arguments; + for (int i=0; i<arguments.length; i++) { + if (arguments[i] == TypePattern.ELLIPSIS) ellipsisCount++; + } + } + + public TypePatternList(List l) { + this((TypePattern[]) l.toArray(new TypePattern[l.size()])); + } + + public int size() { return typePatterns.length; } + + public TypePattern get(int index) { + return typePatterns[index]; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("("); + for (int i=0, len=typePatterns.length; i < len; i++) { + TypePattern type = typePatterns[i]; + if (i > 0) buf.append(", "); + if (type == TypePattern.ELLIPSIS) { + buf.append(".."); + } else { + buf.append(type.toString()); + } + } + buf.append(")"); + return buf.toString(); + } + + //XXX shares much code with WildTypePattern and with NamePattern + /** + * When called with TypePattern.STATIC this will always return either + * FuzzyBoolean.YES or FuzzyBoolean.NO. + * + * When called with TypePattern.DYNAMIC this could return MAYBE if + * at runtime it would be possible for arguments of the given static + * types to dynamically match this, but it is not known for certain. + * + * This method will never return FuzzyBoolean.NEVER + */ + public FuzzyBoolean matches(ResolvedTypeX[] types, TypePattern.MatchKind kind) { + int nameLength = types.length; + int patternLength = typePatterns.length; + + int nameIndex = 0; + int patternIndex = 0; + + if (ellipsisCount == 0) { + if (nameLength != patternLength) return FuzzyBoolean.NO; + FuzzyBoolean finalReturn = FuzzyBoolean.YES; + while (patternIndex < patternLength) { + FuzzyBoolean ret = typePatterns[patternIndex++].matches(types[nameIndex++], kind); + if (ret == FuzzyBoolean.NO) return ret; + if (ret == FuzzyBoolean.MAYBE) finalReturn = ret; + } + return finalReturn; + } else if (ellipsisCount == 1) { + if (nameLength < patternLength-1) return FuzzyBoolean.NO; + FuzzyBoolean finalReturn = FuzzyBoolean.YES; + while (patternIndex < patternLength) { + TypePattern p = typePatterns[patternIndex++]; + if (p == TypePattern.ELLIPSIS) { + nameIndex = nameLength - (patternLength-patternIndex); + } else { + FuzzyBoolean ret = p.matches(types[nameIndex++], kind); + if (ret == FuzzyBoolean.NO) return ret; + if (ret == FuzzyBoolean.MAYBE) finalReturn = ret; + } + } + return finalReturn; + } else { +// System.err.print("match(" + arguments + ", " + types + ") -> "); + FuzzyBoolean b = outOfStar(typePatterns, types, 0, 0, patternLength - ellipsisCount, nameLength, ellipsisCount, kind); +// System.err.println(b); + return b; + } + } + private static FuzzyBoolean outOfStar(final TypePattern[] pattern, final ResolvedTypeX[] target, + int pi, int ti, + int pLeft, int tLeft, + final int starsLeft, TypePattern.MatchKind kind) { + if (pLeft > tLeft) return FuzzyBoolean.NO; + FuzzyBoolean finalReturn = FuzzyBoolean.YES; + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length) + if (tLeft == 0) return finalReturn; + if (pLeft == 0) { + if (starsLeft > 0) { + return finalReturn; + } else { + return FuzzyBoolean.NO; + } + } + if (pattern[pi] == TypePattern.ELLIPSIS) { + return inStar(pattern, target, pi+1, ti, pLeft, tLeft, starsLeft-1, kind); + } + FuzzyBoolean ret = pattern[pi].matches(target[ti], kind); + if (ret == FuzzyBoolean.NO) return ret; + if (ret == FuzzyBoolean.MAYBE) finalReturn = ret; + pi++; ti++; pLeft--; tLeft--; + } + } + private static FuzzyBoolean inStar(final TypePattern[] pattern, final ResolvedTypeX[] target, + int pi, int ti, + final int pLeft, int tLeft, + int starsLeft, TypePattern.MatchKind kind) { + // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern + TypePattern patternChar = pattern[pi]; + while (patternChar == TypePattern.ELLIPSIS) { + starsLeft--; + patternChar = pattern[++pi]; + } + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length) + if (pLeft > tLeft) return FuzzyBoolean.NO; + FuzzyBoolean ff = patternChar.matches(target[ti], kind); + if (ff.maybeTrue()) { + FuzzyBoolean xx = outOfStar(pattern, target, pi+1, ti+1, pLeft-1, tLeft-1, starsLeft, kind); + if (xx.maybeTrue()) return ff.and(xx); + } + ti++; tLeft--; + } + } + + public TypePatternList resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) { + for (int i=0; i<typePatterns.length; i++) { + TypePattern p = typePatterns[i]; + if (p != null) { + typePatterns[i] = typePatterns[i].resolveBindings(scope, bindings, allowBinding); + } + } + return this; + } + + public TypePatternList resolveReferences(IntMap bindings) { + int len = typePatterns.length; + TypePattern[] ret = new TypePattern[len]; + for (int i=0; i < len; i++) { + ret[i] = typePatterns[i].remapAdviceFormals(bindings); + } + return new TypePatternList(ret); + } + + public void postRead(ResolvedTypeX enclosingType) { + for (int i=0; i<typePatterns.length; i++) { + TypePattern p = typePatterns[i]; + p.postRead(enclosingType); + } + } + + + public boolean equals(Object other) { + if (!(other instanceof TypePatternList)) return false; + TypePatternList o = (TypePatternList)other; + int len = o.typePatterns.length; + if (len != this.typePatterns.length) return false; + for (int i=0; i<len; i++) { + if (!this.typePatterns[i].equals(o.typePatterns[i])) return false; + } + return true; + } + public int hashCode() { + int result = 41; + for (int i = 0, len = typePatterns.length; i < len; i++) { + result = 37*result + typePatterns[i].hashCode(); + } + return result; + } + + + public static TypePatternList read(DataInputStream s, ISourceContext context) throws IOException { + short len = s.readShort(); + TypePattern[] arguments = new TypePattern[len]; + for (int i=0; i<len; i++) { + arguments[i] = TypePattern.read(s, context); + } + TypePatternList ret = new TypePatternList(arguments); + ret.readLocation(context, s); + return ret; + } + + + public void write(DataOutputStream s) throws IOException { + s.writeShort(typePatterns.length); + for (int i=0; i<typePatterns.length; i++) { + typePatterns[i].write(s); + } + writeLocation(s); + } + public TypePattern[] getTypePatterns() { + return typePatterns; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/TypePatternQuestions.java b/weaver/src/org/aspectj/weaver/patterns/TypePatternQuestions.java new file mode 100644 index 000000000..d9ebe0983 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/TypePatternQuestions.java @@ -0,0 +1,109 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.util.*; +import java.util.HashMap; +import java.util.Map; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ResolvedTypeX; +import org.aspectj.weaver.TypeX; +import org.aspectj.util.FuzzyBoolean; + + +public class TypePatternQuestions { + private Map questionsAndAnswers = new HashMap(); + + public FuzzyBoolean askQuestion(TypePattern pattern, ResolvedTypeX type, + TypePattern.MatchKind kind) + { + Question question = new Question(pattern, type, kind); + //??? should we use this table to do caching or is that a pessimization + //??? if we do that optimization we can also do error checking that the result + //??? doesn't change + FuzzyBoolean answer = question.ask(); + questionsAndAnswers.put(question, answer); + return answer; + } + + public Question anyChanges() { + for (Iterator i = questionsAndAnswers.entrySet().iterator(); i.hasNext(); ) { + Map.Entry entry = (Map.Entry)i.next(); + Question question = (Question)entry.getKey(); + FuzzyBoolean expectedAnswer = (FuzzyBoolean)entry.getValue(); + + FuzzyBoolean currentAnswer = question.ask(); + //System.out.println(question + ":" + currentAnswer); + if (currentAnswer != expectedAnswer) { + return question; + } + } + + return null; + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append("TypePatternQuestions{"); + for (Iterator i = questionsAndAnswers.entrySet().iterator(); i.hasNext(); ) { + Map.Entry entry = (Map.Entry)i.next(); + Question question = (Question)entry.getKey(); + FuzzyBoolean expectedAnswer = (FuzzyBoolean)entry.getValue(); + buf.append(question); + buf.append(":"); + buf.append(expectedAnswer); + buf.append(", "); + } + buf.append("}"); + return buf.toString(); + } + + + public class Question { + TypePattern pattern; + ResolvedTypeX type; + TypePattern.MatchKind kind; + + public Question(TypePattern pattern, ResolvedTypeX type, + TypePattern.MatchKind kind) { + super(); + this.pattern = pattern; + this.type = type; + this.kind = kind; + } + + public FuzzyBoolean ask() { + return pattern.matches(type, kind); + } + + public boolean equals(Object other) { + if (!(other instanceof Question)) return false; + Question o = (Question)other; + return o.pattern.equals(pattern) && o.type.equals(type) && o.kind == kind; + } + + public int hashCode() { + int result = 17; + result = 37*result + kind.hashCode(); + result = 37*result + pattern.hashCode(); + result = 37*result + type.hashCode(); + return result; + } + + public String toString() { + return "?(" + pattern + ", " + type + ", " + kind + ")"; + } + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java b/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java new file mode 100644 index 000000000..1aed2f2ea --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/WildTypePattern.java @@ -0,0 +1,428 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.*; + +import org.aspectj.weaver.*; +import org.aspectj.bridge.*; +import org.aspectj.bridge.IMessage; +import org.aspectj.util.*; + +//XXX need to use dim in matching +public class WildTypePattern extends TypePattern { + NamePattern[] namePatterns; + int ellipsisCount; + String[] importedPrefixes; + String[] knownMatches; + int dim; + + WildTypePattern(NamePattern[] namePatterns, boolean includeSubtypes, int dim) { + super(includeSubtypes); + this.namePatterns = namePatterns; + this.ellipsisCount = ellipsisCount; + this.dim = dim; + ellipsisCount = 0; + for (int i=0; i<namePatterns.length; i++) { + if (namePatterns[i] == NamePattern.ELLIPSIS) ellipsisCount++; + } + setLocation(namePatterns[0].getSourceContext(), namePatterns[0].getStart(), namePatterns[namePatterns.length-1].getEnd()); + } + + public WildTypePattern(List names, boolean includeSubtypes, int dim) { + this((NamePattern[])names.toArray(new NamePattern[names.size()]), includeSubtypes, dim); + + } + + public WildTypePattern(List names, boolean includeSubtypes, int dim, int endPos) { + this(names, includeSubtypes, dim); + this.end = endPos; + } + + //XXX inefficient implementation + public static char[][] splitNames(String s) { + List ret = new ArrayList(); + int startIndex = 0; + while (true) { + int breakIndex = s.indexOf('.', startIndex); // what about / + if (breakIndex == -1) breakIndex = s.indexOf('$', startIndex); // we treat $ like . here + if (breakIndex == -1) break; + char[] name = s.substring(startIndex, breakIndex).toCharArray(); + ret.add(name); + startIndex = breakIndex+1; + } + ret.add(s.substring(startIndex).toCharArray()); + return (char[][])ret.toArray(new char[ret.size()][]); + } + + + /** + * @see org.aspectj.weaver.TypePattern#matchesExactly(IType) + */ + protected boolean matchesExactly(ResolvedTypeX type) { + String targetTypeName = type.getName(); + + //XXX hack + if (knownMatches == null) { + return innerMatchesExactly(targetTypeName); + } + + // if our pattern is length 1, then known matches are exact matches + // if it's longer than that, then known matches are prefixes of a sort + if (namePatterns.length == 1) { + for (int i=0, len=knownMatches.length; i < len; i++) { + if (knownMatches[i].equals(targetTypeName)) return true; + } + } else { + for (int i=0, len=knownMatches.length; i < len; i++) { + String knownPrefix = knownMatches[i] + "$"; + if (targetTypeName.startsWith(knownPrefix)) { + int pos = lastIndexOfDotOrDollar(knownMatches[i]); + if (innerMatchesExactly(targetTypeName.substring(pos+1))) { + return true; + } + } + } + } + + + // if any prefixes match, strip the prefix and check that the rest matches + // assumes that prefixes have a dot at the end + for (int i=0, len=importedPrefixes.length; i < len; i++) { + String prefix = importedPrefixes[i]; + if (targetTypeName.startsWith(prefix)) { + if (innerMatchesExactly(targetTypeName.substring(prefix.length()))) { + return true; + } + } + } + + return innerMatchesExactly(targetTypeName); + } + + private int lastIndexOfDotOrDollar(String string) { + int dot = string.lastIndexOf('.'); + int dollar = string.lastIndexOf('$'); + return Math.max(dot, dollar); + } + + + private boolean innerMatchesExactly(String targetTypeName) { + //??? doing this everytime is not very efficient + char[][] names = splitNames(targetTypeName); + + + + return innerMatchesExactly(names); + } + + private boolean innerMatchesExactly(char[][] names) { + + int namesLength = names.length; + int patternsLength = namePatterns.length; + + int namesIndex = 0; + int patternsIndex = 0; + + if (ellipsisCount == 0) { + if (namesLength != patternsLength) return false; + while (patternsIndex < patternsLength) { + if (!namePatterns[patternsIndex++].matches(names[namesIndex++])) { + return false; + } + } + return true; + } else if (ellipsisCount == 1) { + if (namesLength < patternsLength-1) return false; + while (patternsIndex < patternsLength) { + NamePattern p = namePatterns[patternsIndex++]; + if (p == NamePattern.ELLIPSIS) { + namesIndex = namesLength - (patternsLength-patternsIndex); + } else { + if (!p.matches(names[namesIndex++])) { + return false; + } + } + } + return true; + } else { + // System.err.print("match(\"" + Arrays.asList(namePatterns) + "\", \"" + Arrays.asList(names) + "\") -> "); + boolean b = outOfStar(namePatterns, names, 0, 0, patternsLength - ellipsisCount, namesLength, ellipsisCount); + // System.err.println(b); + return b; + } + } + private static boolean outOfStar(final NamePattern[] pattern, final char[][] target, + int pi, int ti, + int pLeft, int tLeft, + final int starsLeft) { + if (pLeft > tLeft) return false; + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length && pi < pattern.length) + if (tLeft == 0) return true; + if (pLeft == 0) { + return (starsLeft > 0); + } + if (pattern[pi] == NamePattern.ELLIPSIS) { + return inStar(pattern, target, pi+1, ti, pLeft, tLeft, starsLeft-1); + } + if (! pattern[pi].matches(target[ti])) { + return false; + } + pi++; ti++; pLeft--; tLeft--; + } + } + private static boolean inStar(final NamePattern[] pattern, final char[][] target, + int pi, int ti, + final int pLeft, int tLeft, + int starsLeft) { + // invariant: pLeft > 0, so we know we'll run out of stars and find a real char in pattern + // of course, we probably can't parse multiple ..'s in a row, but this keeps the algorithm + // exactly parallel with that in NamePattern + NamePattern patternChar = pattern[pi]; + while (patternChar == NamePattern.ELLIPSIS) { + starsLeft--; + patternChar = pattern[++pi]; + } + while (true) { + // invariant: if (tLeft > 0) then (ti < target.length) + if (pLeft > tLeft) return false; + if (patternChar.matches(target[ti])) { + if (outOfStar(pattern, target, pi+1, ti+1, pLeft-1, tLeft-1, starsLeft)) return true; + } + ti++; tLeft--; + } + } + + /** + * @see org.aspectj.weaver.TypePattern#matchesInstanceof(IType) + */ + public FuzzyBoolean matchesInstanceof(ResolvedTypeX type) { + //XXX hack to let unmatched types just silently remain so + if (maybeGetSimpleName() != null) return FuzzyBoolean.NO; + + type.getWorld().getMessageHandler().handleMessage( + new Message("can't do instanceof matching on patterns with wildcards", + IMessage.ERROR, null, getSourceLocation())); + return FuzzyBoolean.NO; + } + + public NamePattern extractName() { + //System.err.println("extract from : " + Arrays.asList(namePatterns)); + int len = namePatterns.length; + NamePattern ret = namePatterns[len-1]; + NamePattern[] newNames = new NamePattern[len-1]; + System.arraycopy(namePatterns, 0, newNames, 0, len-1); + namePatterns = newNames; + //System.err.println(" left : " + Arrays.asList(namePatterns)); + return ret; + } + + /** + * Method maybeExtractName. + * @param string + * @return boolean + */ + public boolean maybeExtractName(String string) { + int len = namePatterns.length; + NamePattern ret = namePatterns[len-1]; + String simple = ret.maybeGetSimpleName(); + if (simple != null && simple.equals(string)) { + extractName(); + return true; + } + return false; + } + + /** + * If this type pattern has no '.' or '*' in it, then + * return a simple string + * + * otherwise, this will return null; + */ + public String maybeGetSimpleName() { + if (namePatterns.length == 1) { + return namePatterns[0].maybeGetSimpleName(); + } + return null; + } + + /** + * If this type pattern has no '*' or '..' in it + */ + public String maybeGetCleanName() { + if (namePatterns.length == 0) { + throw new RuntimeException("bad name: " + namePatterns); + } + //System.out.println("get clean: " + this); + StringBuffer buf = new StringBuffer(); + for (int i=0, len=namePatterns.length; i < len; i++) { + NamePattern p = namePatterns[i]; + String simpleName = p.maybeGetSimpleName(); + if (simpleName == null) return null; + if (i > 0) buf.append("."); + buf.append(simpleName); + } + //System.out.println(buf); + return buf.toString(); + } + + + /** + * Need to determine if I'm really a pattern or a reference to a formal + * + * We may wish to further optimize the case of pattern vs. non-pattern + * + * We will be replaced by what we return + */ + public TypePattern resolveBindings(IScope scope, Bindings bindings, boolean allowBinding) { + if (isStar()) { + return TypePattern.ANY; //??? loses source location + } + + String simpleName = maybeGetSimpleName(); + if (simpleName != null) { + FormalBinding formalBinding = scope.lookupFormal(simpleName); + if (formalBinding != null) { + if (!allowBinding || bindings == null) { + scope.message(IMessage.ERROR, this, "negation doesn't allow binding"); + return this; + } + BindingTypePattern binding = new BindingTypePattern(formalBinding); + binding.copyLocationFrom(this); + bindings.register(binding, scope); + + return binding; + } + } + + String cleanName = maybeGetCleanName(); + if (cleanName != null) { + TypeX type; + + //System.out.println("resolve: " + cleanName); + //??? this loop has too many inefficiencies to count + while ((type = scope.lookupType(cleanName, this)) == ResolvedTypeX.MISSING) { + int lastDot = cleanName.lastIndexOf('.'); + if (lastDot == -1) break; + cleanName = cleanName.substring(0, lastDot) + '$' + cleanName.substring(lastDot+1); + } + if (type == ResolvedTypeX.MISSING) { + if (scope.getWorld().getLint().invalidAbsoluteTypeName.isEnabled()) { + scope.getWorld().getLint().invalidAbsoluteTypeName.signal(cleanName, getSourceLocation()); + } + } else { + TypePattern ret = new ExactTypePattern(type, includeSubtypes); + ret.copyLocationFrom(this); + return ret; + } + } else { + //XXX need to implement behavior for Lint.invalidWildcardTypeName + } + + importedPrefixes = scope.getImportedPrefixes(); + knownMatches = preMatch(scope.getImportedNames()); + + return this; + } + + public boolean isStar() { + return namePatterns.length == 1 && namePatterns[0].isAny(); + } + + /** + * returns those possible matches which I match exactly the last element of + */ + private String[] preMatch(String[] possibleMatches) { + //if (namePatterns.length != 1) return CollectionUtil.NO_STRINGS; + + List ret = new ArrayList(); + for (int i=0, len=possibleMatches.length; i < len; i++) { + char[][] names = splitNames(possibleMatches[i]); //??? not most efficient + if (namePatterns[0].matches(names[names.length-1])) { + ret.add(possibleMatches[i]); + } + } + return (String[])ret.toArray(new String[ret.size()]); + } + + +// public void postRead(ResolvedTypeX enclosingType) { +// this.importedPrefixes = enclosingType.getImportedPrefixes(); +// this.knownNames = prematch(enclosingType.getImportedNames()); +// } + + + public String toString() { + StringBuffer buf = new StringBuffer(); + for (int i=0, len=namePatterns.length; i < len; i++) { + NamePattern name = namePatterns[i]; + if (name == null) { + buf.append("."); + } else { + if (i > 0) buf.append("."); + buf.append(name.toString()); + } + } + return buf.toString(); + } + + public boolean equals(Object other) { + if (!(other instanceof WildTypePattern)) return false; + WildTypePattern o = (WildTypePattern)other; + int len = o.namePatterns.length; + if (len != this.namePatterns.length) return false; + for (int i=0; i < len; i++) { + if (!o.namePatterns[i].equals(this.namePatterns[i])) return false; + } + return true; + } + + public int hashCode() { + int result = 17; + for (int i = 0, len = namePatterns.length; i < len; i++) { + result = 37*result + namePatterns[i].hashCode(); + } + return result; + } + + /** + * @see org.aspectj.weaver.patterns.PatternNode#write(DataOutputStream) + */ + public void write(DataOutputStream s) throws IOException { + s.writeByte(TypePattern.WILD); + s.writeShort(namePatterns.length); + for (int i = 0; i < namePatterns.length; i++) { + namePatterns[i].write(s); + } + s.writeBoolean(includeSubtypes); + s.writeInt(dim); + writeLocation(s); + } + + public static TypePattern read(DataInputStream s, ISourceContext context) throws IOException { + int len = s.readShort(); + NamePattern[] namePatterns = new NamePattern[len]; + for (int i=0; i < len; i++) { + namePatterns[i] = NamePattern.read(s); + } + boolean includeSubtypes = s.readBoolean(); + int dim = s.readInt(); + TypePattern ret = new WildTypePattern(namePatterns, includeSubtypes, dim); + ret.readLocation(context, s); + return ret; + } + +} diff --git a/weaver/src/org/aspectj/weaver/patterns/WithinPointcut.java b/weaver/src/org/aspectj/weaver/patterns/WithinPointcut.java new file mode 100644 index 000000000..2b931985b --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/WithinPointcut.java @@ -0,0 +1,83 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.util.*; + +public class WithinPointcut extends Pointcut { + TypePattern type; + + public WithinPointcut(TypePattern type) { + this.type = type; + } + + public FuzzyBoolean match(Shadow shadow) { + TypeX enclosingType = shadow.getEnclosingType(); + while (enclosingType != null) { + if (type.matchesStatically(shadow.getIWorld().resolve(enclosingType))) { + return FuzzyBoolean.YES; + } + enclosingType = enclosingType.getDeclaringType(); + } + return FuzzyBoolean.NO; + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.WITHIN); + type.write(s); + writeLocation(s); + } + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + TypePattern type = TypePattern.read(s, context); + WithinPointcut ret = new WithinPointcut(type); + ret.readLocation(context, s); + return ret; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + type = type.resolveBindings(scope, bindings, false); + } + + public void postRead(ResolvedTypeX enclosingType) { + type.postRead(enclosingType); + } + + public boolean equals(Object other) { + if (!(other instanceof WithinPointcut)) return false; + WithinPointcut o = (WithinPointcut)other; + return o.type.equals(this.type); + } + public int hashCode() { + int result = 43; + result = 37*result + type.hashCode(); + return result; + } + + public String toString() { + return "within(" + type + ")"; + } + + public Test findResidue(Shadow shadow, ExposedState state) { + return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE; + } + + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + return this; //??? no pointers out of here so we're okay + } +} diff --git a/weaver/src/org/aspectj/weaver/patterns/WithincodePointcut.java b/weaver/src/org/aspectj/weaver/patterns/WithincodePointcut.java new file mode 100644 index 000000000..328f31fb4 --- /dev/null +++ b/weaver/src/org/aspectj/weaver/patterns/WithincodePointcut.java @@ -0,0 +1,79 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ast.*; +import org.aspectj.util.*; + +public class WithincodePointcut extends Pointcut { + SignaturePattern signature; + + public WithincodePointcut(SignaturePattern signature) { + this.signature = signature; + } + + public FuzzyBoolean match(Shadow shadow) { + //This will not match code in local or anonymous classes as if + //they were withincode of the outer signature + return FuzzyBoolean.fromBoolean( + signature.matches(shadow.getEnclosingCodeSignature(), shadow.getIWorld())); + } + + public void write(DataOutputStream s) throws IOException { + s.writeByte(Pointcut.WITHINCODE); + signature.write(s); + writeLocation(s); + } + + public static Pointcut read(DataInputStream s, ISourceContext context) throws IOException { + WithincodePointcut ret = new WithincodePointcut(SignaturePattern.read(s, context)); + ret.readLocation(context, s); + return ret; + } + + public void resolveBindings(IScope scope, Bindings bindings) { + signature = signature.resolveBindings(scope, bindings); + } + + public void postRead(ResolvedTypeX enclosingType) { + signature.postRead(enclosingType); + } + + public boolean equals(Object other) { + if (!(other instanceof WithincodePointcut)) return false; + WithincodePointcut o = (WithincodePointcut)other; + return o.signature.equals(this.signature); + } + public int hashCode() { + int result = 43; + result = 37*result + signature.hashCode(); + return result; + } + + public String toString() { + return "withincode(" + signature + ")"; + } + + public Test findResidue(Shadow shadow, ExposedState state) { + return match(shadow).alwaysTrue() ? Literal.TRUE : Literal.FALSE; + } + + + public Pointcut concretize1(ResolvedTypeX inAspect, IntMap bindings) { + return this; //??? no pointers out of here so we're okay + } +} diff --git a/weaver/testdata/AddNotResidueDynamicHelloWorld.txt b/weaver/testdata/AddNotResidueDynamicHelloWorld.txt new file mode 100644 index 000000000..48a5bfd77 --- /dev/null +++ b/weaver/testdata/AddNotResidueDynamicHelloWorld.txt @@ -0,0 +1,82 @@ +public class DynamicHelloWorld extends java.lang.Object implements java.io.Serializable: + public void <init>(): + ALOAD_0 // DynamicHelloWorld this (line 8) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void DynamicHelloWorld.<init>()) + | RETURN + constructor-execution(void DynamicHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + | catch java.lang.UnsupportedOperationException -> E0 + | | NEW DynamicHelloWorld (line 12) + | | DUP + | | constructor-call(void DynamicHelloWorld.<init>()) + | | | INVOKESPECIAL DynamicHelloWorld.<init> ()V + | | constructor-call(void DynamicHelloWorld.<init>()) + | | LDC "hello" + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | | GETSTATIC java.util.Collections.EMPTY_LIST Ljava/util/List; + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | | INVOKEVIRTUAL DynamicHelloWorld.doit (Ljava/lang/String;Ljava/util/List;)Ljava/lang/String; + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | POP + | | GOTO L0 + | catch java.lang.UnsupportedOperationException -> E0 + | E0: ASTORE_1 (line 13) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 14) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | LDC "expected and caught: " + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ALOAD_1 // java.lang.UnsupportedOperationException t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 15) + | L0: NEW java.lang.RuntimeException (line 17) + | DUP + | LDC "should have caught exception" + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.RuntimeException.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | ATHROW + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + String doit(String, java.util.List): + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | ALOAD_2 // java.util.List l (line 21) + | ALOAD_1 // java.lang.String arg0 + | ASTORE_3 + | ASTORE 4 + | method-call(boolean java.util.List.add(java.lang.Object)) + | | ALOAD 4 + | | INSTANCEOF java.util.ArrayList + | | IFNE L0 + | | INVOKESTATIC Aspect.ajc_before_0 ()V + | | L0: ALOAD 4 + | | ALOAD_3 + | | INVOKEINTERFACE java.util.List.add (Ljava/lang/Object;)Z + | method-call(boolean java.util.List.add(java.lang.Object)) + | POP + | ALOAD_2 // java.util.List l (line 22) + | method-call(java.lang.String java.lang.Object.toString()) + | | INVOKEVIRTUAL java.lang.Object.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.Object.toString()) + | ARETURN + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + end String doit(String, java.util.List) +end public class DynamicHelloWorld diff --git a/weaver/testdata/AddResidueDynamicHelloWorld.txt b/weaver/testdata/AddResidueDynamicHelloWorld.txt new file mode 100644 index 000000000..16f438647 --- /dev/null +++ b/weaver/testdata/AddResidueDynamicHelloWorld.txt @@ -0,0 +1,82 @@ +public class DynamicHelloWorld extends java.lang.Object implements java.io.Serializable: + public void <init>(): + ALOAD_0 // DynamicHelloWorld this (line 8) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void DynamicHelloWorld.<init>()) + | RETURN + constructor-execution(void DynamicHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + | catch java.lang.UnsupportedOperationException -> E0 + | | NEW DynamicHelloWorld (line 12) + | | DUP + | | constructor-call(void DynamicHelloWorld.<init>()) + | | | INVOKESPECIAL DynamicHelloWorld.<init> ()V + | | constructor-call(void DynamicHelloWorld.<init>()) + | | LDC "hello" + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | | GETSTATIC java.util.Collections.EMPTY_LIST Ljava/util/List; + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | | INVOKEVIRTUAL DynamicHelloWorld.doit (Ljava/lang/String;Ljava/util/List;)Ljava/lang/String; + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | POP + | | GOTO L0 + | catch java.lang.UnsupportedOperationException -> E0 + | E0: ASTORE_1 (line 13) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 14) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | LDC "expected and caught: " + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ALOAD_1 // java.lang.UnsupportedOperationException t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 15) + | L0: NEW java.lang.RuntimeException (line 17) + | DUP + | LDC "should have caught exception" + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.RuntimeException.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | ATHROW + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + String doit(String, java.util.List): + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | ALOAD_2 // java.util.List l (line 21) + | ALOAD_1 // java.lang.String arg0 + | ASTORE_3 + | ASTORE 4 + | method-call(boolean java.util.List.add(java.lang.Object)) + | | ALOAD 4 + | | INSTANCEOF java.util.ArrayList + | | IFEQ L0 + | | INVOKESTATIC Aspect.ajc_before_0 ()V + | | L0: ALOAD 4 + | | ALOAD_3 + | | INVOKEINTERFACE java.util.List.add (Ljava/lang/Object;)Z + | method-call(boolean java.util.List.add(java.lang.Object)) + | POP + | ALOAD_2 // java.util.List l (line 22) + | method-call(java.lang.String java.lang.Object.toString()) + | | INVOKEVIRTUAL java.lang.Object.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.Object.toString()) + | ARETURN + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + end String doit(String, java.util.List) +end public class DynamicHelloWorld diff --git a/weaver/testdata/AddStateResidueDynamicHelloWorld.txt b/weaver/testdata/AddStateResidueDynamicHelloWorld.txt new file mode 100644 index 000000000..f0c96df34 --- /dev/null +++ b/weaver/testdata/AddStateResidueDynamicHelloWorld.txt @@ -0,0 +1,84 @@ +public class DynamicHelloWorld extends java.lang.Object implements java.io.Serializable: + public void <init>(): + ALOAD_0 // DynamicHelloWorld this (line 8) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void DynamicHelloWorld.<init>()) + | RETURN + constructor-execution(void DynamicHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + | catch java.lang.UnsupportedOperationException -> E0 + | | NEW DynamicHelloWorld (line 12) + | | DUP + | | constructor-call(void DynamicHelloWorld.<init>()) + | | | INVOKESPECIAL DynamicHelloWorld.<init> ()V + | | constructor-call(void DynamicHelloWorld.<init>()) + | | LDC "hello" + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | | GETSTATIC java.util.Collections.EMPTY_LIST Ljava/util/List; + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | | INVOKEVIRTUAL DynamicHelloWorld.doit (Ljava/lang/String;Ljava/util/List;)Ljava/lang/String; + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | POP + | | GOTO L0 + | catch java.lang.UnsupportedOperationException -> E0 + | E0: ASTORE_1 (line 13) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 14) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | LDC "expected and caught: " + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ALOAD_1 // java.lang.UnsupportedOperationException t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 15) + | L0: NEW java.lang.RuntimeException (line 17) + | DUP + | LDC "should have caught exception" + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.RuntimeException.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | ATHROW + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + String doit(String, java.util.List): + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | ALOAD_2 // java.util.List l (line 21) + | ALOAD_1 // java.lang.String arg0 + | ASTORE_3 + | ASTORE 4 + | method-call(boolean java.util.List.add(java.lang.Object)) + | | ALOAD 4 + | | INSTANCEOF java.util.ArrayList + | | IFEQ L0 + | | ALOAD 4 + | | CHECKCAST java.util.ArrayList + | | INVOKESTATIC Aspect.ajc_before_0 (Ljava/util/ArrayList;)V + | | L0: ALOAD 4 + | | ALOAD_3 + | | INVOKEINTERFACE java.util.List.add (Ljava/lang/Object;)Z + | method-call(boolean java.util.List.add(java.lang.Object)) + | POP + | ALOAD_2 // java.util.List l (line 22) + | method-call(java.lang.String java.lang.Object.toString()) + | | INVOKEVIRTUAL java.lang.Object.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.Object.toString()) + | ARETURN + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + end String doit(String, java.util.List) +end public class DynamicHelloWorld diff --git a/weaver/testdata/AfterFancyHelloWorld.txt b/weaver/testdata/AfterFancyHelloWorld.txt new file mode 100644 index 000000000..16b04e4b1 --- /dev/null +++ b/weaver/testdata/AfterFancyHelloWorld.txt @@ -0,0 +1,183 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | catch java.lang.Throwable -> E0 + | | GOTO L0 + | catch java.lang.Throwable -> E0 + | E0: ASTORE_1 + | INVOKESTATIC Aspect.ajc_after_constructor_execution ()V + | ALOAD_1 + | ATHROW + | L0: INVOKESTATIC Aspect.ajc_after_constructor_execution ()V + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | catch java.lang.Throwable -> E6 + | | field-get(java.io.PrintStream java.lang.System.out) + | | | catch java.lang.Throwable -> E3 + | | | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | | | catch java.lang.Throwable -> E3 + | | | GOTO L0 + | | | E3: ASTORE 5 + | | | INVOKESTATIC Aspect.ajc_after_field_get ()V + | | | ALOAD 5 + | | | ATHROW + | | | L0: NOP + | | | INVOKESTATIC Aspect.ajc_after_field_get ()V + | | | NOP + | | field-get(java.io.PrintStream java.lang.System.out) + | | ASTORE_1 + | | finally -> E5 + | | | catch java.lang.Exception -> E4 + | | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | | LDC "bye" + | | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | | catch java.lang.Throwable -> E2 + | | | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | | | catch java.lang.Throwable -> E2 + | | | | | GOTO L1 + | | | | | E2: ASTORE 6 + | | | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | | | ALOAD 6 + | | | | | ATHROW + | | | | | L1: NOP + | | | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | | | NOP + | | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | GOTO L3 + | | | catch java.lang.Exception -> E4 + | | | E4: ASTORE_2 (line 12) + | | | ALOAD_1 // java.io.PrintStream out (line 13) + | | | ALOAD_2 // java.lang.Exception e + | | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | | catch java.lang.Throwable -> E1 + | | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | | | catch java.lang.Throwable -> E1 + | | | | GOTO L2 + | | | | E1: ASTORE 7 + | | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | | ALOAD 7 + | | | | ATHROW + | | | | L2: NOP + | | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | | NOP + | | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | finally -> E5 + | | GOTO L3 + | | E5: ASTORE 4 (line 14) + | | JSR L4 + | | ALOAD 4 + | | ATHROW + | | L3: JSR L4 + | | GOTO L6 + | | L4: ASTORE_3 + | | ALOAD_1 // java.io.PrintStream out (line 15) + | | LDC "finally" + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | catch java.lang.Throwable -> E0 + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | catch java.lang.Throwable -> E0 + | | | GOTO L5 + | | | E0: ASTORE 8 + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | ALOAD 8 + | | | ATHROW + | | | L5: NOP + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | NOP + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | RET 3 (line 10) + | | L6: GOTO L7 (line 17) + | catch java.lang.Throwable -> E6 + | E6: ASTORE 9 + | INVOKESTATIC Aspect.ajc_after_method_execution ()V + | ALOAD 9 + | ATHROW + | L7: INVOKESTATIC Aspect.ajc_after_method_execution ()V + | RETURN + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | catch java.lang.Throwable -> E4 + | | ICONST_0 (line 20) + | | ISTORE_0 + | | ILOAD_0 // int x (line 21) + | | LDC "name" + | | method-call(int java.lang.String.hashCode()) + | | | catch java.lang.Throwable -> E3 + | | | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | | | catch java.lang.Throwable -> E3 + | | | GOTO L0 + | | | E3: ASTORE_1 + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | ALOAD_1 + | | | ATHROW + | | | L0: NOP + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | NOP + | | method-call(int java.lang.String.hashCode()) + | | IADD + | | ISTORE_0 // int x + | | LDC "name" (line 22) + | | ASTORE_2 + | | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | | catch java.lang.Throwable -> E2 + | | | | NEW java.lang.StringBuffer + | | | | DUP + | | | | ALOAD_2 + | | | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | | | catch java.lang.Throwable -> E2 + | | | GOTO L1 + | | | E2: ASTORE_3 + | | | INVOKESTATIC Aspect.ajc_after_constructor_call ()V + | | | ALOAD_3 + | | | ATHROW + | | | L1: NOP + | | | INVOKESTATIC Aspect.ajc_after_constructor_call ()V + | | | NOP + | | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | ILOAD_0 // int x + | | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | | catch java.lang.Throwable -> E1 + | | | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | | | catch java.lang.Throwable -> E1 + | | | GOTO L2 + | | | E1: ASTORE 4 + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | ALOAD 4 + | | | ATHROW + | | | L2: NOP + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | NOP + | | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | | catch java.lang.Throwable -> E0 + | | | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | | | catch java.lang.Throwable -> E0 + | | | GOTO L3 + | | | E0: ASTORE 5 + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | ALOAD 5 + | | | ATHROW + | | | L3: NOP + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | NOP + | | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | GOTO L4 + | catch java.lang.Throwable -> E4 + | E4: ASTORE 6 + | INVOKESTATIC Aspect.ajc_after_method_execution ()V + | ALOAD 6 + | ATHROW + | L4: INVOKESTATIC Aspect.ajc_after_method_execution ()V + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/AfterHelloWorld.txt b/weaver/testdata/AfterHelloWorld.txt new file mode 100644 index 000000000..4c0e6db53 --- /dev/null +++ b/weaver/testdata/AfterHelloWorld.txt @@ -0,0 +1,58 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | catch java.lang.Throwable -> E0 + | | GOTO L0 + | catch java.lang.Throwable -> E0 + | E0: ASTORE_1 + | INVOKESTATIC Aspect.ajc_after_constructor_execution ()V + | ALOAD_1 + | ATHROW + | L0: INVOKESTATIC Aspect.ajc_after_constructor_execution ()V + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | catch java.lang.Throwable -> E2 + | | field-get(java.io.PrintStream java.lang.System.out) + | | | catch java.lang.Throwable -> E1 + | | | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | | | catch java.lang.Throwable -> E1 + | | | GOTO L0 + | | | E1: ASTORE_1 + | | | INVOKESTATIC Aspect.ajc_after_field_get ()V + | | | ALOAD_1 + | | | ATHROW + | | | L0: NOP + | | | INVOKESTATIC Aspect.ajc_after_field_get ()V + | | | NOP + | | field-get(java.io.PrintStream java.lang.System.out) + | | LDC "hello world" (line 9) + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | catch java.lang.Throwable -> E0 + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | catch java.lang.Throwable -> E0 + | | | GOTO L1 + | | | E0: ASTORE_2 + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | ALOAD_2 + | | | ATHROW + | | | L1: NOP + | | | INVOKESTATIC Aspect.ajc_after_method_call ()V + | | | NOP + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | GOTO L2 (line 11) + | catch java.lang.Throwable -> E2 + | E2: ASTORE_3 + | INVOKESTATIC Aspect.ajc_after_method_execution ()V + | ALOAD_3 + | ATHROW + | L2: INVOKESTATIC Aspect.ajc_after_method_execution ()V + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/AfterReturningCheckcastParamFancyHelloWorld.txt b/weaver/testdata/AfterReturningCheckcastParamFancyHelloWorld.txt new file mode 100644 index 000000000..868a63429 --- /dev/null +++ b/weaver/testdata/AfterReturningCheckcastParamFancyHelloWorld.txt @@ -0,0 +1,86 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | | DUP + | | ASTORE 5 + | | ALOAD 5 + | | INSTANCEOF java.rmi.server.LogStream + | | IFEQ L0 + | | ALOAD 5 + | | CHECKCAST java.rmi.server.LogStream + | | INVOKESTATIC Aspect.ajc_afterReturning_field_get (Ljava/rmi/server/LogStream;)V + | | L0: NOP + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L1 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L1 + | E1: ASTORE 4 (line 14) + | JSR L2 + | ALOAD 4 + | ATHROW + | L1: JSR L2 + | GOTO L3 + | L2: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L3: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/AfterReturningCheckcastParamHelloWorld.txt b/weaver/testdata/AfterReturningCheckcastParamHelloWorld.txt new file mode 100644 index 000000000..0aa498026 --- /dev/null +++ b/weaver/testdata/AfterReturningCheckcastParamHelloWorld.txt @@ -0,0 +1,31 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | | DUP + | | ASTORE_1 + | | ALOAD_1 + | | INSTANCEOF java.rmi.server.LogStream + | | IFEQ L0 + | | ALOAD_1 + | | CHECKCAST java.rmi.server.LogStream + | | INVOKESTATIC Aspect.ajc_afterReturning_field_get (Ljava/rmi/server/LogStream;)V + | | L0: NOP + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/AfterReturningConversionParam.txt b/weaver/testdata/AfterReturningConversionParam.txt new file mode 100644 index 000000000..7920b30d2 --- /dev/null +++ b/weaver/testdata/AfterReturningConversionParam.txt @@ -0,0 +1,83 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | | DUP + | | ISTORE_1 + | | ILOAD_1 + | | INVOKESTATIC org.aspectj.runtime.internal.Conversions.intObject (I)Ljava/lang/Object; + | | INVOKESTATIC Aspect.ajc_afterReturning_field_get (Ljava/lang/Object;)V + | | NOP + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/AfterReturningConversionParamFancyHelloWorld.txt b/weaver/testdata/AfterReturningConversionParamFancyHelloWorld.txt new file mode 100644 index 000000000..ab6c18583 --- /dev/null +++ b/weaver/testdata/AfterReturningConversionParamFancyHelloWorld.txt @@ -0,0 +1,88 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + local 0: FancyHelloWorld this + | ALOAD_0 + | INVOKESPECIAL java.lang.Object.<init> ()V + local 0: FancyHelloWorld this + RETURN + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | local 0: java.lang.String[] args + | | field-get(java.io.PrintStream java.lang.System.out) + | | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; + | | field-get(java.io.PrintStream java.lang.System.out) + | | ASTORE_1 + | | local 1: java.io.PrintStream out + | | | finally -> E1 + | | | | catch java.lang.Exception -> E0 + | | | | | ALOAD_1 + | | | | | LDC "bye" + | | | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | | GOTO L0 + | | | | catch java.lang.Exception -> E0 + | | | | E0: ASTORE_2 + | | | | local 2: java.lang.Exception e + | | | | | ALOAD_1 + | | | | | ALOAD_2 + | | | | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | | | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | | local 2: java.lang.Exception e + | | | finally -> E1 + | | | GOTO L0 + | | | E1: ASTORE 4 + | | | JSR L1 + | | | ALOAD 4 + | | | ATHROW + | | | L0: JSR L1 + | | | GOTO L2 + | | | L1: ASTORE_3 + | | | ALOAD_1 + | | | LDC "finally" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | RET 3 + | | local 1: java.io.PrintStream out + | local 0: java.lang.String[] args + | L2: RETURN + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 + | ISTORE_0 + | local 0: int x + | | ILOAD_0 + | | LDC "name" + | | method-call(int java.lang.String.hashCode()) + | | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | | | DUP + | | | ISTORE_1 + | | | ILOAD_1 + | | | INVOKESTATIC org.aspectj.runtime.internal.Conversions.intObject (I)Ljava/lang/Object; + | | | INVOKESTATIC Aspect.ajc_afterReturning_field_get (Ljava/lang/Object;)V + | | method-call(int java.lang.String.hashCode()) + | | IADD + | | ISTORE_0 + | | NEW java.lang.StringBuffer + | | DUP + | | LDC "name" + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | | ILOAD_0 + | | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | | method-call(java.lang.String java.lang.StringBuffer.toString()) + | local 0: int x + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/AfterReturningFancyHelloWorld.txt b/weaver/testdata/AfterReturningFancyHelloWorld.txt new file mode 100644 index 000000000..1bcdad132 --- /dev/null +++ b/weaver/testdata/AfterReturningFancyHelloWorld.txt @@ -0,0 +1,101 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | GOTO L0 + | L0: INVOKESTATIC Aspect.ajc_afterReturning_constructor_execution ()V + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | | INVOKESTATIC Aspect.ajc_afterReturning_field_get ()V + | | NOP + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | | INVOKESTATIC Aspect.ajc_afterReturning_method_call ()V + | | | | NOP + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | | INVOKESTATIC Aspect.ajc_afterReturning_method_call ()V + | | | NOP + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | INVOKESTATIC Aspect.ajc_afterReturning_method_call ()V + | | NOP + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: GOTO L3 (line 17) + | L3: INVOKESTATIC Aspect.ajc_afterReturning_method_execution ()V + | RETURN + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | | INVOKESTATIC Aspect.ajc_afterReturning_method_call ()V + | | NOP + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | LDC "name" (line 22) + | ASTORE_1 + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | NEW java.lang.StringBuffer + | | DUP + | | ALOAD_1 + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | | INVOKESTATIC Aspect.ajc_afterReturning_constructor_call ()V + | | NOP + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | | INVOKESTATIC Aspect.ajc_afterReturning_method_call ()V + | | NOP + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | | INVOKESTATIC Aspect.ajc_afterReturning_method_call ()V + | | NOP + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | GOTO L0 + | L0: INVOKESTATIC Aspect.ajc_afterReturning_method_execution ()V + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/AfterReturningHelloWorld.txt b/weaver/testdata/AfterReturningHelloWorld.txt new file mode 100644 index 000000000..271a34b38 --- /dev/null +++ b/weaver/testdata/AfterReturningHelloWorld.txt @@ -0,0 +1,30 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | GOTO L0 + | L0: INVOKESTATIC Aspect.ajc_afterReturning_constructor_execution ()V + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | | INVOKESTATIC Aspect.ajc_afterReturning_field_get ()V + | | NOP + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | INVOKESTATIC Aspect.ajc_afterReturning_method_call ()V + | | NOP + | method-call(void java.io.PrintStream.println(java.lang.String)) + | GOTO L0 (line 11) + | L0: INVOKESTATIC Aspect.ajc_afterReturning_method_execution ()V + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/AfterReturningParamFancyHelloWorld.txt b/weaver/testdata/AfterReturningParamFancyHelloWorld.txt new file mode 100644 index 000000000..959862843 --- /dev/null +++ b/weaver/testdata/AfterReturningParamFancyHelloWorld.txt @@ -0,0 +1,82 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | | DUP + | | ASTORE 5 + | | ALOAD 5 + | | INVOKESTATIC Aspect.ajc_afterReturning_field_get (Ljava/lang/Object;)V + | | NOP + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/AfterReturningParamHelloWorld.txt b/weaver/testdata/AfterReturningParamHelloWorld.txt new file mode 100644 index 000000000..6da75a8f8 --- /dev/null +++ b/weaver/testdata/AfterReturningParamHelloWorld.txt @@ -0,0 +1,27 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | | DUP + | | ASTORE_1 + | | ALOAD_1 + | | INVOKESTATIC Aspect.ajc_afterReturning_field_get (Ljava/lang/Object;)V + | | NOP + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/AfterThrowingFancyHelloWorld.txt b/weaver/testdata/AfterThrowingFancyHelloWorld.txt new file mode 100644 index 000000000..ed9e89bfd --- /dev/null +++ b/weaver/testdata/AfterThrowingFancyHelloWorld.txt @@ -0,0 +1,161 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | catch java.lang.Throwable -> E0 + | | RETURN + | catch java.lang.Throwable -> E0 + | E0: ASTORE_1 + | INVOKESTATIC Aspect.ajc_afterThrowing_constructor_execution ()V + | ALOAD_1 + | ATHROW + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | catch java.lang.Throwable -> E6 + | | field-get(java.io.PrintStream java.lang.System.out) + | | | catch java.lang.Throwable -> E3 + | | | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | | | catch java.lang.Throwable -> E3 + | | | GOTO L0 + | | | E3: ASTORE 5 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_field_get ()V + | | | ALOAD 5 + | | | ATHROW + | | | L0: NOP + | | field-get(java.io.PrintStream java.lang.System.out) + | | ASTORE_1 + | | finally -> E5 + | | | catch java.lang.Exception -> E4 + | | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | | LDC "bye" + | | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | | catch java.lang.Throwable -> E2 + | | | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | | | catch java.lang.Throwable -> E2 + | | | | | GOTO L1 + | | | | | E2: ASTORE 6 + | | | | | INVOKESTATIC Aspect.ajc_afterThrowing_method_call ()V + | | | | | ALOAD 6 + | | | | | ATHROW + | | | | | L1: NOP + | | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | GOTO L3 + | | | catch java.lang.Exception -> E4 + | | | E4: ASTORE_2 (line 12) + | | | ALOAD_1 // java.io.PrintStream out (line 13) + | | | ALOAD_2 // java.lang.Exception e + | | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | | catch java.lang.Throwable -> E1 + | | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | | | catch java.lang.Throwable -> E1 + | | | | GOTO L2 + | | | | E1: ASTORE 7 + | | | | INVOKESTATIC Aspect.ajc_afterThrowing_method_call ()V + | | | | ALOAD 7 + | | | | ATHROW + | | | | L2: NOP + | | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | finally -> E5 + | | GOTO L3 + | | E5: ASTORE 4 (line 14) + | | JSR L4 + | | ALOAD 4 + | | ATHROW + | | L3: JSR L4 + | | GOTO L6 + | | L4: ASTORE_3 + | | ALOAD_1 // java.io.PrintStream out (line 15) + | | LDC "finally" + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | catch java.lang.Throwable -> E0 + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | catch java.lang.Throwable -> E0 + | | | GOTO L5 + | | | E0: ASTORE 8 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_method_call ()V + | | | ALOAD 8 + | | | ATHROW + | | | L5: NOP + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | RET 3 (line 10) + | | L6: RETURN (line 17) + | catch java.lang.Throwable -> E6 + | E6: ASTORE 9 + | INVOKESTATIC Aspect.ajc_afterThrowing_method_execution ()V + | ALOAD 9 + | ATHROW + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | catch java.lang.Throwable -> E4 + | | ICONST_0 (line 20) + | | ISTORE_0 + | | ILOAD_0 // int x (line 21) + | | LDC "name" + | | method-call(int java.lang.String.hashCode()) + | | | catch java.lang.Throwable -> E3 + | | | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | | | catch java.lang.Throwable -> E3 + | | | GOTO L0 + | | | E3: ASTORE_1 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_method_call ()V + | | | ALOAD_1 + | | | ATHROW + | | | L0: NOP + | | method-call(int java.lang.String.hashCode()) + | | IADD + | | ISTORE_0 // int x + | | LDC "name" (line 22) + | | ASTORE_2 + | | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | | catch java.lang.Throwable -> E2 + | | | | NEW java.lang.StringBuffer + | | | | DUP + | | | | ALOAD_2 + | | | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | | | catch java.lang.Throwable -> E2 + | | | GOTO L1 + | | | E2: ASTORE_3 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_constructor_call ()V + | | | ALOAD_3 + | | | ATHROW + | | | L1: NOP + | | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | ILOAD_0 // int x + | | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | | catch java.lang.Throwable -> E1 + | | | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | | | catch java.lang.Throwable -> E1 + | | | GOTO L2 + | | | E1: ASTORE 4 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_method_call ()V + | | | ALOAD 4 + | | | ATHROW + | | | L2: NOP + | | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | | catch java.lang.Throwable -> E0 + | | | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | | | catch java.lang.Throwable -> E0 + | | | GOTO L3 + | | | E0: ASTORE 5 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_method_call ()V + | | | ALOAD 5 + | | | ATHROW + | | | L3: NOP + | | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | ARETURN + | catch java.lang.Throwable -> E4 + | E4: ASTORE 6 + | INVOKESTATIC Aspect.ajc_afterThrowing_method_execution ()V + | ALOAD 6 + | ATHROW + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/AfterThrowingHelloWorld.txt b/weaver/testdata/AfterThrowingHelloWorld.txt new file mode 100644 index 000000000..6b307e761 --- /dev/null +++ b/weaver/testdata/AfterThrowingHelloWorld.txt @@ -0,0 +1,50 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | catch java.lang.Throwable -> E0 + | | RETURN + | catch java.lang.Throwable -> E0 + | E0: ASTORE_1 + | INVOKESTATIC Aspect.ajc_afterThrowing_constructor_execution ()V + | ALOAD_1 + | ATHROW + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | catch java.lang.Throwable -> E2 + | | field-get(java.io.PrintStream java.lang.System.out) + | | | catch java.lang.Throwable -> E1 + | | | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | | | catch java.lang.Throwable -> E1 + | | | GOTO L0 + | | | E1: ASTORE_1 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_field_get ()V + | | | ALOAD_1 + | | | ATHROW + | | | L0: NOP + | | field-get(java.io.PrintStream java.lang.System.out) + | | LDC "hello world" (line 9) + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | catch java.lang.Throwable -> E0 + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | catch java.lang.Throwable -> E0 + | | | GOTO L1 + | | | E0: ASTORE_2 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_method_call ()V + | | | ALOAD_2 + | | | ATHROW + | | | L1: NOP + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | RETURN (line 11) + | catch java.lang.Throwable -> E2 + | E2: ASTORE_3 + | INVOKESTATIC Aspect.ajc_afterThrowing_method_execution ()V + | ALOAD_3 + | ATHROW + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/AfterThrowingParamFancyHelloWorld.txt b/weaver/testdata/AfterThrowingParamFancyHelloWorld.txt new file mode 100644 index 000000000..351d35649 --- /dev/null +++ b/weaver/testdata/AfterThrowingParamFancyHelloWorld.txt @@ -0,0 +1,86 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | catch java.lang.Throwable -> E0 + | | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | | catch java.lang.Throwable -> E0 + | | GOTO L0 + | | E0: ASTORE 5 + | | ALOAD 5 + | | INVOKESTATIC Aspect.ajc_afterThrowing_field_get (Ljava/lang/Throwable;)V + | | ALOAD 5 + | | ATHROW + | | L0: NOP + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E2 + | | catch java.lang.Exception -> E1 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L1 + | | catch java.lang.Exception -> E1 + | | E1: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E2 + | GOTO L1 + | E2: ASTORE 4 (line 14) + | JSR L2 + | ALOAD 4 + | ATHROW + | L1: JSR L2 + | GOTO L3 + | L2: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L3: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/AfterThrowingParamHelloWorld.txt b/weaver/testdata/AfterThrowingParamHelloWorld.txt new file mode 100644 index 000000000..c94486d22 --- /dev/null +++ b/weaver/testdata/AfterThrowingParamHelloWorld.txt @@ -0,0 +1,31 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | catch java.lang.Throwable -> E0 + | | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | | catch java.lang.Throwable -> E0 + | | GOTO L0 + | | E0: ASTORE_1 + | | ALOAD_1 + | | INVOKESTATIC Aspect.ajc_afterThrowing_field_get (Ljava/lang/Throwable;)V + | | ALOAD_1 + | | ATHROW + | | L0: NOP + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/ArgsAfterReturningFancyHelloWorld.txt b/weaver/testdata/ArgsAfterReturningFancyHelloWorld.txt new file mode 100644 index 000000000..1aa2a4f09 --- /dev/null +++ b/weaver/testdata/ArgsAfterReturningFancyHelloWorld.txt @@ -0,0 +1,108 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE 8 + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | ASTORE 5 + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | ALOAD 5 + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | | ALOAD 5 + | | | | INVOKESTATIC Aspect.ajc_afterReturning_method_call (Ljava/lang/Object;)V + | | | | NOP + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | ASTORE 6 + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | ALOAD 6 + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | | ALOAD 6 + | | | INVOKESTATIC Aspect.ajc_afterReturning_method_call (Ljava/lang/Object;)V + | | | NOP + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | ASTORE 7 + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | ALOAD 7 + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | ALOAD 7 + | | INVOKESTATIC Aspect.ajc_afterReturning_method_call (Ljava/lang/Object;)V + | | NOP + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: GOTO L3 (line 17) + | L3: ALOAD 8 + | INVOKESTATIC Aspect.ajc_afterReturning_method_execution (Ljava/lang/Object;)V + | RETURN + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | LDC "name" (line 22) + | ASTORE_1 + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | NEW java.lang.StringBuffer + | | DUP + | | ALOAD_1 + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | | ALOAD_1 + | | INVOKESTATIC Aspect.ajc_afterReturning_constructor_call (Ljava/lang/Object;)V + | | NOP + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | ISTORE_2 + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | ILOAD_2 + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | | ILOAD_2 + | | INVOKESTATIC org.aspectj.runtime.internal.Conversions.intObject (I)Ljava/lang/Object; + | | INVOKESTATIC Aspect.ajc_afterReturning_method_call (Ljava/lang/Object;)V + | | NOP + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/ArgsAfterReturningHelloWorld.txt b/weaver/testdata/ArgsAfterReturningHelloWorld.txt new file mode 100644 index 000000000..1b3c0e0e7 --- /dev/null +++ b/weaver/testdata/ArgsAfterReturningHelloWorld.txt @@ -0,0 +1,32 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE_2 + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | ASTORE_1 + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | ALOAD_1 + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | ALOAD_1 + | | INVOKESTATIC Aspect.ajc_afterReturning_method_call (Ljava/lang/Object;)V + | | NOP + | method-call(void java.io.PrintStream.println(java.lang.String)) + | GOTO L0 (line 11) + | L0: ALOAD_2 + | INVOKESTATIC Aspect.ajc_afterReturning_method_execution (Ljava/lang/Object;)V + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/ArgsAfterThrowingHelloWorld.txt b/weaver/testdata/ArgsAfterThrowingHelloWorld.txt new file mode 100644 index 000000000..e71e5a4f1 --- /dev/null +++ b/weaver/testdata/ArgsAfterThrowingHelloWorld.txt @@ -0,0 +1,42 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE_3 + method-execution(void HelloWorld.main(java.lang.String[])) + | catch java.lang.Throwable -> E1 + | | field-get(java.io.PrintStream java.lang.System.out) + | | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | | field-get(java.io.PrintStream java.lang.System.out) + | | LDC "hello world" (line 9) + | | ASTORE_1 + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | catch java.lang.Throwable -> E0 + | | | | ALOAD_1 + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | catch java.lang.Throwable -> E0 + | | | GOTO L0 + | | | E0: ASTORE_2 + | | | ALOAD_1 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_method_call (Ljava/lang/Object;)V + | | | ALOAD_2 + | | | ATHROW + | | | L0: NOP + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | RETURN (line 11) + | catch java.lang.Throwable -> E1 + | E1: ASTORE 4 + | ALOAD_3 + | INVOKESTATIC Aspect.ajc_afterThrowing_method_execution (Ljava/lang/Object;)V + | ALOAD 4 + | ATHROW + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/ArgsBeforeAfterHelloWorld.txt b/weaver/testdata/ArgsBeforeAfterHelloWorld.txt new file mode 100644 index 000000000..cddac2323 --- /dev/null +++ b/weaver/testdata/ArgsBeforeAfterHelloWorld.txt @@ -0,0 +1,52 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE_3 + method-execution(void HelloWorld.main(java.lang.String[])) + | catch java.lang.Throwable -> E1 + | | ALOAD_3 + | | INVOKESTATIC Aspect.ajc_before_method_execution (Ljava/lang/Object;)V + | | field-get(java.io.PrintStream java.lang.System.out) + | | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | | field-get(java.io.PrintStream java.lang.System.out) + | | LDC "hello world" (line 9) + | | ASTORE_1 + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | catch java.lang.Throwable -> E0 + | | | | ALOAD_1 + | | | | INVOKESTATIC Aspect.ajc_before_method_call (Ljava/lang/Object;)V + | | | | ALOAD_1 + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | catch java.lang.Throwable -> E0 + | | | GOTO L0 + | | | E0: ASTORE_2 + | | | ALOAD_1 + | | | INVOKESTATIC Aspect.ajc_afterThrowing_method_call (Ljava/lang/Object;)V + | | | ALOAD_2 + | | | ATHROW + | | | L0: NOP + | | | ALOAD_1 + | | | INVOKESTATIC Aspect.ajc_afterReturning_method_call (Ljava/lang/Object;)V + | | | NOP + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | GOTO L1 (line 11) + | catch java.lang.Throwable -> E1 + | E1: ASTORE 4 + | ALOAD_3 + | INVOKESTATIC Aspect.ajc_afterThrowing_method_execution (Ljava/lang/Object;)V + | ALOAD 4 + | ATHROW + | L1: ALOAD_3 + | INVOKESTATIC Aspect.ajc_afterReturning_method_execution (Ljava/lang/Object;)V + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/AroundAllAndOthersFancyHelloWorld.txt b/weaver/testdata/AroundAllAndOthersFancyHelloWorld.txt new file mode 100644 index 000000000..fd5984ed4 --- /dev/null +++ b/weaver/testdata/AroundAllAndOthersFancyHelloWorld.txt @@ -0,0 +1,1003 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | INVOKESTATIC Aspect.ajc_before_constructor_execution ()V + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE_2 + | ALOAD_2 + | BIPUSH 0 + | ALOAD_0 + | AASTORE + | NEW FancyHelloWorld$AjcClosure3 + | DUP + | ALOAD_2 + | INVOKESPECIAL FancyHelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE 19 + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 21 + | ALOAD 21 + | BIPUSH 0 + | ALOAD 19 + | AASTORE + | NEW FancyHelloWorld$AjcClosure23 + | DUP + | ALOAD 21 + | INVOKESPECIAL FancyHelloWorld$AjcClosure23.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + | RETURN + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | BIPUSH 0 + | ANEWARRAY java.lang.Object + | ASTORE 15 + | NEW FancyHelloWorld$AjcClosure43 + | DUP + | ALOAD 15 + | INVOKESPECIAL FancyHelloWorld$AjcClosure43.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.lang.String + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() + + static final void init$_aroundBody0(FancyHelloWorld): + RETURN (line 7) + end static final void init$_aroundBody0(FancyHelloWorld) + + static final void init$_aroundBody2(FancyHelloWorld): + INVOKESTATIC Aspect.ajc_before_constructor_execution ()V + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE_1 + ALOAD_1 + BIPUSH 0 + ALOAD_0 + AASTORE + NEW FancyHelloWorld$AjcClosure1 + DUP + ALOAD_1 + INVOKESPECIAL FancyHelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void init$_aroundBody2(FancyHelloWorld) + + static final java.io.PrintStream out_aroundBody4(): + GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + ARETURN + end static final java.io.PrintStream out_aroundBody4() + + static final java.io.PrintStream out_aroundBody6(): + INVOKESTATIC Aspect.ajc_before_field_get ()V + BIPUSH 0 + ANEWARRAY java.lang.Object + ASTORE_0 + NEW FancyHelloWorld$AjcClosure5 + DUP + ALOAD_0 + INVOKESPECIAL FancyHelloWorld$AjcClosure5.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + CHECKCAST java.io.PrintStream + ARETURN + end static final java.io.PrintStream out_aroundBody6() + + static final void println_aroundBody8(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 11) + RETURN + end static final void println_aroundBody8(java.io.PrintStream, String) + + static final void println_aroundBody10(java.io.PrintStream, String): + INVOKESTATIC Aspect.ajc_before_method_call ()V + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW FancyHelloWorld$AjcClosure9 + DUP + ALOAD_2 + INVOKESPECIAL FancyHelloWorld$AjcClosure9.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void println_aroundBody10(java.io.PrintStream, String) + + static final void println_aroundBody12(java.io.PrintStream, Object): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V (line 13) + RETURN + end static final void println_aroundBody12(java.io.PrintStream, Object) + + static final void println_aroundBody14(java.io.PrintStream, Object): + INVOKESTATIC Aspect.ajc_before_method_call ()V + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW FancyHelloWorld$AjcClosure13 + DUP + ALOAD_2 + INVOKESPECIAL FancyHelloWorld$AjcClosure13.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void println_aroundBody14(java.io.PrintStream, Object) + + static final void println_aroundBody16(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 15) + RETURN + end static final void println_aroundBody16(java.io.PrintStream, String) + + static final void println_aroundBody18(java.io.PrintStream, String): + INVOKESTATIC Aspect.ajc_before_method_call ()V + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW FancyHelloWorld$AjcClosure17 + DUP + ALOAD_2 + INVOKESPECIAL FancyHelloWorld$AjcClosure17.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void println_aroundBody18(java.io.PrintStream, String) + + static final void main_aroundBody20(String[]): + field-get(java.io.PrintStream java.lang.System.out) + | INVOKESTATIC Aspect.ajc_before_field_get ()V + | BIPUSH 0 + | ANEWARRAY java.lang.Object + | ASTORE_1 + | NEW FancyHelloWorld$AjcClosure7 + | DUP + | ALOAD_1 + | INVOKESPECIAL FancyHelloWorld$AjcClosure7.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.io.PrintStream + field-get(java.io.PrintStream java.lang.System.out) + ASTORE_3 (line 9) + finally -> E1 + | catch java.lang.Exception -> E0 + | | ALOAD_3 (line 11) + | | LDC "bye" + | | ASTORE 5 + | | ASTORE 7 + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | | BIPUSH 2 + | | | ANEWARRAY java.lang.Object + | | | ASTORE 9 + | | | ALOAD 9 + | | | BIPUSH 0 + | | | ALOAD 7 + | | | AASTORE + | | | ALOAD 9 + | | | BIPUSH 1 + | | | ALOAD 5 + | | | AASTORE + | | | NEW FancyHelloWorld$AjcClosure11 + | | | DUP + | | | ALOAD 9 + | | | INVOKESPECIAL FancyHelloWorld$AjcClosure11.<init> ([Ljava/lang/Object;)V + | | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | | POP + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | GOTO L0 + | catch java.lang.Exception -> E0 + | E0: ASTORE 11 (line 12) + | ALOAD_3 (line 13) + | ALOAD 11 + | ASTORE 13 + | ASTORE 15 + | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | BIPUSH 2 + | | ANEWARRAY java.lang.Object + | | ASTORE 17 + | | ALOAD 17 + | | BIPUSH 0 + | | ALOAD 15 + | | AASTORE + | | ALOAD 17 + | | BIPUSH 1 + | | ALOAD 13 + | | AASTORE + | | NEW FancyHelloWorld$AjcClosure15 + | | DUP + | | ALOAD 17 + | | INVOKESPECIAL FancyHelloWorld$AjcClosure15.<init> ([Ljava/lang/Object;)V + | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | POP + | method-call(void java.io.PrintStream.println(java.lang.Object)) + finally -> E1 + GOTO L0 + E1: ASTORE 19 (line 14) + JSR L1 + ALOAD 19 + ATHROW + L0: JSR L1 + GOTO L2 + L1: ASTORE 21 + ALOAD_3 (line 15) + LDC "finally" + ASTORE 23 + ASTORE 25 + method-call(void java.io.PrintStream.println(java.lang.String)) + | INVOKESTATIC Aspect.ajc_before_method_call ()V + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE 27 + | ALOAD 27 + | BIPUSH 0 + | ALOAD 25 + | AASTORE + | ALOAD 27 + | BIPUSH 1 + | ALOAD 23 + | AASTORE + | NEW FancyHelloWorld$AjcClosure19 + | DUP + | ALOAD 27 + | INVOKESPECIAL FancyHelloWorld$AjcClosure19.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + method-call(void java.io.PrintStream.println(java.lang.String)) + RET 21 (line 10) + L2: RETURN (line 17) + end static final void main_aroundBody20(String[]) + + static final void main_aroundBody22(String[]): + INVOKESTATIC Aspect.ajc_before_method_execution ()V + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE_1 + ALOAD_1 + BIPUSH 0 + ALOAD_0 + AASTORE + NEW FancyHelloWorld$AjcClosure21 + DUP + ALOAD_1 + INVOKESPECIAL FancyHelloWorld$AjcClosure21.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void main_aroundBody22(String[]) + + static final int hashCode_aroundBody24(String): + ALOAD_0 + INVOKEVIRTUAL java.lang.String.hashCode ()I (line 21) + IRETURN + end static final int hashCode_aroundBody24(String) + + static final int hashCode_aroundBody26(String): + INVOKESTATIC Aspect.ajc_before_method_call ()V + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE_1 + ALOAD_1 + BIPUSH 0 + ALOAD_0 + AASTORE + NEW FancyHelloWorld$AjcClosure25 + DUP + ALOAD_1 + INVOKESPECIAL FancyHelloWorld$AjcClosure25.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + INVOKESTATIC org.aspectj.runtime.internal.Conversions.intValue (Ljava/lang/Object;)I + IRETURN + end static final int hashCode_aroundBody26(String) + + static final StringBuffer init$_aroundBody28(String): + NEW java.lang.StringBuffer + DUP + ALOAD_0 + INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V (line 22) + ARETURN + end static final StringBuffer init$_aroundBody28(String) + + static final StringBuffer init$_aroundBody30(String): + INVOKESTATIC Aspect.ajc_before_constructor_call ()V + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE_1 + ALOAD_1 + BIPUSH 0 + ALOAD_0 + AASTORE + NEW FancyHelloWorld$AjcClosure29 + DUP + ALOAD_1 + INVOKESPECIAL FancyHelloWorld$AjcClosure29.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + CHECKCAST java.lang.StringBuffer + ARETURN + end static final StringBuffer init$_aroundBody30(String) + + static final StringBuffer append_aroundBody32(StringBuffer, int): + ALOAD_0 + ILOAD_1 + INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; (line 22) + ARETURN + end static final StringBuffer append_aroundBody32(StringBuffer, int) + + static final StringBuffer append_aroundBody34(StringBuffer, int): + INVOKESTATIC Aspect.ajc_before_method_call ()V + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ILOAD_1 + INVOKESTATIC org.aspectj.runtime.internal.Conversions.intObject (I)Ljava/lang/Object; + AASTORE + NEW FancyHelloWorld$AjcClosure33 + DUP + ALOAD_2 + INVOKESPECIAL FancyHelloWorld$AjcClosure33.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + CHECKCAST java.lang.StringBuffer + ARETURN + end static final StringBuffer append_aroundBody34(StringBuffer, int) + + static final String toString_aroundBody36(StringBuffer): + ALOAD_0 + INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; (line 22) + ARETURN + end static final String toString_aroundBody36(StringBuffer) + + static final String toString_aroundBody38(StringBuffer): + INVOKESTATIC Aspect.ajc_before_method_call ()V + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE_1 + ALOAD_1 + BIPUSH 0 + ALOAD_0 + AASTORE + NEW FancyHelloWorld$AjcClosure37 + DUP + ALOAD_1 + INVOKESPECIAL FancyHelloWorld$AjcClosure37.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + CHECKCAST java.lang.String + ARETURN + end static final String toString_aroundBody38(StringBuffer) + + static final String getName_aroundBody40(): + ICONST_0 (line 20) + ISTORE_0 + ILOAD_0 (line 21) + LDC "name" + ASTORE_2 + method-call(int java.lang.String.hashCode()) + | INVOKESTATIC Aspect.ajc_before_method_call ()V + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 4 + | ALOAD 4 + | BIPUSH 0 + | ALOAD_2 + | AASTORE + | NEW FancyHelloWorld$AjcClosure27 + | DUP + | ALOAD 4 + | INVOKESPECIAL FancyHelloWorld$AjcClosure27.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | INVOKESTATIC org.aspectj.runtime.internal.Conversions.intValue (Ljava/lang/Object;)I + method-call(int java.lang.String.hashCode()) + IADD + ISTORE_0 + LDC "name" (line 22) + ASTORE 6 + constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | INVOKESTATIC Aspect.ajc_before_constructor_call ()V + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 8 + | ALOAD 8 + | BIPUSH 0 + | ALOAD 6 + | AASTORE + | NEW FancyHelloWorld$AjcClosure31 + | DUP + | ALOAD 8 + | INVOKESPECIAL FancyHelloWorld$AjcClosure31.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.lang.StringBuffer + constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + ILOAD_0 + ISTORE 10 + ASTORE 12 + method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | INVOKESTATIC Aspect.ajc_before_method_call ()V + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE 14 + | ALOAD 14 + | BIPUSH 0 + | ALOAD 12 + | AASTORE + | ALOAD 14 + | BIPUSH 1 + | ILOAD 10 + | INVOKESTATIC org.aspectj.runtime.internal.Conversions.intObject (I)Ljava/lang/Object; + | AASTORE + | NEW FancyHelloWorld$AjcClosure35 + | DUP + | ALOAD 14 + | INVOKESPECIAL FancyHelloWorld$AjcClosure35.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.lang.StringBuffer + method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + ASTORE 16 + method-call(java.lang.String java.lang.StringBuffer.toString()) + | INVOKESTATIC Aspect.ajc_before_method_call ()V + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 18 + | ALOAD 18 + | BIPUSH 0 + | ALOAD 16 + | AASTORE + | NEW FancyHelloWorld$AjcClosure39 + | DUP + | ALOAD 18 + | INVOKESPECIAL FancyHelloWorld$AjcClosure39.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.lang.String + method-call(java.lang.String java.lang.StringBuffer.toString()) + ARETURN + end static final String getName_aroundBody40() + + static final String getName_aroundBody42(): + INVOKESTATIC Aspect.ajc_before_method_execution ()V + BIPUSH 0 + ANEWARRAY java.lang.Object + ASTORE_0 + NEW FancyHelloWorld$AjcClosure41 + DUP + ALOAD_0 + INVOKESPECIAL FancyHelloWorld$AjcClosure41.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + CHECKCAST java.lang.String + ARETURN + end static final String getName_aroundBody42() +end public abstract class FancyHelloWorld + +public class FancyHelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST FancyHelloWorld + INVOKESTATIC FancyHelloWorld.init$_aroundBody0 (LFancyHelloWorld;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure1 + +public class FancyHelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST FancyHelloWorld + INVOKESTATIC FancyHelloWorld.init$_aroundBody2 (LFancyHelloWorld;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure3 + +public class FancyHelloWorld$AjcClosure5 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + INVOKESTATIC FancyHelloWorld.out_aroundBody4 ()Ljava/io/PrintStream; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure5 + +public class FancyHelloWorld$AjcClosure7 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + INVOKESTATIC FancyHelloWorld.out_aroundBody6 ()Ljava/io/PrintStream; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure7 + +public class FancyHelloWorld$AjcClosure9 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody8 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure9 + +public class FancyHelloWorld$AjcClosure11 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody10 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure11 + +public class FancyHelloWorld$AjcClosure13 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC FancyHelloWorld.println_aroundBody12 (Ljava/io/PrintStream;Ljava/lang/Object;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure13 + +public class FancyHelloWorld$AjcClosure15 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC FancyHelloWorld.println_aroundBody14 (Ljava/io/PrintStream;Ljava/lang/Object;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure15 + +public class FancyHelloWorld$AjcClosure17 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody16 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure17 + +public class FancyHelloWorld$AjcClosure19 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody18 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure19 + +public class FancyHelloWorld$AjcClosure21 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST [Ljava.lang.String; + INVOKESTATIC FancyHelloWorld.main_aroundBody20 ([Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure21 + +public class FancyHelloWorld$AjcClosure23 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST [Ljava.lang.String; + INVOKESTATIC FancyHelloWorld.main_aroundBody22 ([Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure23 + +public class FancyHelloWorld$AjcClosure25 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.hashCode_aroundBody24 (Ljava/lang/String;)I + INVOKESTATIC org.aspectj.runtime.internal.Conversions.intObject (I)Ljava/lang/Object; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure25 + +public class FancyHelloWorld$AjcClosure27 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.hashCode_aroundBody26 (Ljava/lang/String;)I + INVOKESTATIC org.aspectj.runtime.internal.Conversions.intObject (I)Ljava/lang/Object; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure27 + +public class FancyHelloWorld$AjcClosure29 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.init$_aroundBody28 (Ljava/lang/String;)Ljava/lang/StringBuffer; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure29 + +public class FancyHelloWorld$AjcClosure31 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.init$_aroundBody30 (Ljava/lang/String;)Ljava/lang/StringBuffer; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure31 + +public class FancyHelloWorld$AjcClosure33 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.StringBuffer + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC org.aspectj.runtime.internal.Conversions.intValue (Ljava/lang/Object;)I + INVOKESTATIC FancyHelloWorld.append_aroundBody32 (Ljava/lang/StringBuffer;I)Ljava/lang/StringBuffer; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure33 + +public class FancyHelloWorld$AjcClosure35 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.StringBuffer + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC org.aspectj.runtime.internal.Conversions.intValue (Ljava/lang/Object;)I + INVOKESTATIC FancyHelloWorld.append_aroundBody34 (Ljava/lang/StringBuffer;I)Ljava/lang/StringBuffer; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure35 + +public class FancyHelloWorld$AjcClosure37 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.StringBuffer + INVOKESTATIC FancyHelloWorld.toString_aroundBody36 (Ljava/lang/StringBuffer;)Ljava/lang/String; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure37 + +public class FancyHelloWorld$AjcClosure39 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.StringBuffer + INVOKESTATIC FancyHelloWorld.toString_aroundBody38 (Ljava/lang/StringBuffer;)Ljava/lang/String; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure39 + +public class FancyHelloWorld$AjcClosure41 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + INVOKESTATIC FancyHelloWorld.getName_aroundBody40 ()Ljava/lang/String; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure41 + +public class FancyHelloWorld$AjcClosure43 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + INVOKESTATIC FancyHelloWorld.getName_aroundBody42 ()Ljava/lang/String; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure43 diff --git a/weaver/testdata/AroundAllAndOthersHelloWorld.txt b/weaver/testdata/AroundAllAndOthersHelloWorld.txt new file mode 100644 index 000000000..2175e03c6 --- /dev/null +++ b/weaver/testdata/AroundAllAndOthersHelloWorld.txt @@ -0,0 +1,346 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | INVOKESTATIC Aspect.ajc_before_constructor_execution ()V + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE_2 + | ALOAD_2 + | BIPUSH 0 + | ALOAD_0 + | AASTORE + | NEW HelloWorld$AjcClosure3 + | DUP + | ALOAD_2 + | INVOKESPECIAL HelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE 7 + method-execution(void HelloWorld.main(java.lang.String[])) + | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 9 + | ALOAD 9 + | BIPUSH 0 + | ALOAD 7 + | AASTORE + | NEW HelloWorld$AjcClosure15 + | DUP + | ALOAD 9 + | INVOKESPECIAL HelloWorld$AjcClosure15.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static final void init$_aroundBody0(HelloWorld): + RETURN (line 5) + end static final void init$_aroundBody0(HelloWorld) + + static final void init$_aroundBody2(HelloWorld): + INVOKESTATIC Aspect.ajc_before_constructor_execution ()V + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE_1 + ALOAD_1 + BIPUSH 0 + ALOAD_0 + AASTORE + NEW HelloWorld$AjcClosure1 + DUP + ALOAD_1 + INVOKESPECIAL HelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void init$_aroundBody2(HelloWorld) + + static final java.io.PrintStream out_aroundBody4(): + GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + ARETURN + end static final java.io.PrintStream out_aroundBody4() + + static final java.io.PrintStream out_aroundBody6(): + INVOKESTATIC Aspect.ajc_before_field_get ()V + BIPUSH 0 + ANEWARRAY java.lang.Object + ASTORE_0 + NEW HelloWorld$AjcClosure5 + DUP + ALOAD_0 + INVOKESPECIAL HelloWorld$AjcClosure5.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + CHECKCAST java.io.PrintStream + ARETURN + end static final java.io.PrintStream out_aroundBody6() + + static final void println_aroundBody8(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 9) + RETURN + end static final void println_aroundBody8(java.io.PrintStream, String) + + static final void println_aroundBody10(java.io.PrintStream, String): + INVOKESTATIC Aspect.ajc_before_method_call ()V + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW HelloWorld$AjcClosure9 + DUP + ALOAD_2 + INVOKESPECIAL HelloWorld$AjcClosure9.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void println_aroundBody10(java.io.PrintStream, String) + + static final void main_aroundBody12(String[]): + field-get(java.io.PrintStream java.lang.System.out) + | INVOKESTATIC Aspect.ajc_before_field_get ()V + | BIPUSH 0 + | ANEWARRAY java.lang.Object + | ASTORE_1 + | NEW HelloWorld$AjcClosure7 + | DUP + | ALOAD_1 + | INVOKESPECIAL HelloWorld$AjcClosure7.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.io.PrintStream + field-get(java.io.PrintStream java.lang.System.out) + LDC "hello world" (line 9) + ASTORE_3 + ASTORE 5 + method-call(void java.io.PrintStream.println(java.lang.String)) + | INVOKESTATIC Aspect.ajc_before_method_call ()V + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE 7 + | ALOAD 7 + | BIPUSH 0 + | ALOAD 5 + | AASTORE + | ALOAD 7 + | BIPUSH 1 + | ALOAD_3 + | AASTORE + | NEW HelloWorld$AjcClosure11 + | DUP + | ALOAD 7 + | INVOKESPECIAL HelloWorld$AjcClosure11.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + method-call(void java.io.PrintStream.println(java.lang.String)) + RETURN (line 11) + end static final void main_aroundBody12(String[]) + + static final void main_aroundBody14(String[]): + INVOKESTATIC Aspect.ajc_before_method_execution ()V + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE_1 + ALOAD_1 + BIPUSH 0 + ALOAD_0 + AASTORE + NEW HelloWorld$AjcClosure13 + DUP + ALOAD_1 + INVOKESPECIAL HelloWorld$AjcClosure13.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void main_aroundBody14(String[]) +end public class HelloWorld + +public class HelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST HelloWorld + INVOKESTATIC HelloWorld.init$_aroundBody0 (LHelloWorld;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure1 + +public class HelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST HelloWorld + INVOKESTATIC HelloWorld.init$_aroundBody2 (LHelloWorld;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure3 + +public class HelloWorld$AjcClosure5 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + INVOKESTATIC HelloWorld.out_aroundBody4 ()Ljava/io/PrintStream; + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure5 + +public class HelloWorld$AjcClosure7 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + INVOKESTATIC HelloWorld.out_aroundBody6 ()Ljava/io/PrintStream; + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure7 + +public class HelloWorld$AjcClosure9 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC HelloWorld.println_aroundBody8 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure9 + +public class HelloWorld$AjcClosure11 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC HelloWorld.println_aroundBody10 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure11 + +public class HelloWorld$AjcClosure13 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST [Ljava.lang.String; + INVOKESTATIC HelloWorld.main_aroundBody12 ([Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure13 + +public class HelloWorld$AjcClosure15 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST [Ljava.lang.String; + INVOKESTATIC HelloWorld.main_aroundBody14 ([Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure15 diff --git a/weaver/testdata/AroundAllFancyHelloWorld.txt b/weaver/testdata/AroundAllFancyHelloWorld.txt new file mode 100644 index 000000000..ab5412705 --- /dev/null +++ b/weaver/testdata/AroundAllFancyHelloWorld.txt @@ -0,0 +1,541 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE_1 + | ALOAD_1 + | BIPUSH 0 + | ALOAD_0 + | AASTORE + | NEW FancyHelloWorld$AjcClosure1 + | DUP + | ALOAD_1 + | INVOKESPECIAL FancyHelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE 15 + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 16 + | ALOAD 16 + | BIPUSH 0 + | ALOAD 15 + | AASTORE + | NEW FancyHelloWorld$AjcClosure11 + | DUP + | ALOAD 16 + | INVOKESPECIAL FancyHelloWorld$AjcClosure11.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + | RETURN + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | BIPUSH 0 + | ANEWARRAY java.lang.Object + | ASTORE 10 + | NEW FancyHelloWorld$AjcClosure21 + | DUP + | ALOAD 10 + | INVOKESPECIAL FancyHelloWorld$AjcClosure21.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.lang.String + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() + + static final void init$_aroundBody0(FancyHelloWorld): + RETURN (line 7) + end static final void init$_aroundBody0(FancyHelloWorld) + + static final java.io.PrintStream out_aroundBody2(): + GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + ARETURN + end static final java.io.PrintStream out_aroundBody2() + + static final void println_aroundBody4(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 11) + RETURN + end static final void println_aroundBody4(java.io.PrintStream, String) + + static final void println_aroundBody6(java.io.PrintStream, Object): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V (line 13) + RETURN + end static final void println_aroundBody6(java.io.PrintStream, Object) + + static final void println_aroundBody8(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 15) + RETURN + end static final void println_aroundBody8(java.io.PrintStream, String) + + static final void main_aroundBody10(String[]): + field-get(java.io.PrintStream java.lang.System.out) + | BIPUSH 0 + | ANEWARRAY java.lang.Object + | ASTORE_1 + | NEW FancyHelloWorld$AjcClosure3 + | DUP + | ALOAD_1 + | INVOKESPECIAL FancyHelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.io.PrintStream + field-get(java.io.PrintStream java.lang.System.out) + ASTORE_3 (line 9) + finally -> E1 + | catch java.lang.Exception -> E0 + | | ALOAD_3 (line 11) + | | LDC "bye" + | | ASTORE 5 + | | ASTORE 7 + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | BIPUSH 2 + | | | ANEWARRAY java.lang.Object + | | | ASTORE 9 + | | | ALOAD 9 + | | | BIPUSH 0 + | | | ALOAD 7 + | | | AASTORE + | | | ALOAD 9 + | | | BIPUSH 1 + | | | ALOAD 5 + | | | AASTORE + | | | NEW FancyHelloWorld$AjcClosure5 + | | | DUP + | | | ALOAD 9 + | | | INVOKESPECIAL FancyHelloWorld$AjcClosure5.<init> ([Ljava/lang/Object;)V + | | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | | POP + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | GOTO L0 + | catch java.lang.Exception -> E0 + | E0: ASTORE 11 (line 12) + | ALOAD_3 (line 13) + | ALOAD 11 + | ASTORE 13 + | ASTORE 15 + | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | BIPUSH 2 + | | ANEWARRAY java.lang.Object + | | ASTORE 17 + | | ALOAD 17 + | | BIPUSH 0 + | | ALOAD 15 + | | AASTORE + | | ALOAD 17 + | | BIPUSH 1 + | | ALOAD 13 + | | AASTORE + | | NEW FancyHelloWorld$AjcClosure7 + | | DUP + | | ALOAD 17 + | | INVOKESPECIAL FancyHelloWorld$AjcClosure7.<init> ([Ljava/lang/Object;)V + | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | POP + | method-call(void java.io.PrintStream.println(java.lang.Object)) + finally -> E1 + GOTO L0 + E1: ASTORE 19 (line 14) + JSR L1 + ALOAD 19 + ATHROW + L0: JSR L1 + GOTO L2 + L1: ASTORE 21 + ALOAD_3 (line 15) + LDC "finally" + ASTORE 23 + ASTORE 25 + method-call(void java.io.PrintStream.println(java.lang.String)) + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE 27 + | ALOAD 27 + | BIPUSH 0 + | ALOAD 25 + | AASTORE + | ALOAD 27 + | BIPUSH 1 + | ALOAD 23 + | AASTORE + | NEW FancyHelloWorld$AjcClosure9 + | DUP + | ALOAD 27 + | INVOKESPECIAL FancyHelloWorld$AjcClosure9.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + method-call(void java.io.PrintStream.println(java.lang.String)) + RET 21 (line 10) + L2: RETURN (line 17) + end static final void main_aroundBody10(String[]) + + static final int hashCode_aroundBody12(String): + ALOAD_0 + INVOKEVIRTUAL java.lang.String.hashCode ()I (line 21) + IRETURN + end static final int hashCode_aroundBody12(String) + + static final StringBuffer init$_aroundBody14(String): + NEW java.lang.StringBuffer + DUP + ALOAD_0 + INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V (line 22) + ARETURN + end static final StringBuffer init$_aroundBody14(String) + + static final StringBuffer append_aroundBody16(StringBuffer, int): + ALOAD_0 + ILOAD_1 + INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; (line 22) + ARETURN + end static final StringBuffer append_aroundBody16(StringBuffer, int) + + static final String toString_aroundBody18(StringBuffer): + ALOAD_0 + INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; (line 22) + ARETURN + end static final String toString_aroundBody18(StringBuffer) + + static final String getName_aroundBody20(): + ICONST_0 (line 20) + ISTORE_0 + ILOAD_0 (line 21) + LDC "name" + ASTORE_2 + method-call(int java.lang.String.hashCode()) + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 4 + | ALOAD 4 + | BIPUSH 0 + | ALOAD_2 + | AASTORE + | NEW FancyHelloWorld$AjcClosure13 + | DUP + | ALOAD 4 + | INVOKESPECIAL FancyHelloWorld$AjcClosure13.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | INVOKESTATIC org.aspectj.runtime.internal.Conversions.intValue (Ljava/lang/Object;)I + method-call(int java.lang.String.hashCode()) + IADD + ISTORE_0 + LDC "name" (line 22) + ASTORE 6 + constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 8 + | ALOAD 8 + | BIPUSH 0 + | ALOAD 6 + | AASTORE + | NEW FancyHelloWorld$AjcClosure15 + | DUP + | ALOAD 8 + | INVOKESPECIAL FancyHelloWorld$AjcClosure15.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.lang.StringBuffer + constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + ILOAD_0 + ISTORE 10 + ASTORE 12 + method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE 14 + | ALOAD 14 + | BIPUSH 0 + | ALOAD 12 + | AASTORE + | ALOAD 14 + | BIPUSH 1 + | ILOAD 10 + | INVOKESTATIC org.aspectj.runtime.internal.Conversions.intObject (I)Ljava/lang/Object; + | AASTORE + | NEW FancyHelloWorld$AjcClosure17 + | DUP + | ALOAD 14 + | INVOKESPECIAL FancyHelloWorld$AjcClosure17.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.lang.StringBuffer + method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + ASTORE 16 + method-call(java.lang.String java.lang.StringBuffer.toString()) + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 18 + | ALOAD 18 + | BIPUSH 0 + | ALOAD 16 + | AASTORE + | NEW FancyHelloWorld$AjcClosure19 + | DUP + | ALOAD 18 + | INVOKESPECIAL FancyHelloWorld$AjcClosure19.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.lang.String + method-call(java.lang.String java.lang.StringBuffer.toString()) + ARETURN + end static final String getName_aroundBody20() +end public abstract class FancyHelloWorld + +public class FancyHelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST FancyHelloWorld + INVOKESTATIC FancyHelloWorld.init$_aroundBody0 (LFancyHelloWorld;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure1 + +public class FancyHelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + INVOKESTATIC FancyHelloWorld.out_aroundBody2 ()Ljava/io/PrintStream; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure3 + +public class FancyHelloWorld$AjcClosure5 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody4 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure5 + +public class FancyHelloWorld$AjcClosure7 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC FancyHelloWorld.println_aroundBody6 (Ljava/io/PrintStream;Ljava/lang/Object;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure7 + +public class FancyHelloWorld$AjcClosure9 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody8 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure9 + +public class FancyHelloWorld$AjcClosure11 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST [Ljava.lang.String; + INVOKESTATIC FancyHelloWorld.main_aroundBody10 ([Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure11 + +public class FancyHelloWorld$AjcClosure13 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.hashCode_aroundBody12 (Ljava/lang/String;)I + INVOKESTATIC org.aspectj.runtime.internal.Conversions.intObject (I)Ljava/lang/Object; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure13 + +public class FancyHelloWorld$AjcClosure15 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.init$_aroundBody14 (Ljava/lang/String;)Ljava/lang/StringBuffer; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure15 + +public class FancyHelloWorld$AjcClosure17 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.StringBuffer + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC org.aspectj.runtime.internal.Conversions.intValue (Ljava/lang/Object;)I + INVOKESTATIC FancyHelloWorld.append_aroundBody16 (Ljava/lang/StringBuffer;I)Ljava/lang/StringBuffer; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure17 + +public class FancyHelloWorld$AjcClosure19 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.lang.StringBuffer + INVOKESTATIC FancyHelloWorld.toString_aroundBody18 (Ljava/lang/StringBuffer;)Ljava/lang/String; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure19 + +public class FancyHelloWorld$AjcClosure21 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + INVOKESTATIC FancyHelloWorld.getName_aroundBody20 ()Ljava/lang/String; + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure21 diff --git a/weaver/testdata/AroundAllHelloWorld.txt b/weaver/testdata/AroundAllHelloWorld.txt new file mode 100644 index 000000000..ea505e316 --- /dev/null +++ b/weaver/testdata/AroundAllHelloWorld.txt @@ -0,0 +1,183 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE_1 + | ALOAD_1 + | BIPUSH 0 + | ALOAD_0 + | AASTORE + | NEW HelloWorld$AjcClosure1 + | DUP + | ALOAD_1 + | INVOKESPECIAL HelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE 5 + method-execution(void HelloWorld.main(java.lang.String[])) + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 6 + | ALOAD 6 + | BIPUSH 0 + | ALOAD 5 + | AASTORE + | NEW HelloWorld$AjcClosure7 + | DUP + | ALOAD 6 + | INVOKESPECIAL HelloWorld$AjcClosure7.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static final void init$_aroundBody0(HelloWorld): + RETURN (line 5) + end static final void init$_aroundBody0(HelloWorld) + + static final java.io.PrintStream out_aroundBody2(): + GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + ARETURN + end static final java.io.PrintStream out_aroundBody2() + + static final void println_aroundBody4(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 9) + RETURN + end static final void println_aroundBody4(java.io.PrintStream, String) + + static final void main_aroundBody6(String[]): + field-get(java.io.PrintStream java.lang.System.out) + | BIPUSH 0 + | ANEWARRAY java.lang.Object + | ASTORE_1 + | NEW HelloWorld$AjcClosure3 + | DUP + | ALOAD_1 + | INVOKESPECIAL HelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.io.PrintStream + field-get(java.io.PrintStream java.lang.System.out) + LDC "hello world" (line 9) + ASTORE_3 + ASTORE 5 + method-call(void java.io.PrintStream.println(java.lang.String)) + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE 7 + | ALOAD 7 + | BIPUSH 0 + | ALOAD 5 + | AASTORE + | ALOAD 7 + | BIPUSH 1 + | ALOAD_3 + | AASTORE + | NEW HelloWorld$AjcClosure5 + | DUP + | ALOAD 7 + | INVOKESPECIAL HelloWorld$AjcClosure5.<init> ([Ljava/lang/Object;)V + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | POP + method-call(void java.io.PrintStream.println(java.lang.String)) + RETURN (line 11) + end static final void main_aroundBody6(String[]) +end public class HelloWorld + +public class HelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST HelloWorld + INVOKESTATIC HelloWorld.init$_aroundBody0 (LHelloWorld;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure1 + +public class HelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + INVOKESTATIC HelloWorld.out_aroundBody2 ()Ljava/io/PrintStream; + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure3 + +public class HelloWorld$AjcClosure5 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC HelloWorld.println_aroundBody4 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure5 + +public class HelloWorld$AjcClosure7 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST [Ljava.lang.String; + INVOKESTATIC HelloWorld.main_aroundBody6 ([Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure7 diff --git a/weaver/testdata/AroundAndOthersFancyHelloWorld.txt b/weaver/testdata/AroundAndOthersFancyHelloWorld.txt new file mode 100644 index 000000000..a8a2bd44e --- /dev/null +++ b/weaver/testdata/AroundAndOthersFancyHelloWorld.txt @@ -0,0 +1,375 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | ASTORE 5 + | | | ASTORE 6 + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | | | | BIPUSH 2 + | | | | ANEWARRAY java.lang.Object + | | | | ASTORE 8 + | | | | ALOAD 8 + | | | | BIPUSH 0 + | | | | ALOAD 6 + | | | | AASTORE + | | | | ALOAD 8 + | | | | BIPUSH 1 + | | | | ALOAD 5 + | | | | AASTORE + | | | | NEW FancyHelloWorld$AjcClosure3 + | | | | DUP + | | | | ALOAD 8 + | | | | INVOKESPECIAL FancyHelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | | | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | | | POP + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | ASTORE 9 + | | ASTORE 10 + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | | | BIPUSH 2 + | | | ANEWARRAY java.lang.Object + | | | ASTORE 12 + | | | ALOAD 12 + | | | BIPUSH 0 + | | | ALOAD 10 + | | | AASTORE + | | | ALOAD 12 + | | | BIPUSH 1 + | | | ALOAD 9 + | | | AASTORE + | | | NEW FancyHelloWorld$AjcClosure7 + | | | DUP + | | | ALOAD 12 + | | | INVOKESPECIAL FancyHelloWorld$AjcClosure7.<init> ([Ljava/lang/Object;)V + | | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | | POP + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | ASTORE 13 + | ASTORE 14 + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | | BIPUSH 2 + | | ANEWARRAY java.lang.Object + | | ASTORE 16 + | | ALOAD 16 + | | BIPUSH 0 + | | ALOAD 14 + | | AASTORE + | | ALOAD 16 + | | BIPUSH 1 + | | ALOAD 13 + | | AASTORE + | | NEW FancyHelloWorld$AjcClosure11 + | | DUP + | | ALOAD 16 + | | INVOKESPECIAL FancyHelloWorld$AjcClosure11.<init> ([Ljava/lang/Object;)V + | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | POP + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() + + static final void println_aroundBody0(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 11) + RETURN + end static final void println_aroundBody0(java.io.PrintStream, String) + + static final void println_aroundBody2(java.io.PrintStream, String): + INVOKESTATIC Aspect.ajc_before_method_execution ()V + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW FancyHelloWorld$AjcClosure1 + DUP + ALOAD_2 + INVOKESPECIAL FancyHelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void println_aroundBody2(java.io.PrintStream, String) + + static final void println_aroundBody4(java.io.PrintStream, Object): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V (line 13) + RETURN + end static final void println_aroundBody4(java.io.PrintStream, Object) + + static final void println_aroundBody6(java.io.PrintStream, Object): + INVOKESTATIC Aspect.ajc_before_method_execution ()V + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW FancyHelloWorld$AjcClosure5 + DUP + ALOAD_2 + INVOKESPECIAL FancyHelloWorld$AjcClosure5.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void println_aroundBody6(java.io.PrintStream, Object) + + static final void println_aroundBody8(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 15) + RETURN + end static final void println_aroundBody8(java.io.PrintStream, String) + + static final void println_aroundBody10(java.io.PrintStream, String): + INVOKESTATIC Aspect.ajc_before_method_execution ()V + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW FancyHelloWorld$AjcClosure9 + DUP + ALOAD_2 + INVOKESPECIAL FancyHelloWorld$AjcClosure9.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void println_aroundBody10(java.io.PrintStream, String) +end public abstract class FancyHelloWorld + +public class FancyHelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody0 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure1 + +public class FancyHelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody2 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure3 + +public class FancyHelloWorld$AjcClosure5 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC FancyHelloWorld.println_aroundBody4 (Ljava/io/PrintStream;Ljava/lang/Object;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure5 + +public class FancyHelloWorld$AjcClosure7 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC FancyHelloWorld.println_aroundBody6 (Ljava/io/PrintStream;Ljava/lang/Object;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure7 + +public class FancyHelloWorld$AjcClosure9 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody8 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure9 + +public class FancyHelloWorld$AjcClosure11 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody10 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure11 diff --git a/weaver/testdata/AroundAndOthersHelloWorld.txt b/weaver/testdata/AroundAndOthersHelloWorld.txt new file mode 100644 index 000000000..66240b877 --- /dev/null +++ b/weaver/testdata/AroundAndOthersHelloWorld.txt @@ -0,0 +1,122 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | ASTORE_1 + | ASTORE_2 + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | | BIPUSH 2 + | | ANEWARRAY java.lang.Object + | | ASTORE 4 + | | ALOAD 4 + | | BIPUSH 0 + | | ALOAD_2 + | | AASTORE + | | ALOAD 4 + | | BIPUSH 1 + | | ALOAD_1 + | | AASTORE + | | NEW HelloWorld$AjcClosure3 + | | DUP + | | ALOAD 4 + | | INVOKESPECIAL HelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | POP + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static final void println_aroundBody0(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 9) + RETURN + end static final void println_aroundBody0(java.io.PrintStream, String) + + static final void println_aroundBody2(java.io.PrintStream, String): + INVOKESTATIC Aspect.ajc_before_method_execution ()V + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW HelloWorld$AjcClosure1 + DUP + ALOAD_2 + INVOKESPECIAL HelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + POP + RETURN + end static final void println_aroundBody2(java.io.PrintStream, String) +end public class HelloWorld + +public class HelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC HelloWorld.println_aroundBody0 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure1 + +public class HelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC HelloWorld.println_aroundBody2 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure3 diff --git a/weaver/testdata/AroundArgsDynamicHelloWorld.txt b/weaver/testdata/AroundArgsDynamicHelloWorld.txt new file mode 100644 index 000000000..5ca21c9b5 --- /dev/null +++ b/weaver/testdata/AroundArgsDynamicHelloWorld.txt @@ -0,0 +1,133 @@ +public class DynamicHelloWorld extends java.lang.Object implements java.io.Serializable: + public void <init>(): + ALOAD_0 // DynamicHelloWorld this (line 8) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void DynamicHelloWorld.<init>()) + | RETURN + constructor-execution(void DynamicHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + | catch java.lang.UnsupportedOperationException -> E0 + | | NEW DynamicHelloWorld (line 12) + | | DUP + | | constructor-call(void DynamicHelloWorld.<init>()) + | | | INVOKESPECIAL DynamicHelloWorld.<init> ()V + | | constructor-call(void DynamicHelloWorld.<init>()) + | | LDC "hello" + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | | GETSTATIC java.util.Collections.EMPTY_LIST Ljava/util/List; + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | | INVOKEVIRTUAL DynamicHelloWorld.doit (Ljava/lang/String;Ljava/util/List;)Ljava/lang/String; + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | POP + | | GOTO L0 + | catch java.lang.UnsupportedOperationException -> E0 + | E0: ASTORE_1 (line 13) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 14) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | LDC "expected and caught: " + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ALOAD_1 // java.lang.UnsupportedOperationException t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 15) + | L0: NEW java.lang.RuntimeException (line 17) + | DUP + | LDC "should have caught exception" + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.RuntimeException.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | ATHROW + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + String doit(String, java.util.List): + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | ALOAD_2 // java.util.List l (line 21) + | ALOAD_1 // java.lang.String arg0 + | ASTORE_3 + | ASTORE 4 + | method-call(boolean java.util.List.add(java.lang.Object)) + | | ALOAD 4 + | | INSTANCEOF java.util.ArrayList + | | IFEQ L0 + | | ALOAD 4 + | | CHECKCAST java.util.ArrayList + | | BIPUSH 2 + | | ANEWARRAY java.lang.Object + | | ASTORE 5 + | | ALOAD 5 + | | BIPUSH 0 + | | ALOAD 4 + | | AASTORE + | | ALOAD 5 + | | BIPUSH 1 + | | ALOAD_3 + | | AASTORE + | | NEW DynamicHelloWorld$AjcClosure1 + | | DUP + | | ALOAD 5 + | | INVOKESPECIAL DynamicHelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + | | INVOKESTATIC Aspect.ajc_around0 (Ljava/util/ArrayList;Lorg/aspectj/runtime/internal/AroundClosure;)Z + | | GOTO L1 + | | L0: ALOAD 4 + | | ALOAD_3 + | | INVOKESTATIC DynamicHelloWorld.add_aroundBody0 (Ljava/util/List;Ljava/lang/Object;)Z + | | L1: NOP + | method-call(boolean java.util.List.add(java.lang.Object)) + | POP + | ALOAD_2 // java.util.List l (line 22) + | method-call(java.lang.String java.lang.Object.toString()) + | | INVOKEVIRTUAL java.lang.Object.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.Object.toString()) + | ARETURN + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + end String doit(String, java.util.List) + + static final boolean add_aroundBody0(java.util.List, Object): + ALOAD_0 + ALOAD_1 + INVOKEINTERFACE java.util.List.add (Ljava/lang/Object;)Z (line 21) + IRETURN + end static final boolean add_aroundBody0(java.util.List, Object) +end public class DynamicHelloWorld + +public class DynamicHelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_1 + BIPUSH 0 + AALOAD + CHECKCAST java.util.List + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC DynamicHelloWorld.add_aroundBody0 (Ljava/util/List;Ljava/lang/Object;)Z + INVOKESTATIC org.aspectj.runtime.internal.Conversions.booleanObject (Z)Ljava/lang/Object; + ARETURN + end public Object run(Object[]) +end public class DynamicHelloWorld$AjcClosure1 diff --git a/weaver/testdata/AroundFancyHelloWorld.txt b/weaver/testdata/AroundFancyHelloWorld.txt new file mode 100644 index 000000000..f558cb548 --- /dev/null +++ b/weaver/testdata/AroundFancyHelloWorld.txt @@ -0,0 +1,229 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | ASTORE 5 + | | | ASTORE 6 + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | BIPUSH 2 + | | | | ANEWARRAY java.lang.Object + | | | | ASTORE 7 + | | | | ALOAD 7 + | | | | BIPUSH 0 + | | | | ALOAD 6 + | | | | AASTORE + | | | | ALOAD 7 + | | | | BIPUSH 1 + | | | | ALOAD 5 + | | | | AASTORE + | | | | NEW FancyHelloWorld$AjcClosure1 + | | | | DUP + | | | | ALOAD 7 + | | | | INVOKESPECIAL FancyHelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + | | | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | | | POP + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | ASTORE 8 + | | ASTORE 9 + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | BIPUSH 2 + | | | ANEWARRAY java.lang.Object + | | | ASTORE 10 + | | | ALOAD 10 + | | | BIPUSH 0 + | | | ALOAD 9 + | | | AASTORE + | | | ALOAD 10 + | | | BIPUSH 1 + | | | ALOAD 8 + | | | AASTORE + | | | NEW FancyHelloWorld$AjcClosure3 + | | | DUP + | | | ALOAD 10 + | | | INVOKESPECIAL FancyHelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | | POP + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | ASTORE 11 + | ASTORE 12 + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | BIPUSH 2 + | | ANEWARRAY java.lang.Object + | | ASTORE 13 + | | ALOAD 13 + | | BIPUSH 0 + | | ALOAD 12 + | | AASTORE + | | ALOAD 13 + | | BIPUSH 1 + | | ALOAD 11 + | | AASTORE + | | NEW FancyHelloWorld$AjcClosure5 + | | DUP + | | ALOAD 13 + | | INVOKESPECIAL FancyHelloWorld$AjcClosure5.<init> ([Ljava/lang/Object;)V + | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | POP + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() + + static final void println_aroundBody0(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 11) + RETURN + end static final void println_aroundBody0(java.io.PrintStream, String) + + static final void println_aroundBody2(java.io.PrintStream, Object): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V (line 13) + RETURN + end static final void println_aroundBody2(java.io.PrintStream, Object) + + static final void println_aroundBody4(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 15) + RETURN + end static final void println_aroundBody4(java.io.PrintStream, String) +end public abstract class FancyHelloWorld + +public class FancyHelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody0 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure1 + +public class FancyHelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + INVOKESTATIC FancyHelloWorld.println_aroundBody2 (Ljava/io/PrintStream;Ljava/lang/Object;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure3 + +public class FancyHelloWorld$AjcClosure5 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC FancyHelloWorld.println_aroundBody4 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class FancyHelloWorld$AjcClosure5 diff --git a/weaver/testdata/AroundHelloWorld.txt b/weaver/testdata/AroundHelloWorld.txt new file mode 100644 index 000000000..dcddb75fa --- /dev/null +++ b/weaver/testdata/AroundHelloWorld.txt @@ -0,0 +1,73 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | ASTORE_1 + | ASTORE_2 + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | BIPUSH 2 + | | ANEWARRAY java.lang.Object + | | ASTORE_3 + | | ALOAD_3 + | | BIPUSH 0 + | | ALOAD_2 + | | AASTORE + | | ALOAD_3 + | | BIPUSH 1 + | | ALOAD_1 + | | AASTORE + | | NEW HelloWorld$AjcClosure1 + | | DUP + | | ALOAD_3 + | | INVOKESPECIAL HelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + | | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | | POP + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static final void println_aroundBody0(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 9) + RETURN + end static final void println_aroundBody0(java.io.PrintStream, String) +end public class HelloWorld + +public class HelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + INVOKESTATIC HelloWorld.println_aroundBody0 (Ljava/io/PrintStream;Ljava/lang/String;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure1 diff --git a/weaver/testdata/BeforeFancyHelloWorld.txt b/weaver/testdata/BeforeFancyHelloWorld.txt new file mode 100644 index 000000000..18136b693 --- /dev/null +++ b/weaver/testdata/BeforeFancyHelloWorld.txt @@ -0,0 +1,90 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | INVOKESTATIC Aspect.ajc_before_constructor_execution ()V + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | field-get(java.io.PrintStream java.lang.System.out) + | | INVOKESTATIC Aspect.ajc_before_field_get ()V + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | LDC "name" (line 22) + | ASTORE_1 + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESTATIC Aspect.ajc_before_constructor_call ()V + | | NEW java.lang.StringBuffer + | | DUP + | | ALOAD_1 + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/BeforeHelloWorld.txt b/weaver/testdata/BeforeHelloWorld.txt new file mode 100644 index 000000000..3fc3fa818 --- /dev/null +++ b/weaver/testdata/BeforeHelloWorld.txt @@ -0,0 +1,26 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | INVOKESTATIC Aspect.ajc_before_constructor_execution ()V + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | field-get(java.io.PrintStream java.lang.System.out) + | | INVOKESTATIC Aspect.ajc_before_field_get ()V + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/CflowNonStaticBeforeFancyHelloWorld.txt b/weaver/testdata/CflowNonStaticBeforeFancyHelloWorld.txt new file mode 100644 index 000000000..cb71eca4b --- /dev/null +++ b/weaver/testdata/CflowNonStaticBeforeFancyHelloWorld.txt @@ -0,0 +1,92 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | INVOKESTATIC Aspect.ajc$perCflowPush ()V + | catch java.lang.Throwable -> E2 + | | field-get(java.io.PrintStream java.lang.System.out) + | | | INVOKESTATIC Aspect.hasAspect ()Z + | | | IFEQ L0 + | | | INVOKESTATIC Aspect.aspectOf ()LAspect; + | | | INVOKEVIRTUAL Aspect.ajc_before ()V + | | | L0: GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | | field-get(java.io.PrintStream java.lang.System.out) + | | ASTORE_1 + | | finally -> E1 + | | | catch java.lang.Exception -> E0 + | | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | | LDC "bye" + | | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | GOTO L1 + | | | catch java.lang.Exception -> E0 + | | | E0: ASTORE_2 (line 12) + | | | ALOAD_1 // java.io.PrintStream out (line 13) + | | | ALOAD_2 // java.lang.Exception e + | | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | finally -> E1 + | | GOTO L1 + | | E1: ASTORE 4 (line 14) + | | JSR L2 + | | ALOAD 4 + | | ATHROW + | | L1: JSR L2 + | | GOTO L3 + | | L2: ASTORE_3 + | | ALOAD_1 // java.io.PrintStream out (line 15) + | | LDC "finally" + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | RET 3 (line 10) + | | L3: GOTO L4 (line 17) + | catch java.lang.Throwable -> E2 + | E2: ASTORE 6 + | GETSTATIC Aspect.ajc$perCflowStack Lorg/aspectj/runtime/internal/CFlowStack; + | INVOKEVIRTUAL org.aspectj.runtime.internal.CFlowStack.pop ()V + | ALOAD 6 + | ATHROW + | L4: GETSTATIC Aspect.ajc$perCflowStack Lorg/aspectj/runtime/internal/CFlowStack; + | INVOKEVIRTUAL org.aspectj.runtime.internal.CFlowStack.pop ()V + | RETURN + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/CflowNonStaticBeforeHelloWorld.txt b/weaver/testdata/CflowNonStaticBeforeHelloWorld.txt new file mode 100644 index 000000000..a2a9d3cc0 --- /dev/null +++ b/weaver/testdata/CflowNonStaticBeforeHelloWorld.txt @@ -0,0 +1,37 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | INVOKESTATIC Aspect.ajc$perCflowPush ()V + | catch java.lang.Throwable -> E0 + | | field-get(java.io.PrintStream java.lang.System.out) + | | | INVOKESTATIC Aspect.hasAspect ()Z + | | | IFEQ L0 + | | | INVOKESTATIC Aspect.aspectOf ()LAspect; + | | | INVOKEVIRTUAL Aspect.ajc_before ()V + | | | L0: GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | | field-get(java.io.PrintStream java.lang.System.out) + | | LDC "hello world" (line 9) + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | GOTO L1 (line 11) + | catch java.lang.Throwable -> E0 + | E0: ASTORE_2 + | GETSTATIC Aspect.ajc$perCflowStack Lorg/aspectj/runtime/internal/CFlowStack; + | INVOKEVIRTUAL org.aspectj.runtime.internal.CFlowStack.pop ()V + | ALOAD_2 + | ATHROW + | L1: GETSTATIC Aspect.ajc$perCflowStack Lorg/aspectj/runtime/internal/CFlowStack; + | INVOKEVIRTUAL org.aspectj.runtime.internal.CFlowStack.pop ()V + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/CflowStateResidueDynamicHelloWorld.txt b/weaver/testdata/CflowStateResidueDynamicHelloWorld.txt new file mode 100644 index 000000000..fd6bfd650 --- /dev/null +++ b/weaver/testdata/CflowStateResidueDynamicHelloWorld.txt @@ -0,0 +1,119 @@ +public class DynamicHelloWorld extends java.lang.Object implements java.io.Serializable: + public void <init>(): + ALOAD_0 // DynamicHelloWorld this (line 8) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void DynamicHelloWorld.<init>()) + | RETURN + constructor-execution(void DynamicHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + | GETSTATIC Aspect.ajc$cflowStack$0 Lorg/aspectj/runtime/internal/CFlowStack; + | INVOKEVIRTUAL org.aspectj.runtime.internal.CFlowStack.isValid ()Z + | IFEQ L0 + | GETSTATIC Aspect.ajc$cflowStack$0 Lorg/aspectj/runtime/internal/CFlowStack; + | BIPUSH 0 + | INVOKEVIRTUAL org.aspectj.runtime.internal.CFlowStack.get (I)Ljava/lang/Object; + | CHECKCAST java.util.ArrayList + | INVOKESTATIC Aspect.ajc_before_0 (Ljava/util/ArrayList;)V + | catch java.lang.UnsupportedOperationException -> E0 + | | L0: NEW DynamicHelloWorld (line 12) + | | DUP + | | constructor-call(void DynamicHelloWorld.<init>()) + | | | INVOKESPECIAL DynamicHelloWorld.<init> ()V + | | constructor-call(void DynamicHelloWorld.<init>()) + | | LDC "hello" + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | | GETSTATIC java.util.Collections.EMPTY_LIST Ljava/util/List; + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | | INVOKEVIRTUAL DynamicHelloWorld.doit (Ljava/lang/String;Ljava/util/List;)Ljava/lang/String; + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | POP + | | GOTO L1 + | catch java.lang.UnsupportedOperationException -> E0 + | E0: ASTORE_1 (line 13) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 14) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | LDC "expected and caught: " + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ALOAD_1 // java.lang.UnsupportedOperationException t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 15) + | L1: NEW java.lang.RuntimeException (line 17) + | DUP + | LDC "should have caught exception" + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.RuntimeException.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | ATHROW + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + String doit(String, java.util.List): + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | ALOAD_2 // java.util.List l (line 21) + | ALOAD_1 // java.lang.String arg0 + | ASTORE_3 + | ASTORE 4 + | method-call(boolean java.util.List.add(java.lang.Object)) + | | BIPUSH 0 + | | ISTORE 5 + | | ALOAD 4 + | | INSTANCEOF java.util.ArrayList + | | IFEQ L0 + | | BIPUSH 1 + | | ISTORE 5 + | | BIPUSH 1 + | | ANEWARRAY java.lang.Object + | | ASTORE 6 + | | ALOAD 6 + | | BIPUSH 0 + | | ALOAD 4 + | | AASTORE + | | GETSTATIC Aspect.ajc$cflowStack$0 Lorg/aspectj/runtime/internal/CFlowStack; + | | ALOAD 6 + | | INVOKEVIRTUAL org.aspectj.runtime.internal.CFlowStack.push ([Ljava/lang/Object;)V + | | catch java.lang.Throwable -> E0 + | | | L0: ALOAD 4 + | | | ALOAD_3 + | | | INVOKEINTERFACE java.util.List.add (Ljava/lang/Object;)Z + | | catch java.lang.Throwable -> E0 + | | GOTO L2 + | | E0: ASTORE 7 + | | ILOAD 5 + | | IFEQ L1 + | | GETSTATIC Aspect.ajc$cflowStack$0 Lorg/aspectj/runtime/internal/CFlowStack; + | | INVOKEVIRTUAL org.aspectj.runtime.internal.CFlowStack.pop ()V + | | L1: ALOAD 7 + | | ATHROW + | | L2: NOP + | | ILOAD 5 + | | IFEQ L3 + | | GETSTATIC Aspect.ajc$cflowStack$0 Lorg/aspectj/runtime/internal/CFlowStack; + | | INVOKEVIRTUAL org.aspectj.runtime.internal.CFlowStack.pop ()V + | | L3: NOP + | method-call(boolean java.util.List.add(java.lang.Object)) + | POP + | ALOAD_2 // java.util.List l (line 22) + | method-call(java.lang.String java.lang.Object.toString()) + | | INVOKEVIRTUAL java.lang.Object.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.Object.toString()) + | ARETURN + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + end String doit(String, java.util.List) +end public class DynamicHelloWorld diff --git a/weaver/testdata/ExtractedFancyHelloWorld.txt b/weaver/testdata/ExtractedFancyHelloWorld.txt new file mode 100644 index 000000000..378da90b8 --- /dev/null +++ b/weaver/testdata/ExtractedFancyHelloWorld.txt @@ -0,0 +1,169 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | ALOAD_0 + | INVOKESTATIC FancyHelloWorld.init$_extracted0 (LFancyHelloWorld;)V + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE 11 + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | ALOAD 11 + | INVOKESTATIC FancyHelloWorld.main_extracted5 ([Ljava/lang/String;)V + | RETURN + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | INVOKESTATIC FancyHelloWorld.getName_extracted10 ()Ljava/lang/String; + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() + + static final void init$_extracted0(FancyHelloWorld): + RETURN (line 7) + end static final void init$_extracted0(FancyHelloWorld) + + static final java.io.PrintStream out_extracted1(): + GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + ARETURN + end static final java.io.PrintStream out_extracted1() + + static final void println_extracted2(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 11) + RETURN + end static final void println_extracted2(java.io.PrintStream, String) + + static final void println_extracted3(java.io.PrintStream, Object): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V (line 13) + RETURN + end static final void println_extracted3(java.io.PrintStream, Object) + + static final void println_extracted4(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 15) + RETURN + end static final void println_extracted4(java.io.PrintStream, String) + + static final void main_extracted5(String[]): + field-get(java.io.PrintStream java.lang.System.out) + | INVOKESTATIC FancyHelloWorld.out_extracted1 ()Ljava/io/PrintStream; + field-get(java.io.PrintStream java.lang.System.out) + ASTORE_1 (line 9) + finally -> E1 + | catch java.lang.Exception -> E0 + | | ALOAD_1 (line 11) + | | LDC "bye" + | | ASTORE_3 + | | ASTORE 5 + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | ALOAD 5 + | | | ALOAD_3 + | | | INVOKESTATIC FancyHelloWorld.println_extracted2 (Ljava/io/PrintStream;Ljava/lang/String;)V + | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | GOTO L0 + | catch java.lang.Exception -> E0 + | E0: ASTORE 7 (line 12) + | ALOAD_1 (line 13) + | ALOAD 7 + | ASTORE 9 + | ASTORE 11 + | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | ALOAD 11 + | | ALOAD 9 + | | INVOKESTATIC FancyHelloWorld.println_extracted3 (Ljava/io/PrintStream;Ljava/lang/Object;)V + | method-call(void java.io.PrintStream.println(java.lang.Object)) + finally -> E1 + GOTO L0 + E1: ASTORE 13 (line 14) + JSR L1 + ALOAD 13 + ATHROW + L0: JSR L1 + GOTO L2 + L1: ASTORE 15 + ALOAD_1 (line 15) + LDC "finally" + ASTORE 17 + ASTORE 19 + method-call(void java.io.PrintStream.println(java.lang.String)) + | ALOAD 19 + | ALOAD 17 + | INVOKESTATIC FancyHelloWorld.println_extracted4 (Ljava/io/PrintStream;Ljava/lang/String;)V + method-call(void java.io.PrintStream.println(java.lang.String)) + RET 15 (line 10) + L2: RETURN (line 17) + end static final void main_extracted5(String[]) + + static final int hashCode_extracted6(String): + ALOAD_0 + INVOKEVIRTUAL java.lang.String.hashCode ()I (line 21) + IRETURN + end static final int hashCode_extracted6(String) + + static final StringBuffer init$_extracted7(String): + NEW java.lang.StringBuffer + DUP + ALOAD_0 + INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V (line 22) + ARETURN + end static final StringBuffer init$_extracted7(String) + + static final StringBuffer append_extracted8(StringBuffer, int): + ALOAD_0 + ILOAD_1 + INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; (line 22) + ARETURN + end static final StringBuffer append_extracted8(StringBuffer, int) + + static final String toString_extracted9(StringBuffer): + ALOAD_0 + INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; (line 22) + ARETURN + end static final String toString_extracted9(StringBuffer) + + static final String getName_extracted10(): + ICONST_0 (line 20) + ISTORE_0 + ILOAD_0 (line 21) + LDC "name" + ASTORE_2 + method-call(int java.lang.String.hashCode()) + | ALOAD_2 + | INVOKESTATIC FancyHelloWorld.hashCode_extracted6 (Ljava/lang/String;)I + method-call(int java.lang.String.hashCode()) + IADD + ISTORE_0 + LDC "name" (line 22) + ASTORE 4 + constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ALOAD 4 + | INVOKESTATIC FancyHelloWorld.init$_extracted7 (Ljava/lang/String;)Ljava/lang/StringBuffer; + constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + ILOAD_0 + ISTORE 6 + ASTORE 8 + method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | ALOAD 8 + | ILOAD 6 + | INVOKESTATIC FancyHelloWorld.append_extracted8 (Ljava/lang/StringBuffer;I)Ljava/lang/StringBuffer; + method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + ASTORE 10 + method-call(java.lang.String java.lang.StringBuffer.toString()) + | ALOAD 10 + | INVOKESTATIC FancyHelloWorld.toString_extracted9 (Ljava/lang/StringBuffer;)Ljava/lang/String; + method-call(java.lang.String java.lang.StringBuffer.toString()) + ARETURN + end static final String getName_extracted10() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/ExtractedHelloWorld.txt b/weaver/testdata/ExtractedHelloWorld.txt new file mode 100644 index 000000000..7ac93cbef --- /dev/null +++ b/weaver/testdata/ExtractedHelloWorld.txt @@ -0,0 +1,52 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | ALOAD_0 + | INVOKESTATIC HelloWorld.init$_extracted (LHelloWorld;)V + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE_3 + method-execution(void HelloWorld.main(java.lang.String[])) + | ALOAD_3 + | INVOKESTATIC HelloWorld.main_extracted ([Ljava/lang/String;)V + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static final void init$_extracted(HelloWorld): + RETURN (line 5) + end static final void init$_extracted(HelloWorld) + + static final java.io.PrintStream out_extracted(): + GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + ARETURN + end static final java.io.PrintStream out_extracted() + + static final void println_extracted(java.io.PrintStream, String): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 9) + RETURN + end static final void println_extracted(java.io.PrintStream, String) + + static final void main_extracted(String[]): + field-get(java.io.PrintStream java.lang.System.out) + | INVOKESTATIC HelloWorld.out_extracted ()Ljava/io/PrintStream; + field-get(java.io.PrintStream java.lang.System.out) + LDC "hello world" (line 9) + ASTORE_1 + ASTORE_3 + method-call(void java.io.PrintStream.println(java.lang.String)) + | ALOAD_3 + | ALOAD_1 + | INVOKESTATIC HelloWorld.println_extracted (Ljava/io/PrintStream;Ljava/lang/String;)V + method-call(void java.io.PrintStream.println(java.lang.String)) + RETURN (line 11) + end static final void main_extracted(String[]) +end public class HelloWorld diff --git a/weaver/testdata/FieldSet.txt b/weaver/testdata/FieldSet.txt new file mode 100644 index 000000000..c89c7e7bc --- /dev/null +++ b/weaver/testdata/FieldSet.txt @@ -0,0 +1,68 @@ +public class FieldyHelloWorld extends java.lang.Object: + public static String str + static void <clinit>(): + staticinitialization(void FieldyHelloWorld.<clinit>()) + | LDC "Hello" (line 3) + | field-set(java.lang.String FieldyHelloWorld.str) + | | PUTSTATIC FieldyHelloWorld.str Ljava/lang/String; + | field-set(java.lang.String FieldyHelloWorld.str) + | RETURN (line 1) + staticinitialization(void FieldyHelloWorld.<clinit>()) + end static void <clinit>() + + public void <init>(): + ALOAD_0 // FieldyHelloWorld this (line 1) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FieldyHelloWorld.<init>()) + | INVOKESTATIC Aspect.ajc_before_constructor_execution ()V + | RETURN + constructor-execution(void FieldyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FieldyHelloWorld.main(java.lang.String[])) + | INVOKESTATIC Aspect.ajc_before_method_execution ()V + | field-get(java.lang.String FieldyHelloWorld.str) + | | INVOKESTATIC Aspect.ajc_before_field_get ()V + | | GETSTATIC FieldyHelloWorld.str Ljava/lang/String; (line 6) + | field-get(java.lang.String FieldyHelloWorld.str) + | method-call(java.lang.String java.lang.String.valueOf(java.lang.Object)) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | INVOKESTATIC java.lang.String.valueOf (Ljava/lang/Object;)Ljava/lang/String; + | method-call(java.lang.String java.lang.String.valueOf(java.lang.Object)) + | ASTORE_1 + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESTATIC Aspect.ajc_before_constructor_call ()V + | | NEW java.lang.StringBuffer + | | DUP + | | ALOAD_1 + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | LDC " World" + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/String;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | field-set(java.lang.String FieldyHelloWorld.str) + | | PUTSTATIC FieldyHelloWorld.str Ljava/lang/String; + | field-set(java.lang.String FieldyHelloWorld.str) + | field-get(java.io.PrintStream java.lang.System.out) + | | INVOKESTATIC Aspect.ajc_before_field_get ()V + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | field-get(java.lang.String FieldyHelloWorld.str) + | | INVOKESTATIC Aspect.ajc_before_field_get ()V + | | GETSTATIC FieldyHelloWorld.str Ljava/lang/String; + | field-get(java.lang.String FieldyHelloWorld.str) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKESTATIC Aspect.ajc_before_method_call ()V + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 9) + method-execution(void FieldyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class FieldyHelloWorld diff --git a/weaver/testdata/IdDummyAspect.txt b/weaver/testdata/IdDummyAspect.txt new file mode 100644 index 000000000..17ec9dac5 --- /dev/null +++ b/weaver/testdata/IdDummyAspect.txt @@ -0,0 +1,16 @@ +public abstract class DummyAspect extends java.lang.Object: + public void <init>(): + ALOAD_0 // DummyAspect this (line 1) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void DummyAspect.<init>()) + | RETURN + constructor-execution(void DummyAspect.<init>()) + end public void <init>() + + public void ajc$before$DummyAspect$57(Object) AdviceAttribute(before, traced(BindingTypePattern(java.lang.Object, 0)), 0, 87) +: + advice-execution(void DummyAspect.ajc$before$DummyAspect$57(java.lang.Object)) + | RETURN (line 5) + advice-execution(void DummyAspect.ajc$before$DummyAspect$57(java.lang.Object)) + end public void ajc$before$DummyAspect$57(Object) +end public abstract class DummyAspect diff --git a/weaver/testdata/IdFancyHelloWorld.txt b/weaver/testdata/IdFancyHelloWorld.txt new file mode 100644 index 000000000..86d44a554 --- /dev/null +++ b/weaver/testdata/IdFancyHelloWorld.txt @@ -0,0 +1,77 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/IdHelloWorld.txt b/weaver/testdata/IdHelloWorld.txt new file mode 100644 index 000000000..dfd6deff9 --- /dev/null +++ b/weaver/testdata/IdHelloWorld.txt @@ -0,0 +1,22 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/NoResidueDynamicHelloWorld.txt b/weaver/testdata/NoResidueDynamicHelloWorld.txt new file mode 100644 index 000000000..9ae90cc05 --- /dev/null +++ b/weaver/testdata/NoResidueDynamicHelloWorld.txt @@ -0,0 +1,75 @@ +public class DynamicHelloWorld extends java.lang.Object implements java.io.Serializable: + public void <init>(): + ALOAD_0 // DynamicHelloWorld this (line 8) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void DynamicHelloWorld.<init>()) + | RETURN + constructor-execution(void DynamicHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + | catch java.lang.UnsupportedOperationException -> E0 + | | NEW DynamicHelloWorld (line 12) + | | DUP + | | constructor-call(void DynamicHelloWorld.<init>()) + | | | INVOKESPECIAL DynamicHelloWorld.<init> ()V + | | constructor-call(void DynamicHelloWorld.<init>()) + | | LDC "hello" + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | | GETSTATIC java.util.Collections.EMPTY_LIST Ljava/util/List; + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | | INVOKEVIRTUAL DynamicHelloWorld.doit (Ljava/lang/String;Ljava/util/List;)Ljava/lang/String; + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | POP + | | GOTO L0 + | catch java.lang.UnsupportedOperationException -> E0 + | E0: ASTORE_1 (line 13) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 14) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | LDC "expected and caught: " + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ALOAD_1 // java.lang.UnsupportedOperationException t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 15) + | L0: NEW java.lang.RuntimeException (line 17) + | DUP + | LDC "should have caught exception" + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.RuntimeException.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | ATHROW + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + String doit(String, java.util.List): + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | ALOAD_2 // java.util.List l (line 21) + | ALOAD_1 // java.lang.String arg0 + | method-call(boolean java.util.List.add(java.lang.Object)) + | | INVOKESTATIC Aspect.ajc_before_0 ()V + | | INVOKEINTERFACE java.util.List.add (Ljava/lang/Object;)Z + | method-call(boolean java.util.List.add(java.lang.Object)) + | POP + | ALOAD_2 // java.util.List l (line 22) + | method-call(java.lang.String java.lang.Object.toString()) + | | INVOKEVIRTUAL java.lang.Object.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.Object.toString()) + | ARETURN + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + end String doit(String, java.util.List) +end public class DynamicHelloWorld diff --git a/weaver/testdata/NonStaticBeforeFancyHelloWorld.txt b/weaver/testdata/NonStaticBeforeFancyHelloWorld.txt new file mode 100644 index 000000000..84821964a --- /dev/null +++ b/weaver/testdata/NonStaticBeforeFancyHelloWorld.txt @@ -0,0 +1,79 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC Aspect.ajc$perSingletonInstance LAspect; + | | INVOKEVIRTUAL Aspect.ajc_before ()V + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/NonStaticBeforeHelloWorld.txt b/weaver/testdata/NonStaticBeforeHelloWorld.txt new file mode 100644 index 000000000..2786f0844 --- /dev/null +++ b/weaver/testdata/NonStaticBeforeHelloWorld.txt @@ -0,0 +1,24 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC Aspect.ajc$perSingletonInstance LAspect; + | | INVOKEVIRTUAL Aspect.ajc_before ()V + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/PatternWeaveFancyHelloWorld.txt b/weaver/testdata/PatternWeaveFancyHelloWorld.txt new file mode 100644 index 000000000..86d44a554 --- /dev/null +++ b/weaver/testdata/PatternWeaveFancyHelloWorld.txt @@ -0,0 +1,77 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L0 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L0 + | E1: ASTORE 4 (line 14) + | JSR L1 + | ALOAD 4 + | ATHROW + | L0: JSR L1 + | GOTO L2 + | L1: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L2: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/PatternWeaveHelloWorld.txt b/weaver/testdata/PatternWeaveHelloWorld.txt new file mode 100644 index 000000000..dfd6deff9 --- /dev/null +++ b/weaver/testdata/PatternWeaveHelloWorld.txt @@ -0,0 +1,22 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/PerSingletonField.txt b/weaver/testdata/PerSingletonField.txt new file mode 100644 index 000000000..4837c6569 --- /dev/null +++ b/weaver/testdata/PerSingletonField.txt @@ -0,0 +1,22 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + RETURN + end public void <init>() + + public static void main(String[]): + GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + LDC "hello world" (line 9) + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + RETURN (line 11) + end public static void main(String[]) + + static void <clinit>(): + NEW HelloWorld + DUP + INVOKESPECIAL HelloWorld.<init> ()V + PUTSTATIC HelloWorld.ajc$perSingletonInstance LHelloWorld; + RETURN + end static void <clinit>() +end public class HelloWorld diff --git a/weaver/testdata/PerThisNonStaticBeforeFancyHelloWorld.txt b/weaver/testdata/PerThisNonStaticBeforeFancyHelloWorld.txt new file mode 100644 index 000000000..5155ab6d7 --- /dev/null +++ b/weaver/testdata/PerThisNonStaticBeforeFancyHelloWorld.txt @@ -0,0 +1,113 @@ +public abstract class FancyHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // FancyHelloWorld this (line 7) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void FancyHelloWorld.<init>()) + | RETURN + constructor-execution(void FancyHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void FancyHelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 9) + | field-get(java.io.PrintStream java.lang.System.out) + | ASTORE_1 + | finally -> E1 + | | catch java.lang.Exception -> E0 + | | | ALOAD_1 // java.io.PrintStream out (line 11) + | | | LDC "bye" + | | | ASTORE 5 + | | | ASTORE 6 + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | | ALOAD 6 + | | | | INVOKESTATIC Aspect.ajc$perObjectBind (Ljava/lang/Object;)V + | | | | ALOAD 6 + | | | | INVOKESTATIC Aspect.hasAspect (Ljava/lang/Object;)Z + | | | | IFEQ L0 + | | | | ALOAD 6 + | | | | INVOKESTATIC Aspect.aspectOf (Ljava/lang/Object;)LAspect; + | | | | INVOKEVIRTUAL Aspect.ajc_before ()V + | | | | L0: ALOAD 6 + | | | | ALOAD 5 + | | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | | | method-call(void java.io.PrintStream.println(java.lang.String)) + | | | GOTO L2 + | | catch java.lang.Exception -> E0 + | | E0: ASTORE_2 (line 12) + | | ALOAD_1 // java.io.PrintStream out (line 13) + | | ALOAD_2 // java.lang.Exception e + | | ASTORE 7 + | | ASTORE 8 + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | | | ALOAD 8 + | | | INVOKESTATIC Aspect.ajc$perObjectBind (Ljava/lang/Object;)V + | | | ALOAD 8 + | | | INVOKESTATIC Aspect.hasAspect (Ljava/lang/Object;)Z + | | | IFEQ L1 + | | | ALOAD 8 + | | | INVOKESTATIC Aspect.aspectOf (Ljava/lang/Object;)LAspect; + | | | INVOKEVIRTUAL Aspect.ajc_before ()V + | | | L1: ALOAD 8 + | | | ALOAD 7 + | | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/Object;)V + | | method-call(void java.io.PrintStream.println(java.lang.Object)) + | finally -> E1 + | GOTO L2 + | E1: ASTORE 4 (line 14) + | JSR L3 + | ALOAD 4 + | ATHROW + | L2: JSR L3 + | GOTO L5 + | L3: ASTORE_3 + | ALOAD_1 // java.io.PrintStream out (line 15) + | LDC "finally" + | ASTORE 9 + | ASTORE 10 + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | ALOAD 10 + | | INVOKESTATIC Aspect.ajc$perObjectBind (Ljava/lang/Object;)V + | | ALOAD 10 + | | INVOKESTATIC Aspect.hasAspect (Ljava/lang/Object;)Z + | | IFEQ L4 + | | ALOAD 10 + | | INVOKESTATIC Aspect.aspectOf (Ljava/lang/Object;)LAspect; + | | INVOKEVIRTUAL Aspect.ajc_before ()V + | | L4: ALOAD 10 + | | ALOAD 9 + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RET 3 (line 10) + | L5: RETURN (line 17) + method-execution(void FancyHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + public static String getName(): + method-execution(java.lang.String FancyHelloWorld.getName()) + | ICONST_0 (line 20) + | ISTORE_0 + | ILOAD_0 // int x (line 21) + | LDC "name" + | method-call(int java.lang.String.hashCode()) + | | INVOKEVIRTUAL java.lang.String.hashCode ()I + | method-call(int java.lang.String.hashCode()) + | IADD + | ISTORE_0 // int x + | NEW java.lang.StringBuffer (line 22) + | DUP + | LDC "name" + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ILOAD_0 // int x + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (I)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | ARETURN + method-execution(java.lang.String FancyHelloWorld.getName()) + end public static String getName() +end public abstract class FancyHelloWorld diff --git a/weaver/testdata/PerThisNonStaticBeforeHelloWorld.txt b/weaver/testdata/PerThisNonStaticBeforeHelloWorld.txt new file mode 100644 index 000000000..7da847852 --- /dev/null +++ b/weaver/testdata/PerThisNonStaticBeforeHelloWorld.txt @@ -0,0 +1,34 @@ +public class HelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | ASTORE_1 + | ASTORE_2 + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | ALOAD_2 + | | INVOKESTATIC Aspect.ajc$perObjectBind (Ljava/lang/Object;)V + | | ALOAD_2 + | | INVOKESTATIC Aspect.hasAspect (Ljava/lang/Object;)Z + | | IFEQ L0 + | | ALOAD_2 + | | INVOKESTATIC Aspect.aspectOf (Ljava/lang/Object;)LAspect; + | | INVOKEVIRTUAL Aspect.ajc_before ()V + | | L0: ALOAD_2 + | | ALOAD_1 + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) +end public class HelloWorld diff --git a/weaver/testdata/Regex.jar b/weaver/testdata/Regex.jar Binary files differnew file mode 100644 index 000000000..713441c52 --- /dev/null +++ b/weaver/testdata/Regex.jar diff --git a/weaver/testdata/StateResidueMultiArgHelloWorld.txt b/weaver/testdata/StateResidueMultiArgHelloWorld.txt new file mode 100644 index 000000000..55cc92c3e --- /dev/null +++ b/weaver/testdata/StateResidueMultiArgHelloWorld.txt @@ -0,0 +1,62 @@ +public class MultiArgHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // MultiArgHelloWorld this (line 3) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void MultiArgHelloWorld.<init>()) + | RETURN + constructor-execution(void MultiArgHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void MultiArgHelloWorld.main(java.lang.String[])) + | LDC "Hello" (line 6) + | LDC "World" + | ASTORE_1 + | ASTORE_2 + | method-call(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | | ALOAD_2 + | | INSTANCEOF java.lang.String + | | IFEQ L0 + | | ALOAD_2 + | | CHECKCAST java.lang.String + | | INVOKESTATIC Aspect.ajc_before_0 (Ljava/lang/String;)V + | | L0: ALOAD_2 + | | ALOAD_1 + | | INVOKESTATIC MultiArgHelloWorld.foo (Ljava/lang/Object;Ljava/lang/Object;)V + | method-call(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | RETURN (line 7) + method-execution(void MultiArgHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static void foo(Object, Object): + method-execution(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 10) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | constructor-call(void java.lang.StringBuffer.<init>()) + | | INVOKESPECIAL java.lang.StringBuffer.<init> ()V + | constructor-call(void java.lang.StringBuffer.<init>()) + | ALOAD_0 // java.lang.Object arg0 + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | LDC " " + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/String;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | ALOAD_1 // java.lang.Object t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + end static void foo(Object, Object) +end public class MultiArgHelloWorld diff --git a/weaver/testdata/StaticEnclosingTjpBeforeHelloWorld.txt b/weaver/testdata/StaticEnclosingTjpBeforeHelloWorld.txt new file mode 100644 index 000000000..6d9ed99f5 --- /dev/null +++ b/weaver/testdata/StaticEnclosingTjpBeforeHelloWorld.txt @@ -0,0 +1,61 @@ +public class HelloWorld extends java.lang.Object: + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_0 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_1 + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | GETSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint$StaticPart;)V + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | GETSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint$StaticPart;)V + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + | | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint$StaticPart;)V + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | GETSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + | | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint$StaticPart;)V + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static void <clinit>(): + NEW org.aspectj.runtime.reflect.Factory + DUP + LDC "HelloWorld.java" + LDC "HelloWorld" + INVOKESTATIC java.lang.Class.forName (Ljava/lang/String;)Ljava/lang/Class; + INVOKESPECIAL org.aspectj.runtime.reflect.Factory.<init> (Ljava/lang/String;Ljava/lang/Class;)V + ASTORE_0 + ALOAD_0 + LDC "constructor-execution" + ALOAD_0 + LDC "1--HelloWorld----" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeConstructorSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/ConstructorSignature; + BIPUSH 5 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "method-execution" + ALOAD_0 + LDC "9-main-HelloWorld-[Ljava/lang/String;:-args:--void-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeMethodSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/MethodSignature; + BIPUSH 8 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + staticinitialization(void HelloWorld.<clinit>()) + | RETURN + staticinitialization(void HelloWorld.<clinit>()) + end static void <clinit>() +end public class HelloWorld diff --git a/weaver/testdata/StaticTjpBeforeHelloWorld.txt b/weaver/testdata/StaticTjpBeforeHelloWorld.txt new file mode 100644 index 000000000..3c248872d --- /dev/null +++ b/weaver/testdata/StaticTjpBeforeHelloWorld.txt @@ -0,0 +1,79 @@ +public class HelloWorld extends java.lang.Object: + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_0 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_1 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_2 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_3 + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void HelloWorld.<init>()) + | GETSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint$StaticPart;)V + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void HelloWorld.main(java.lang.String[])) + | GETSTATIC HelloWorld.ajc$tjp_3 Lorg/aspectj/lang/JoinPoint$StaticPart; + | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint$StaticPart;)V + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + | | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint$StaticPart;)V + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | GETSTATIC HelloWorld.ajc$tjp_2 Lorg/aspectj/lang/JoinPoint$StaticPart; + | | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint$StaticPart;)V + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static void <clinit>(): + NEW org.aspectj.runtime.reflect.Factory + DUP + LDC "HelloWorld.java" + LDC "HelloWorld" + INVOKESTATIC java.lang.Class.forName (Ljava/lang/String;)Ljava/lang/Class; + INVOKESPECIAL org.aspectj.runtime.reflect.Factory.<init> (Ljava/lang/String;Ljava/lang/Class;)V + ASTORE_0 + ALOAD_0 + LDC "constructor-execution" + ALOAD_0 + LDC "1--HelloWorld----" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeConstructorSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/ConstructorSignature; + BIPUSH 5 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "field-get" + ALOAD_0 + LDC "19-out-java.lang.System-java.io.PrintStream-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeFieldSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/FieldSignature; + BIPUSH 8 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "method-call" + ALOAD_0 + LDC "1-println-java.io.PrintStream-java.lang.String:-arg0:--void-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeMethodSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/MethodSignature; + BIPUSH 9 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_2 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "method-execution" + ALOAD_0 + LDC "9-main-HelloWorld-[Ljava/lang/String;:-args:--void-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeMethodSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/MethodSignature; + BIPUSH 8 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_3 Lorg/aspectj/lang/JoinPoint$StaticPart; + staticinitialization(void HelloWorld.<clinit>()) + | RETURN + staticinitialization(void HelloWorld.<clinit>()) + end static void <clinit>() +end public class HelloWorld diff --git a/weaver/testdata/StringResidue1MultiArgHelloWorld.txt b/weaver/testdata/StringResidue1MultiArgHelloWorld.txt new file mode 100644 index 000000000..ff1add1d2 --- /dev/null +++ b/weaver/testdata/StringResidue1MultiArgHelloWorld.txt @@ -0,0 +1,63 @@ +public class MultiArgHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // MultiArgHelloWorld this (line 3) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void MultiArgHelloWorld.<init>()) + | RETURN + constructor-execution(void MultiArgHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void MultiArgHelloWorld.main(java.lang.String[])) + | LDC "Hello" (line 6) + | LDC "World" + | ASTORE_1 + | ASTORE_2 + | method-call(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | | ALOAD_2 + | | INSTANCEOF java.lang.String + | | IFEQ L0 + | | ALOAD_1 + | | INSTANCEOF java.lang.String + | | IFEQ L0 + | | INVOKESTATIC Aspect.ajc_before_0 ()V + | | L0: ALOAD_2 + | | ALOAD_1 + | | INVOKESTATIC MultiArgHelloWorld.foo (Ljava/lang/Object;Ljava/lang/Object;)V + | method-call(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | RETURN (line 7) + method-execution(void MultiArgHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static void foo(Object, Object): + method-execution(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 10) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | constructor-call(void java.lang.StringBuffer.<init>()) + | | INVOKESPECIAL java.lang.StringBuffer.<init> ()V + | constructor-call(void java.lang.StringBuffer.<init>()) + | ALOAD_0 // java.lang.Object arg0 + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | LDC " " + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/String;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | ALOAD_1 // java.lang.Object t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + end static void foo(Object, Object) +end public class MultiArgHelloWorld diff --git a/weaver/testdata/StringResidue2MultiArgHelloWorld.txt b/weaver/testdata/StringResidue2MultiArgHelloWorld.txt new file mode 100644 index 000000000..8fb78655d --- /dev/null +++ b/weaver/testdata/StringResidue2MultiArgHelloWorld.txt @@ -0,0 +1,60 @@ +public class MultiArgHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // MultiArgHelloWorld this (line 3) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void MultiArgHelloWorld.<init>()) + | RETURN + constructor-execution(void MultiArgHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void MultiArgHelloWorld.main(java.lang.String[])) + | LDC "Hello" (line 6) + | LDC "World" + | ASTORE_1 + | ASTORE_2 + | method-call(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | | ALOAD_1 + | | INSTANCEOF java.lang.String + | | IFEQ L0 + | | INVOKESTATIC Aspect.ajc_before_0 ()V + | | L0: ALOAD_2 + | | ALOAD_1 + | | INVOKESTATIC MultiArgHelloWorld.foo (Ljava/lang/Object;Ljava/lang/Object;)V + | method-call(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | RETURN (line 7) + method-execution(void MultiArgHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static void foo(Object, Object): + method-execution(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 10) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | constructor-call(void java.lang.StringBuffer.<init>()) + | | INVOKESPECIAL java.lang.StringBuffer.<init> ()V + | constructor-call(void java.lang.StringBuffer.<init>()) + | ALOAD_0 // java.lang.Object arg0 + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | LDC " " + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/String;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | ALOAD_1 // java.lang.Object t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + end static void foo(Object, Object) +end public class MultiArgHelloWorld diff --git a/weaver/testdata/StringResidue3MultiArgHelloWorld.txt b/weaver/testdata/StringResidue3MultiArgHelloWorld.txt new file mode 100644 index 000000000..6c361581f --- /dev/null +++ b/weaver/testdata/StringResidue3MultiArgHelloWorld.txt @@ -0,0 +1,60 @@ +public class MultiArgHelloWorld extends java.lang.Object: + public void <init>(): + ALOAD_0 // MultiArgHelloWorld this (line 3) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void MultiArgHelloWorld.<init>()) + | RETURN + constructor-execution(void MultiArgHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void MultiArgHelloWorld.main(java.lang.String[])) + | LDC "Hello" (line 6) + | LDC "World" + | ASTORE_1 + | ASTORE_2 + | method-call(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | | ALOAD_2 + | | INSTANCEOF java.lang.String + | | IFEQ L0 + | | INVOKESTATIC Aspect.ajc_before_0 ()V + | | L0: ALOAD_2 + | | ALOAD_1 + | | INVOKESTATIC MultiArgHelloWorld.foo (Ljava/lang/Object;Ljava/lang/Object;)V + | method-call(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | RETURN (line 7) + method-execution(void MultiArgHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static void foo(Object, Object): + method-execution(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 10) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | constructor-call(void java.lang.StringBuffer.<init>()) + | | INVOKESPECIAL java.lang.StringBuffer.<init> ()V + | constructor-call(void java.lang.StringBuffer.<init>()) + | ALOAD_0 // java.lang.Object arg0 + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | LDC " " + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/String;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.String)) + | ALOAD_1 // java.lang.Object t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void MultiArgHelloWorld.foo(java.lang.Object, java.lang.Object)) + end static void foo(Object, Object) +end public class MultiArgHelloWorld diff --git a/weaver/testdata/TjpAround2HelloWorld.txt b/weaver/testdata/TjpAround2HelloWorld.txt new file mode 100644 index 000000000..8f4b4dea4 --- /dev/null +++ b/weaver/testdata/TjpAround2HelloWorld.txt @@ -0,0 +1,503 @@ +public class HelloWorld extends java.lang.Object: + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_0 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_1 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_2 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_3 + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + GETSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + ALOAD_0 + BIPUSH 0 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE_1 + constructor-execution(void HelloWorld.<init>()) + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE 4 + | ALOAD 4 + | BIPUSH 0 + | ALOAD_0 + | AASTORE + | ALOAD 4 + | BIPUSH 1 + | ALOAD_1 + | AASTORE + | NEW HelloWorld$AjcClosure3 + | DUP + | ALOAD 4 + | INVOKESPECIAL HelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | ALOAD_1 + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + | POP + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE 11 + GETSTATIC HelloWorld.ajc$tjp_3 Lorg/aspectj/lang/JoinPoint$StaticPart; + ACONST_NULL + ACONST_NULL + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE 13 + ALOAD 13 + BIPUSH 0 + ALOAD 11 + AASTORE + ALOAD 13 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE 12 + method-execution(void HelloWorld.main(java.lang.String[])) + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE 15 + | ALOAD 15 + | BIPUSH 0 + | ALOAD 11 + | AASTORE + | ALOAD 15 + | BIPUSH 1 + | ALOAD 12 + | AASTORE + | NEW HelloWorld$AjcClosure15 + | DUP + | ALOAD 15 + | INVOKESPECIAL HelloWorld$AjcClosure15.<init> ([Ljava/lang/Object;)V + | ALOAD 12 + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + | POP + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static void <clinit>(): + NEW org.aspectj.runtime.reflect.Factory + DUP + LDC "HelloWorld.java" + LDC "HelloWorld" + INVOKESTATIC java.lang.Class.forName (Ljava/lang/String;)Ljava/lang/Class; + INVOKESPECIAL org.aspectj.runtime.reflect.Factory.<init> (Ljava/lang/String;Ljava/lang/Class;)V + ASTORE_0 + ALOAD_0 + LDC "constructor-execution" + ALOAD_0 + LDC "1--HelloWorld----" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeConstructorSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/ConstructorSignature; + BIPUSH 5 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "field-get" + ALOAD_0 + LDC "19-out-java.lang.System-java.io.PrintStream-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeFieldSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/FieldSignature; + BIPUSH 8 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "method-call" + ALOAD_0 + LDC "1-println-java.io.PrintStream-java.lang.String:-arg0:--void-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeMethodSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/MethodSignature; + BIPUSH 9 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_2 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "method-execution" + ALOAD_0 + LDC "9-main-HelloWorld-[Ljava/lang/String;:-args:--void-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeMethodSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/MethodSignature; + BIPUSH 8 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_3 Lorg/aspectj/lang/JoinPoint$StaticPart; + staticinitialization(void HelloWorld.<clinit>()) + | RETURN + staticinitialization(void HelloWorld.<clinit>()) + end static void <clinit>() + + static final void init$_aroundBody0(HelloWorld, org.aspectj.lang.JoinPoint): + RETURN (line 5) + end static final void init$_aroundBody0(HelloWorld, org.aspectj.lang.JoinPoint) + + static final void init$_aroundBody2(HelloWorld, org.aspectj.lang.JoinPoint): + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW HelloWorld$AjcClosure1 + DUP + ALOAD_2 + INVOKESPECIAL HelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + ALOAD_1 + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + POP + RETURN + end static final void init$_aroundBody2(HelloWorld, org.aspectj.lang.JoinPoint) + + static final java.io.PrintStream out_aroundBody4(org.aspectj.lang.JoinPoint): + GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + ARETURN + end static final java.io.PrintStream out_aroundBody4(org.aspectj.lang.JoinPoint) + + static final java.io.PrintStream out_aroundBody6(org.aspectj.lang.JoinPoint): + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE_1 + ALOAD_1 + BIPUSH 0 + ALOAD_0 + AASTORE + NEW HelloWorld$AjcClosure5 + DUP + ALOAD_1 + INVOKESPECIAL HelloWorld$AjcClosure5.<init> ([Ljava/lang/Object;)V + ALOAD_0 + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + CHECKCAST java.io.PrintStream + ARETURN + end static final java.io.PrintStream out_aroundBody6(org.aspectj.lang.JoinPoint) + + static final void println_aroundBody8(java.io.PrintStream, String, org.aspectj.lang.JoinPoint): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 9) + RETURN + end static final void println_aroundBody8(java.io.PrintStream, String, org.aspectj.lang.JoinPoint) + + static final void println_aroundBody10(java.io.PrintStream, String, org.aspectj.lang.JoinPoint): + BIPUSH 3 + ANEWARRAY java.lang.Object + ASTORE_3 + ALOAD_3 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_3 + BIPUSH 1 + ALOAD_1 + AASTORE + ALOAD_3 + BIPUSH 2 + ALOAD_2 + AASTORE + NEW HelloWorld$AjcClosure9 + DUP + ALOAD_3 + INVOKESPECIAL HelloWorld$AjcClosure9.<init> ([Ljava/lang/Object;)V + ALOAD_2 + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + POP + RETURN + end static final void println_aroundBody10(java.io.PrintStream, String, org.aspectj.lang.JoinPoint) + + static final void main_aroundBody12(String[], org.aspectj.lang.JoinPoint): + GETSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + ACONST_NULL + ACONST_NULL + BIPUSH 0 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE 4 + field-get(java.io.PrintStream java.lang.System.out) + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 6 + | ALOAD 6 + | BIPUSH 0 + | ALOAD 4 + | AASTORE + | NEW HelloWorld$AjcClosure7 + | DUP + | ALOAD 6 + | INVOKESPECIAL HelloWorld$AjcClosure7.<init> ([Ljava/lang/Object;)V + | ALOAD 4 + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + | CHECKCAST java.io.PrintStream + field-get(java.io.PrintStream java.lang.System.out) + LDC "hello world" (line 9) + ASTORE 8 + ASTORE 10 + GETSTATIC HelloWorld.ajc$tjp_2 Lorg/aspectj/lang/JoinPoint$StaticPart; + ACONST_NULL + ALOAD 10 + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE 12 + ALOAD 12 + BIPUSH 0 + ALOAD 8 + AASTORE + ALOAD 12 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE 14 + method-call(void java.io.PrintStream.println(java.lang.String)) + | BIPUSH 3 + | ANEWARRAY java.lang.Object + | ASTORE 16 + | ALOAD 16 + | BIPUSH 0 + | ALOAD 10 + | AASTORE + | ALOAD 16 + | BIPUSH 1 + | ALOAD 8 + | AASTORE + | ALOAD 16 + | BIPUSH 2 + | ALOAD 14 + | AASTORE + | NEW HelloWorld$AjcClosure11 + | DUP + | ALOAD 16 + | INVOKESPECIAL HelloWorld$AjcClosure11.<init> ([Ljava/lang/Object;)V + | ALOAD 14 + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + | POP + method-call(void java.io.PrintStream.println(java.lang.String)) + RETURN (line 11) + end static final void main_aroundBody12(String[], org.aspectj.lang.JoinPoint) + + static final void main_aroundBody14(String[], org.aspectj.lang.JoinPoint): + BIPUSH 2 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_2 + BIPUSH 1 + ALOAD_1 + AASTORE + NEW HelloWorld$AjcClosure13 + DUP + ALOAD_2 + INVOKESPECIAL HelloWorld$AjcClosure13.<init> ([Ljava/lang/Object;)V + ALOAD_1 + INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + POP + RETURN + end static final void main_aroundBody14(String[], org.aspectj.lang.JoinPoint) +end public class HelloWorld + +public class HelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST HelloWorld + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.init$_aroundBody0 (LHelloWorld;Lorg/aspectj/lang/JoinPoint;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure1 + +public class HelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST HelloWorld + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.init$_aroundBody2 (LHelloWorld;Lorg/aspectj/lang/JoinPoint;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure3 + +public class HelloWorld$AjcClosure5 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.out_aroundBody4 (Lorg/aspectj/lang/JoinPoint;)Ljava/io/PrintStream; + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure5 + +public class HelloWorld$AjcClosure7 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.out_aroundBody6 (Lorg/aspectj/lang/JoinPoint;)Ljava/io/PrintStream; + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure7 + +public class HelloWorld$AjcClosure9 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + ALOAD_2 + BIPUSH 2 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.println_aroundBody8 (Ljava/io/PrintStream;Ljava/lang/String;Lorg/aspectj/lang/JoinPoint;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure9 + +public class HelloWorld$AjcClosure11 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + ALOAD_2 + BIPUSH 2 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.println_aroundBody10 (Ljava/io/PrintStream;Ljava/lang/String;Lorg/aspectj/lang/JoinPoint;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure11 + +public class HelloWorld$AjcClosure13 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST [Ljava.lang.String; + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.main_aroundBody12 ([Ljava/lang/String;Lorg/aspectj/lang/JoinPoint;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure13 + +public class HelloWorld$AjcClosure15 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST [Ljava.lang.String; + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.main_aroundBody14 ([Ljava/lang/String;Lorg/aspectj/lang/JoinPoint;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure15 diff --git a/weaver/testdata/TjpAroundHelloWorld.txt b/weaver/testdata/TjpAroundHelloWorld.txt new file mode 100644 index 000000000..d1424058e --- /dev/null +++ b/weaver/testdata/TjpAroundHelloWorld.txt @@ -0,0 +1,312 @@ +public class HelloWorld extends java.lang.Object: + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_0 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_1 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_2 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_3 + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + GETSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + ALOAD_0 + BIPUSH 0 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE_1 + constructor-execution(void HelloWorld.<init>()) + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE_3 + | ALOAD_3 + | BIPUSH 0 + | ALOAD_0 + | AASTORE + | ALOAD_3 + | BIPUSH 1 + | ALOAD_1 + | AASTORE + | NEW HelloWorld$AjcClosure1 + | DUP + | ALOAD_3 + | INVOKESPECIAL HelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + | ALOAD_1 + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + | POP + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE 9 + GETSTATIC HelloWorld.ajc$tjp_3 Lorg/aspectj/lang/JoinPoint$StaticPart; + ACONST_NULL + ACONST_NULL + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE 11 + ALOAD 11 + BIPUSH 0 + ALOAD 9 + AASTORE + ALOAD 11 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE 10 + method-execution(void HelloWorld.main(java.lang.String[])) + | BIPUSH 2 + | ANEWARRAY java.lang.Object + | ASTORE 12 + | ALOAD 12 + | BIPUSH 0 + | ALOAD 9 + | AASTORE + | ALOAD 12 + | BIPUSH 1 + | ALOAD 10 + | AASTORE + | NEW HelloWorld$AjcClosure7 + | DUP + | ALOAD 12 + | INVOKESPECIAL HelloWorld$AjcClosure7.<init> ([Ljava/lang/Object;)V + | ALOAD 10 + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + | POP + | RETURN + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static void <clinit>(): + NEW org.aspectj.runtime.reflect.Factory + DUP + LDC "HelloWorld.java" + LDC "HelloWorld" + INVOKESTATIC java.lang.Class.forName (Ljava/lang/String;)Ljava/lang/Class; + INVOKESPECIAL org.aspectj.runtime.reflect.Factory.<init> (Ljava/lang/String;Ljava/lang/Class;)V + ASTORE_0 + ALOAD_0 + LDC "constructor-execution" + ALOAD_0 + LDC "1--HelloWorld----" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeConstructorSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/ConstructorSignature; + BIPUSH 5 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "field-get" + ALOAD_0 + LDC "19-out-java.lang.System-java.io.PrintStream-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeFieldSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/FieldSignature; + BIPUSH 8 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "method-call" + ALOAD_0 + LDC "1-println-java.io.PrintStream-java.lang.String:-arg0:--void-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeMethodSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/MethodSignature; + BIPUSH 9 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_2 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "method-execution" + ALOAD_0 + LDC "9-main-HelloWorld-[Ljava/lang/String;:-args:--void-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeMethodSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/MethodSignature; + BIPUSH 8 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_3 Lorg/aspectj/lang/JoinPoint$StaticPart; + staticinitialization(void HelloWorld.<clinit>()) + | RETURN + staticinitialization(void HelloWorld.<clinit>()) + end static void <clinit>() + + static final void init$_aroundBody0(HelloWorld, org.aspectj.lang.JoinPoint): + RETURN (line 5) + end static final void init$_aroundBody0(HelloWorld, org.aspectj.lang.JoinPoint) + + static final java.io.PrintStream out_aroundBody2(org.aspectj.lang.JoinPoint): + GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + ARETURN + end static final java.io.PrintStream out_aroundBody2(org.aspectj.lang.JoinPoint) + + static final void println_aroundBody4(java.io.PrintStream, String, org.aspectj.lang.JoinPoint): + ALOAD_0 + ALOAD_1 + INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V (line 9) + RETURN + end static final void println_aroundBody4(java.io.PrintStream, String, org.aspectj.lang.JoinPoint) + + static final void main_aroundBody6(String[], org.aspectj.lang.JoinPoint): + GETSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + ACONST_NULL + ACONST_NULL + BIPUSH 0 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE 4 + field-get(java.io.PrintStream java.lang.System.out) + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 6 + | ALOAD 6 + | BIPUSH 0 + | ALOAD 4 + | AASTORE + | NEW HelloWorld$AjcClosure3 + | DUP + | ALOAD 6 + | INVOKESPECIAL HelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | ALOAD 4 + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + | CHECKCAST java.io.PrintStream + field-get(java.io.PrintStream java.lang.System.out) + LDC "hello world" (line 9) + ASTORE 8 + ASTORE 10 + GETSTATIC HelloWorld.ajc$tjp_2 Lorg/aspectj/lang/JoinPoint$StaticPart; + ACONST_NULL + ALOAD 10 + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE 12 + ALOAD 12 + BIPUSH 0 + ALOAD 8 + AASTORE + ALOAD 12 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE 14 + method-call(void java.io.PrintStream.println(java.lang.String)) + | BIPUSH 3 + | ANEWARRAY java.lang.Object + | ASTORE 16 + | ALOAD 16 + | BIPUSH 0 + | ALOAD 10 + | AASTORE + | ALOAD 16 + | BIPUSH 1 + | ALOAD 8 + | AASTORE + | ALOAD 16 + | BIPUSH 2 + | ALOAD 14 + | AASTORE + | NEW HelloWorld$AjcClosure5 + | DUP + | ALOAD 16 + | INVOKESPECIAL HelloWorld$AjcClosure5.<init> ([Ljava/lang/Object;)V + | ALOAD 14 + | INVOKESTATIC Aspect.ajc_around (Lorg/aspectj/runtime/internal/AroundClosure;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/Object; + | POP + method-call(void java.io.PrintStream.println(java.lang.String)) + RETURN (line 11) + end static final void main_aroundBody6(String[], org.aspectj.lang.JoinPoint) +end public class HelloWorld + +public class HelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST HelloWorld + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.init$_aroundBody0 (LHelloWorld;Lorg/aspectj/lang/JoinPoint;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure1 + +public class HelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.out_aroundBody2 (Lorg/aspectj/lang/JoinPoint;)Ljava/io/PrintStream; + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure3 + +public class HelloWorld$AjcClosure5 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST java.io.PrintStream + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + ALOAD_2 + BIPUSH 2 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.println_aroundBody4 (Ljava/io/PrintStream;Ljava/lang/String;Lorg/aspectj/lang/JoinPoint;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure5 + +public class HelloWorld$AjcClosure7 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST [Ljava.lang.String; + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST org.aspectj.lang.JoinPoint + INVOKESTATIC HelloWorld.main_aroundBody6 ([Ljava/lang/String;Lorg/aspectj/lang/JoinPoint;)V + ACONST_NULL + ARETURN + end public Object run(Object[]) +end public class HelloWorld$AjcClosure7 diff --git a/weaver/testdata/TjpBeforeHelloWorld.txt b/weaver/testdata/TjpBeforeHelloWorld.txt new file mode 100644 index 000000000..b63dde298 --- /dev/null +++ b/weaver/testdata/TjpBeforeHelloWorld.txt @@ -0,0 +1,129 @@ +public class HelloWorld extends java.lang.Object: + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_0 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_1 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_2 + public static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_3 + public void <init>(): + ALOAD_0 // HelloWorld this (line 5) + INVOKESPECIAL java.lang.Object.<init> ()V + GETSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + ALOAD_0 + BIPUSH 0 + ANEWARRAY java.lang.Object + ASTORE_2 + ALOAD_2 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE_1 + constructor-execution(void HelloWorld.<init>()) + | ALOAD_1 + | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint;)V + | RETURN + constructor-execution(void HelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + ALOAD_0 + ASTORE 9 + GETSTATIC HelloWorld.ajc$tjp_3 Lorg/aspectj/lang/JoinPoint$StaticPart; + ACONST_NULL + ACONST_NULL + BIPUSH 1 + ANEWARRAY java.lang.Object + ASTORE 8 + ALOAD 8 + BIPUSH 0 + ALOAD 9 + AASTORE + ALOAD 8 + INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + ASTORE 7 + method-execution(void HelloWorld.main(java.lang.String[])) + | ALOAD 7 + | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint;)V + | GETSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + | ACONST_NULL + | ACONST_NULL + | BIPUSH 0 + | ANEWARRAY java.lang.Object + | ASTORE_2 + | ALOAD_2 + | INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + | ASTORE_1 + | field-get(java.io.PrintStream java.lang.System.out) + | | ALOAD_1 + | | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint;)V + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 8) + | field-get(java.io.PrintStream java.lang.System.out) + | LDC "hello world" (line 9) + | ASTORE 4 + | ASTORE 5 + | GETSTATIC HelloWorld.ajc$tjp_2 Lorg/aspectj/lang/JoinPoint$StaticPart; + | ACONST_NULL + | ALOAD 5 + | BIPUSH 1 + | ANEWARRAY java.lang.Object + | ASTORE 6 + | ALOAD 6 + | BIPUSH 0 + | ALOAD 4 + | AASTORE + | ALOAD 6 + | INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;[Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint; + | ASTORE_3 + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | ALOAD_3 + | | INVOKESTATIC Aspect.ajc_before (Lorg/aspectj/lang/JoinPoint;)V + | | ALOAD 5 + | | ALOAD 4 + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 11) + method-execution(void HelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + static void <clinit>(): + NEW org.aspectj.runtime.reflect.Factory + DUP + LDC "HelloWorld.java" + LDC "HelloWorld" + INVOKESTATIC java.lang.Class.forName (Ljava/lang/String;)Ljava/lang/Class; + INVOKESPECIAL org.aspectj.runtime.reflect.Factory.<init> (Ljava/lang/String;Ljava/lang/Class;)V + ASTORE_0 + ALOAD_0 + LDC "constructor-execution" + ALOAD_0 + LDC "1--HelloWorld----" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeConstructorSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/ConstructorSignature; + BIPUSH 5 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "field-get" + ALOAD_0 + LDC "19-out-java.lang.System-java.io.PrintStream-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeFieldSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/FieldSignature; + BIPUSH 8 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_1 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "method-call" + ALOAD_0 + LDC "1-println-java.io.PrintStream-java.lang.String:-arg0:--void-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeMethodSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/MethodSignature; + BIPUSH 9 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_2 Lorg/aspectj/lang/JoinPoint$StaticPart; + ALOAD_0 + LDC "method-execution" + ALOAD_0 + LDC "9-main-HelloWorld-[Ljava/lang/String;:-args:--void-" + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeMethodSig (Ljava/lang/String;)Lorg/aspectj/lang/reflect/MethodSignature; + BIPUSH 8 + INVOKEVIRTUAL org.aspectj.runtime.reflect.Factory.makeSJP (Ljava/lang/String;Lorg/aspectj/lang/Signature;I)Lorg/aspectj/lang/JoinPoint$StaticPart; + PUTSTATIC HelloWorld.ajc$tjp_3 Lorg/aspectj/lang/JoinPoint$StaticPart; + staticinitialization(void HelloWorld.<clinit>()) + | RETURN + staticinitialization(void HelloWorld.<clinit>()) + end static void <clinit>() +end public class HelloWorld diff --git a/weaver/testdata/TraceJarHello.txt b/weaver/testdata/TraceJarHello.txt new file mode 100644 index 000000000..0741a7ac1 --- /dev/null +++ b/weaver/testdata/TraceJarHello.txt @@ -0,0 +1,199 @@ +public class DynamicHelloWorld extends java.lang.Object implements java.io.Serializable: + public void <init>(): + ALOAD_0 // DynamicHelloWorld this (line 8) + INVOKESPECIAL java.lang.Object.<init> ()V + constructor-execution(void DynamicHelloWorld.<init>()) + | RETURN + constructor-execution(void DynamicHelloWorld.<init>()) + end public void <init>() + + public static void main(String[]): + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + | catch java.lang.UnsupportedOperationException -> E0 + | | NEW DynamicHelloWorld (line 12) + | | DUP + | | constructor-call(void DynamicHelloWorld.<init>()) + | | | INVOKESPECIAL DynamicHelloWorld.<init> ()V + | | constructor-call(void DynamicHelloWorld.<init>()) + | | LDC "hello" + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | | GETSTATIC java.util.Collections.EMPTY_LIST Ljava/util/List; + | | field-get(java.util.List java.util.Collections.EMPTY_LIST) + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | | INVOKEVIRTUAL DynamicHelloWorld.doit (Ljava/lang/String;Ljava/util/List;)Ljava/lang/String; + | | method-call(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | | POP + | | GOTO L0 + | catch java.lang.UnsupportedOperationException -> E0 + | E0: ASTORE_1 (line 13) + | field-get(java.io.PrintStream java.lang.System.out) + | | GETSTATIC java.lang.System.out Ljava/io/PrintStream; (line 14) + | field-get(java.io.PrintStream java.lang.System.out) + | NEW java.lang.StringBuffer + | DUP + | LDC "expected and caught: " + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.StringBuffer.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.StringBuffer.<init>(java.lang.String)) + | ALOAD_1 // java.lang.UnsupportedOperationException t + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | | INVOKEVIRTUAL java.lang.StringBuffer.append (Ljava/lang/Object;)Ljava/lang/StringBuffer; + | method-call(java.lang.StringBuffer java.lang.StringBuffer.append(java.lang.Object)) + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | | INVOKEVIRTUAL java.lang.StringBuffer.toString ()Ljava/lang/String; + | method-call(java.lang.String java.lang.StringBuffer.toString()) + | method-call(void java.io.PrintStream.println(java.lang.String)) + | | INVOKEVIRTUAL java.io.PrintStream.println (Ljava/lang/String;)V + | method-call(void java.io.PrintStream.println(java.lang.String)) + | RETURN (line 15) + | L0: NEW java.lang.RuntimeException (line 17) + | DUP + | LDC "should have caught exception" + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | | INVOKESPECIAL java.lang.RuntimeException.<init> (Ljava/lang/String;)V + | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String)) + | ATHROW + method-execution(void DynamicHelloWorld.main(java.lang.String[])) + end public static void main(String[]) + + String doit(String, java.util.List): + ALOAD_1 + ASTORE_3 + ALOAD_2 + ASTORE 4 + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + | GETSTATIC MyTrace.ajc$perSingletonInstance LMyTrace; + | ALOAD_0 + | INVOKEVIRTUAL Trace.ajc$before$Trace$51 (Ljava/lang/Object;)V + | GETSTATIC MyTrace.ajc$perSingletonInstance LMyTrace; + | BIPUSH 3 + | ANEWARRAY java.lang.Object + | ASTORE 6 + | ALOAD 6 + | BIPUSH 0 + | ALOAD_0 + | AASTORE + | ALOAD 6 + | BIPUSH 1 + | ALOAD_3 + | AASTORE + | ALOAD 6 + | BIPUSH 2 + | ALOAD 4 + | AASTORE + | NEW DynamicHelloWorld$AjcClosure3 + | DUP + | ALOAD 6 + | INVOKESPECIAL DynamicHelloWorld$AjcClosure3.<init> ([Ljava/lang/Object;)V + | INVOKEVIRTUAL Trace.ajc$around$Trace$cc (Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + | CHECKCAST java.lang.String + | GOTO L0 + | L0: DUP + | ASTORE 7 + | GETSTATIC MyTrace.ajc$perSingletonInstance LMyTrace; + | ALOAD_0 + | ALOAD 7 + | INVOKEVIRTUAL MyTrace.ajc$afterReturning$MyTrace$6e (Ljava/lang/Object;Ljava/lang/Object;)V + | ARETURN + method-execution(java.lang.String DynamicHelloWorld.doit(java.lang.String, java.util.List)) + end String doit(String, java.util.List) + + static final String doit_aroundBody0(DynamicHelloWorld, String, java.util.List): + ALOAD_2 (line 21) + ALOAD_1 + method-call(boolean java.util.List.add(java.lang.Object)) + | INVOKEINTERFACE java.util.List.add (Ljava/lang/Object;)Z + method-call(boolean java.util.List.add(java.lang.Object)) + POP + ALOAD_2 (line 22) + method-call(java.lang.String java.lang.Object.toString()) + | INVOKEVIRTUAL java.lang.Object.toString ()Ljava/lang/String; + method-call(java.lang.String java.lang.Object.toString()) + ARETURN + end static final String doit_aroundBody0(DynamicHelloWorld, String, java.util.List) + + static final String doit_aroundBody2(DynamicHelloWorld, String, java.util.List): + GETSTATIC MyTrace.ajc$perSingletonInstance LMyTrace; + ALOAD_0 + BIPUSH 3 + ANEWARRAY java.lang.Object + ASTORE_3 + ALOAD_3 + BIPUSH 0 + ALOAD_0 + AASTORE + ALOAD_3 + BIPUSH 1 + ALOAD_1 + AASTORE + ALOAD_3 + BIPUSH 2 + ALOAD_2 + AASTORE + NEW DynamicHelloWorld$AjcClosure1 + DUP + ALOAD_3 + INVOKESPECIAL DynamicHelloWorld$AjcClosure1.<init> ([Ljava/lang/Object;)V + INVOKEVIRTUAL Trace.ajc$around$Trace$1bc (Ljava/lang/Object;Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object; + CHECKCAST java.lang.String + ARETURN + end static final String doit_aroundBody2(DynamicHelloWorld, String, java.util.List) +end public class DynamicHelloWorld + +public class DynamicHelloWorld$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_1 + BIPUSH 0 + AALOAD + CHECKCAST DynamicHelloWorld + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + ALOAD_2 + BIPUSH 2 + AALOAD + CHECKCAST java.util.List + INVOKESTATIC DynamicHelloWorld.doit_aroundBody0 (LDynamicHelloWorld;Ljava/lang/String;Ljava/util/List;)Ljava/lang/String; + ARETURN + end public Object run(Object[]) +end public class DynamicHelloWorld$AjcClosure1 + +public class DynamicHelloWorld$AjcClosure3 extends org.aspectj.runtime.internal.AroundClosure: + public void <init>(Object[]): + ALOAD_0 + ALOAD_1 + INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V + RETURN + end public void <init>(Object[]) + + public Object run(Object[]): + ALOAD_0 + GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object; + ASTORE_2 + ALOAD_2 + BIPUSH 0 + AALOAD + CHECKCAST DynamicHelloWorld + ALOAD_2 + BIPUSH 1 + AALOAD + CHECKCAST java.lang.String + ALOAD_2 + BIPUSH 2 + AALOAD + CHECKCAST java.util.List + INVOKESTATIC DynamicHelloWorld.doit_aroundBody2 (LDynamicHelloWorld;Ljava/lang/String;Ljava/util/List;)Ljava/lang/String; + ARETURN + end public Object run(Object[]) +end public class DynamicHelloWorld$AjcClosure3 diff --git a/weaver/testdata/aspectjtools.jar b/weaver/testdata/aspectjtools.jar Binary files differnew file mode 100644 index 000000000..b75dfa0ee --- /dev/null +++ b/weaver/testdata/aspectjtools.jar diff --git a/weaver/testdata/dummyAspect.jar b/weaver/testdata/dummyAspect.jar Binary files differnew file mode 100644 index 000000000..d43326ab1 --- /dev/null +++ b/weaver/testdata/dummyAspect.jar diff --git a/weaver/testdata/megatrace.jar b/weaver/testdata/megatrace.jar Binary files differnew file mode 100644 index 000000000..cd9a39fde --- /dev/null +++ b/weaver/testdata/megatrace.jar diff --git a/weaver/testdata/megatraceNoweave.jar b/weaver/testdata/megatraceNoweave.jar Binary files differnew file mode 100644 index 000000000..ec73b528a --- /dev/null +++ b/weaver/testdata/megatraceNoweave.jar diff --git a/weaver/testdata/tracing.jar b/weaver/testdata/tracing.jar Binary files differnew file mode 100644 index 000000000..b43613e79 --- /dev/null +++ b/weaver/testdata/tracing.jar diff --git a/weaver/testsrc/Aspect.java b/weaver/testsrc/Aspect.java new file mode 100644 index 000000000..bdb8108f4 --- /dev/null +++ b/weaver/testsrc/Aspect.java @@ -0,0 +1,347 @@ +/* This file is part of the compiler and core tools for the AspectJ(tm) + * programming language; see http://aspectj.org + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * either http://www.mozilla.org/MPL/ or http://aspectj.org/MPL/. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is AspectJ. + * + * The Initial Developer of the Original Code is Palo Alto Research Center, + * Incorporated (PARC). Portions created by PARC are are + * Copyright (C) 2002 Palo Alto Research Center, Incorporated. + * All Rights Reserved. + * + * Contributor(s): + */ + +import java.util.*; + +import org.aspectj.runtime.internal.*; +import org.aspectj.runtime.internal.AroundClosure; +import org.aspectj.lang.JoinPoint; + +public class Aspect { + + public static void ajc_before_0() { + System.out.println("before_0"); + } + public static void ajc_before_0(String s) { + System.out.println("before_0: " + s); + } + public static boolean ajc_around_0(ArrayList s, AroundClosure c) throws Throwable { + System.out.println("doing around, got " + s); + Object ret = c.run(new Object[] {s}); // proceed(s) + return ((Boolean) ret).booleanValue(); + } + + public static void ajc_before_0(java.util.ArrayList list) { + System.out.println("before_0: " + list); + } + + public static void ajc_before_method_execution() { + + } + public static void ajc_before_method_execution(Object o) { + System.out.println("before_method_execution: " + o); + } + + public static void ajc_after_method_execution() { + System.out.println("after_method_execution"); + } + public static void ajc_after_method_execution(Object o) { + System.out.println("after_method_execution: " + o); + } + + public static void ajc_afterReturning_method_execution() { + System.out.println("ajc_afterReturning_method_execution"); + } + public static void ajc_afterReturning_method_execution(Object o) { + System.out.println("afterReturning_method_execution: " + o); + } + + public static void ajc_afterThrowing_method_execution() { + System.out.println("ajc_afterThrowing_method_execution"); + } + public static void ajc_afterThrowing_method_execution(Object o) { + System.out.println("afterThrowing_method_execution: " + o); + } + + + + + + public static Object ajc_around(AroundClosure closure) throws Throwable { + Object ret = closure.run(new Object[] {}); + return ret; + } + + public static Object ajc_around(AroundClosure closure, JoinPoint tjp) throws Throwable { + System.out.println("thisJoinPoint: " + tjp); + Object ret = closure.run(new Object[] {}); + return ret; + } + + // --- + + + public static void ajc_before_method_call() { + System.out.println("before_method_call"); + } + public static void ajc_before_method_call(Object o) { + System.out.println("before_method_call: " + o); + } + + public static void ajc_after_method_call() { + System.out.println("after_method_call"); + } + public static void ajc_after_method_call(Object o) { + System.out.println("after_method_call: " + o); + } + + public static void ajc_afterReturning_method_call() { + System.out.println("ajc_afterReturning_method_call"); + } + public static void ajc_afterReturning_method_call(Object o) { + System.out.println("afterReturning_method_call: " + o); + } + + public static void ajc_afterThrowing_method_call() { + System.out.println("ajc_afterThrowing_method_call"); + } + public static void ajc_afterThrowing_method_call(Object o) { + System.out.println("afterThrowing_method_call: " + o); + } + + public static Object ajc_around_method_call(AroundClosure closure) throws Throwable { + Object ret = null; + for (int i=0; i<3; i++) { + System.out.println("enter: " + i); + ret = closure.run(new Object[] {}); + } + return ret; + } + + // ---- + + public static void ajc_before_constructor_call() { + System.out.println("before_constructor_call"); + } + public static void ajc_before_constructor_call(Object o) { + System.out.println("before_constructor_call: " + o); + } + + public static void ajc_after_constructor_call() { + System.out.println("after_constructor_call"); + } + public static void ajc_after_constructor_call(Object o) { + System.out.println("after_constructor_call: " + o); + } + + public static void ajc_afterReturning_constructor_call() { + System.out.println("ajc_afterReturning_constructor_call"); + } + public static void ajc_afterReturning_constructor_call(Object o) { + System.out.println("afterReturning_constructor_call: " + o); + } + + public static void ajc_afterThrowing_constructor_call() { + System.out.println("ajc_afterThrowing_constructor_call"); + } + public static void ajc_afterThrowing_constructor_call(Object o) { + System.out.println("afterThrowing_constructor_call: " + o); + } + + public static Object ajc_around_constructor_call(AroundClosure closure) throws Throwable { + Object ret = null; + for (int i=0; i<3; i++) { + System.out.println("enter: " + i); + ret = closure.run(new Object[] {}); + } + return ret; + } + // ---- + + public static void ajc_before_constructor_execution() { + System.out.println("before_constructor_execution"); + } + public static void ajc_before_constructor_execution(Object o) { + System.out.println("before_constructor_execution: " + o); + } + + public static void ajc_after_constructor_execution() { + System.out.println("after_constructor_execution"); + } + public static void ajc_after_constructor_execution(Object o) { + System.out.println("after_constructor_execution: " + o); + } + + public static void ajc_afterReturning_constructor_execution() { + System.out.println("ajc_afterReturning_constructor_execution"); + } + public static void ajc_afterReturning_constructor_execution(Object o) { + System.out.println("afterReturning_constructor_execution: " + o); + } + + public static void ajc_afterThrowing_constructor_execution() { + System.out.println("ajc_afterThrowing_constructor_execution"); + } + public static void ajc_afterThrowing_constructor_execution(Object o) { + System.out.println("afterThrowing_constructor_execution: " + o); + } + + public static Object ajc_around_constructor_execution(AroundClosure closure) throws Throwable { + Object ret = null; + for (int i=0; i<3; i++) { + System.out.println("enter: " + i); + ret = closure.run(new Object[] {}); + } + return ret; + } + + + // --- + + + public static void ajc_before_field_get() { + System.out.println("before_field_get"); + } + public static void ajc_before_field_get(Object o) { + System.out.println("before_field_get: " + o); + } + + public static void ajc_after_field_get() { + System.out.println("after_field_get"); + } + public static void ajc_after_field_get(Object o) { + System.out.println("after_field_get: " + o); + } + + public static void ajc_afterReturning_field_get() { + System.out.println("afterReturning_field_get"); + } + public static void ajc_afterReturning_field_get(Object o) { + System.out.println("afterReturning_field_get: " + o); + } + + public static void ajc_afterThrowing_field_get() { + System.out.println("afterThrowing_field_get"); + } + public static void ajc_afterThrowing_field_get(Object o) { + System.out.println("afterThrowing_field_get: " + o); + } + public static void ajc_afterThrowing_field_get(Throwable t) { + System.out.println("afterThrowing_field_get: " + t); + } + + public static Object ajc_around_field_get(AroundClosure closure) throws Throwable { + Object ret = closure.run(new Object[] {}); + return ret; + } + + + // --- + + + public static void ajc_before_field_set() { + System.out.println("before_field_set"); + } + public static void ajc_before_field_set(Object o) { + System.out.println("before_field_set: " + o); + } + + public static void ajc_after_field_set() { + System.out.println("after_field_set"); + } + public static void ajc_after_field_set(Object o) { + System.out.println("after_field_set: " + o); + } + + public static void ajc_afterReturning_field_set() { + System.out.println("afterReturning_field_set"); + } + public static void ajc_afterReturning_field_set(Object o) { + System.out.println("afterReturning_field_set: " + o); + } + + public static void ajc_afterThrowing_field_set() { + System.out.println("afterThrowing_field_set"); + } + public static void ajc_afterThrowing_field_set(Object o) { + System.out.println("afterThrowing_field_set: " + o); + } + public static void ajc_afterThrowing_field_set(Throwable t) { + System.out.println("afterThrowing_field_set: " + t); + } + + public static Object ajc_around_field_set(AroundClosure closure) throws Throwable { + Object ret = closure.run(new Object[] {}); + return ret; + } + + // don't call this method for callee-side call join points + public static void ajc_before(JoinPoint.StaticPart tjp) { + System.out.println("before: " + tjp); + if (tjp.getSourceLocation() == null) { + throw new RuntimeException("didn't want null"); + } + System.out.println(" loc: " + tjp.getSourceLocation()); + } + + public static void ajc_before(JoinPoint tjp) { + System.out.println("before: " + tjp + " this = " + tjp.getThis() + + " target = " + tjp.getTarget() + + " args = " + Arrays.asList(tjp.getArgs())); + } + + // per object stuff + + private static Map objects = new HashMap(); + + public static void ajc$perObjectBind(Object o) { + if (objects.containsKey(o)) return; + objects.put(o, new Aspect()); + } + + public static boolean hasAspect(Object o) { + return objects.containsKey(o); + } + + public static Aspect aspectOf(Object o) { + return (Aspect) objects.get(o); + } + + + // per cflow stuff + + public static void ajc$perCflowPush() { + ajc$perCflowStack.pushInstance(new Aspect()); + } + + public static boolean hasAspect() { + return ajc$perCflowStack.isValid(); + } + + public static Aspect aspectOf() { + return (Aspect) ajc$perCflowStack.peekInstance(); + } + + public static CFlowStack ajc$perCflowStack = new CFlowStack(); + + // non-static methods + + public static Aspect ajc$perSingletonInstance = new Aspect(); + public void ajc_before() { + System.out.println("before in: " + this); + } + + public static CFlowStack ajc$cflowStack$0 = new CFlowStack(); + + +} diff --git a/weaver/testsrc/BcweaverModuleTests.java b/weaver/testsrc/BcweaverModuleTests.java new file mode 100644 index 000000000..4c4617338 --- /dev/null +++ b/weaver/testsrc/BcweaverModuleTests.java @@ -0,0 +1,30 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + +// default package + +import junit.framework.*; +import junit.framework.Test; + +public class BcweaverModuleTests extends TestCase { + + public static Test suite() { + TestSuite suite = new TestSuite(BcweaverModuleTests.class.getName()); + suite.addTest(org.aspectj.weaver.bcel.BcelTests.suite()); + suite.addTest(org.aspectj.weaver.BcweaverTests.suite()); + suite.addTest(org.aspectj.weaver.patterns.PatternsTests.suite()); + return suite; + } + + public BcweaverModuleTests(String name) { super(name); } + +} diff --git a/weaver/testsrc/DynamicHelloWorld.java b/weaver/testsrc/DynamicHelloWorld.java new file mode 100644 index 000000000..f3818050e --- /dev/null +++ b/weaver/testsrc/DynamicHelloWorld.java @@ -0,0 +1,24 @@ +import java.io.*; +import java.util.*; + +/** + * @version 1.0 + * @author + */ +public class DynamicHelloWorld implements Serializable { + + public static void main(String[] args) { + try { + new DynamicHelloWorld().doit("hello", Collections.EMPTY_LIST); + } catch (UnsupportedOperationException t) { + System.out.println("expected and caught: " + t); + return; + } + throw new RuntimeException("should have caught exception"); + } + + String doit(String s, List l) { + l.add(s); // this will throw an exception + return l.toString(); + } +} diff --git a/weaver/testsrc/FancyHelloWorld.java b/weaver/testsrc/FancyHelloWorld.java new file mode 100644 index 000000000..96bd4a067 --- /dev/null +++ b/weaver/testsrc/FancyHelloWorld.java @@ -0,0 +1,24 @@ +import java.io.PrintStream; + +/** + * @version 1.0 + * @author + */ +public abstract class FancyHelloWorld { + public static void main(String[] args) { + PrintStream out = System.out; + try { + out.println("bye"); + } catch (Exception e) { + out.println(e); + } finally { + out.println("finally"); + } + } + + public static String getName() { + int x = 0; + x += "name".hashCode(); + return "name" + x; + } +} diff --git a/weaver/testsrc/FieldyHelloWorld.java b/weaver/testsrc/FieldyHelloWorld.java new file mode 100644 index 000000000..b5502abf8 --- /dev/null +++ b/weaver/testsrc/FieldyHelloWorld.java @@ -0,0 +1,10 @@ +public class FieldyHelloWorld { + + public static String str = "Hello"; + + public static void main(String[] args) { + str += " World"; + + System.out.println(str); + } +} diff --git a/weaver/testsrc/HelloWorld.java b/weaver/testsrc/HelloWorld.java new file mode 100644 index 000000000..b296ba704 --- /dev/null +++ b/weaver/testsrc/HelloWorld.java @@ -0,0 +1,12 @@ +/** + * @version 1.0 + * @author + */ +public class HelloWorld { + + public static void main(String[] args) { + System.out + .println("hello world"); + //System.out.println("hello world"); + } +} diff --git a/weaver/testsrc/MultiArgHelloWorld.java b/weaver/testsrc/MultiArgHelloWorld.java new file mode 100644 index 000000000..9fccf0ec6 --- /dev/null +++ b/weaver/testsrc/MultiArgHelloWorld.java @@ -0,0 +1,12 @@ + + +public class MultiArgHelloWorld { + + public static void main(String[] args) { + foo("Hello", "World"); + } + + static void foo(Object s, Object t) { + System.out.println(s + " " + t); + } +} diff --git a/weaver/testsrc/Test.java b/weaver/testsrc/Test.java new file mode 100644 index 000000000..97f37d943 --- /dev/null +++ b/weaver/testsrc/Test.java @@ -0,0 +1,11 @@ +public class Test { + public static void main(String[] args) { + foo() + . + foo(); + } + public static Test foo() { + new Exception().printStackTrace(); + return new Test(); + } +} diff --git a/weaver/testsrc/TestSwitchy.java b/weaver/testsrc/TestSwitchy.java new file mode 100644 index 000000000..1f65a12d8 --- /dev/null +++ b/weaver/testsrc/TestSwitchy.java @@ -0,0 +1,31 @@ +/** + * @author hilsdale + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public abstract class TestSwitchy { + + + public int i = 3; + + public static final int j = 4; + + + public static void main(String[] args) { + switch (args.length) { + case 0: System.err.println("hi"); + case 1: System.err.println("bye"); break; + case 2: System.err.println("two"); + default: System.err.println("ning"); + } + System.err.println("done"); + } + + + abstract int goo(); + + void nimbo() {} +} diff --git a/weaver/testsrc/fluffy/Aspect.java b/weaver/testsrc/fluffy/Aspect.java new file mode 100644 index 000000000..7cb35bfa4 --- /dev/null +++ b/weaver/testsrc/fluffy/Aspect.java @@ -0,0 +1,31 @@ +package fluffy; +import java.util.*; + +import org.aspectj.runtime.internal.AroundClosure; + +public class Aspect { + + public static void ignoreMe() {} + + public static void before_method_call() { + System.out.println("before"); + } + + public static void afterReturning_method_call() { + System.out.println("afterReturning"); + } + + public static void afterThrowing_method_execution(Throwable t) { + System.out.println("afterThrowing " + t); + t.printStackTrace(); + } + + public static Object aroundFun(AroundClosure c) { + System.out.println("around"); + try { + return c.run(new Object[0]); + } catch (Throwable t) { + return null; + } + } +} diff --git a/weaver/testsrc/fluffy/Base.java b/weaver/testsrc/fluffy/Base.java new file mode 100644 index 000000000..9aa148d68 --- /dev/null +++ b/weaver/testsrc/fluffy/Base.java @@ -0,0 +1,15 @@ +package fluffy; + +public class Base { + + public static void onlyBase() {} + public static void both() {} + + public int onlyBase; + public int both; + + public Base() {} + public Base(int i) {} + + public void m() throws CloneNotSupportedException {} +} diff --git a/weaver/testsrc/fluffy/Derived.java b/weaver/testsrc/fluffy/Derived.java new file mode 100644 index 000000000..6c38db40e --- /dev/null +++ b/weaver/testsrc/fluffy/Derived.java @@ -0,0 +1,17 @@ +package fluffy; + +import java.io.IOException; + +public class Derived extends Base { + + public static void onlyDerived() throws IOException, CloneNotSupportedException {} + public static void both() {} + + public int onlyDerived; + public int both; + + public Derived() {} + + public void m() {} + +} diff --git a/weaver/testsrc/org/aspectj/weaver/AbstractWorldTestCase.java b/weaver/testsrc/org/aspectj/weaver/AbstractWorldTestCase.java new file mode 100644 index 000000000..4ae04c77f --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/AbstractWorldTestCase.java @@ -0,0 +1,179 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import java.lang.reflect.Modifier; +import java.util.*; + +import junit.framework.TestCase; + +import org.aspectj.testing.util.TestUtil; + +/** This isn't a test case, it's extended by test cases, and includes tests that + * should be true in all worlds. + */ + +public abstract class AbstractWorldTestCase extends TestCase { + + public AbstractWorldTestCase(String name) { + super(name); + } + + protected abstract World getWorld(); + + private final TypeX[] primitiveTypeXs = + TypeX.forSignatures( + new String[] {"B", "S", "C", "I", "J", "F", "D", "V"}); + + public void testPrimitiveTypes() { + ResolvedTypeX[] primitives = getWorld().resolve(primitiveTypeXs); + for(int i = 0, len = primitives.length; i < len; i++) { + ResolvedTypeX ty = primitives[i]; + modifiersTest(ty, Modifier.PUBLIC | Modifier.FINAL); + fieldsTest(ty, ResolvedMember.NONE); + methodsTest(ty, ResolvedMember.NONE); + interfacesTest(ty, ResolvedTypeX.NONE); + superclassTest(ty, null); + pointcutsTest(ty, ResolvedMember.NONE); + isInterfaceTest(ty, false); + isClassTest(ty, false); + isAspectTest(ty, false); + for (int j = 0; j < len; j++) { + ResolvedTypeX ty1 = primitives[j]; + if (ty.equals(ty1)) { + isCoerceableFromTest(ty, ty1, true); + } else if (ty == ResolvedTypeX.BOOLEAN || ty1 == ResolvedTypeX.BOOLEAN || + ty == ResolvedTypeX.VOID || ty1 == ResolvedTypeX.VOID) { + isCoerceableFromTest(ty, ty1, false); + } else { + isCoerceableFromTest(ty, ty1, true); + } + } + isCoerceableFromTest(ty, TypeX.OBJECT, false); + + primAssignTest("B", new String[] {}); + primAssignTest("S", new String[] {"B"}); + primAssignTest("C", new String[] {"B"}); + primAssignTest("I", new String[] {"B", "S", "C"}); + primAssignTest("J", new String[] {"B", "S", "C", "I"}); + primAssignTest("F", new String[] {"B", "S", "C", "I", "J"}); + primAssignTest("D", new String[] {"B", "S", "C", "I", "J", "F"}); + primAssignTest("Z", new String[] {}); + primAssignTest("V", new String[] {}); + + } + } + private void primAssignTest(String sig, String[] lowers) { + ResolvedTypeX[] primitives = getWorld().resolve(primitiveTypeXs); + ResolvedTypeX ty = getWorld().resolve(TypeX.forSignature(sig)); + ResolvedTypeX[] lowerTyArray = + getWorld().resolve(TypeX.forSignatures(lowers)); + List lowerTys = new ArrayList(Arrays.asList(lowerTyArray)); + lowerTys.add(ty); + Set allLowerTys = new HashSet(lowerTys); + Set allUpperTys = new HashSet(Arrays.asList(primitives)); + allUpperTys.removeAll(allLowerTys); + + for (Iterator i = allLowerTys.iterator(); i.hasNext(); ) { + ResolvedTypeX other = (ResolvedTypeX) i.next(); + isAssignableFromTest(ty, other, true); + } + for (Iterator i = allUpperTys.iterator(); i.hasNext(); ) { + ResolvedTypeX other = (ResolvedTypeX) i.next(); + isAssignableFromTest(ty, other, false); + } + } + + public void testPrimitiveArrays() { + ResolvedTypeX[] primitives = getWorld().resolve(primitiveTypeXs); + for(int i = 0, len = primitives.length; i < len; i++) { + ResolvedTypeX ty = primitives[i]; + ResolvedTypeX aty = getWorld().resolve(TypeX.forSignature("[" + ty.getSignature())); + modifiersTest(aty, Modifier.PUBLIC | Modifier.FINAL); + fieldsTest(aty, ResolvedMember.NONE); + methodsTest(aty, ResolvedMember.NONE); + interfacesTest(aty, new ResolvedTypeX[] { + getWorld().resolve(TypeX.CLONEABLE), + getWorld().resolve(TypeX.SERIALIZABLE) }); + superclassTest(aty, TypeX.OBJECT); + + pointcutsTest(aty, ResolvedMember.NONE); + isInterfaceTest(aty, false); + isClassTest(aty, false); + isAspectTest(aty, false); + for (int j = 0; j < len; j++) { + ResolvedTypeX ty1 = primitives[j]; + isCoerceableFromTest(aty, ty1, false); + ResolvedTypeX aty1 = getWorld().resolve(TypeX.forSignature("[" + ty1.getSignature())); + if (ty.equals(ty1)) { + isCoerceableFromTest(aty, aty1, true); + isAssignableFromTest(aty, aty1, true); + } else { + isCoerceableFromTest(aty, aty1, false); + isAssignableFromTest(aty, aty1, false); + } + } + } + } + + // ---- tests for parts of ResolvedTypeX objects + + protected void modifiersTest(ResolvedTypeX ty, int mods) { + assertEquals(ty + " modifiers:", Modifier.toString(mods), Modifier.toString(ty.getModifiers())); + } + protected void fieldsTest(ResolvedTypeX ty, Member[] x) { + TestUtil.assertSetEquals(ty + " fields:", x, ty.getDeclaredJavaFields()); + } + protected void methodsTest(ResolvedTypeX ty, Member[] x) { + TestUtil.assertSetEquals(ty + " methods:", x, ty.getDeclaredJavaMethods()); + } + protected void mungersTest(ResolvedTypeX ty, ShadowMunger[] x) { + TestUtil.assertSetEquals(ty + " mungers:", x, ty.getDeclaredShadowMungersArray()); + } + protected void interfacesTest(ResolvedTypeX ty, ResolvedTypeX[] x) { + TestUtil.assertArrayEquals(ty + " interfaces:", x, ty.getDeclaredInterfaces()); + } + protected void superclassTest(ResolvedTypeX ty, TypeX x) { + assertEquals(ty + " superclass:", x, ty.getSuperclass()); + } + protected void pointcutsTest(ResolvedTypeX ty, Member[] x) { + TestUtil.assertSetEquals(ty + " pointcuts:", x, ty.getDeclaredPointcuts()); + } + protected void isInterfaceTest(ResolvedTypeX ty, boolean x) { + assertEquals(ty + " is interface:", x, ty.isInterface()); + } + protected void isAspectTest(ResolvedTypeX ty, boolean x) { + assertEquals(ty + " is aspect:", x, ty.isAspect()); + } + protected void isClassTest(ResolvedTypeX ty, boolean x) { + assertEquals(ty + " is class:", x, ty.isClass()); + } + protected void isCoerceableFromTest(TypeX ty0, TypeX ty1, boolean x) { + assertEquals(ty0 + " is coerceable from " + ty1, x, ty0.isCoerceableFrom(ty1, getWorld())); + assertEquals(ty1 + " is coerceable from " + ty0, x, ty1.isCoerceableFrom(ty0, getWorld())); + } + protected void isAssignableFromTest(TypeX ty0, TypeX ty1, boolean x) { + assertEquals(ty0 + " is assignable from " + ty1, x, ty0.isAssignableFrom(ty1, getWorld())); + } + + // ---- tests for parts of ResolvedMethod objects + + protected void modifiersTest(ResolvedMember m, int mods) { + assertEquals(m + " modifiers:", Modifier.toString(mods), Modifier.toString(m.getModifiers())); + } + protected void exceptionsTest(ResolvedMember m, TypeX[] exns) { + TestUtil.assertSetEquals(m + " exceptions:", exns, m.getExceptions()); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/BcweaverTests.java b/weaver/testsrc/org/aspectj/weaver/BcweaverTests.java new file mode 100644 index 000000000..5f2419dd0 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/BcweaverTests.java @@ -0,0 +1,33 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import junit.framework.*; + +public class BcweaverTests extends TestCase { + + public static Test suite() { + TestSuite suite = new TestSuite(BcweaverTests.class.getName()); + // abstract + //suite.addTestSuite(AbstractWorldTestCase.class); + //$JUnit-BEGIN$ + suite.addTestSuite(MemberTestCase.class); + suite.addTestSuite(TypeXTestCase.class); + //$JUnit-END$ + return suite; + } + + public BcweaverTests(String name) { super(name); } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/MemberTestCase.java b/weaver/testsrc/org/aspectj/weaver/MemberTestCase.java new file mode 100644 index 000000000..d3e2919b3 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/MemberTestCase.java @@ -0,0 +1,175 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import junit.framework.TestCase; + +import org.aspectj.testing.util.TestUtil; + +/** + * This is a test case for all the portions of Member that don't require a world. + */ +public class MemberTestCase extends TestCase { + + public MemberTestCase(String name) { + super(name); + } + + public void testMethodConstruction() { + Member s = Member.methodFromString("void Foo.goo(int)"); + Member t = Member.method(TypeX.forName("Foo"), 0, "goo", "(I)V"); + Member u = Member.methodFromString("void Foo1.goo(int)"); + Member v = Member.methodFromString("int Foo.goo(int)"); + + TestUtil.assertCommutativeEquals(s, s, true); + TestUtil.assertCommutativeEquals(t, t, true); + TestUtil.assertCommutativeEquals(u, u, true); + TestUtil.assertCommutativeEquals(v, v, true); + TestUtil.assertCommutativeEquals(s, t, true); + TestUtil.assertCommutativeEquals(s, u, false); + TestUtil.assertCommutativeEquals(s, v, false); + TestUtil.assertCommutativeEquals(t, u, false); + TestUtil.assertCommutativeEquals(t, v, false); + TestUtil.assertCommutativeEquals(u, v, false); + + s = Member.fieldFromString("int Foo.goo"); + t = Member.field("Foo", 0, "goo", "I"); + u = Member.fieldFromString("int Foo.goo1"); + v = Member.fieldFromString("long Foo.goo"); + + TestUtil.assertCommutativeEquals(s, s, true); + TestUtil.assertCommutativeEquals(t, t, true); + TestUtil.assertCommutativeEquals(u, u, true); + TestUtil.assertCommutativeEquals(v, v, true); + TestUtil.assertCommutativeEquals(s, t, true); + TestUtil.assertCommutativeEquals(s, u, false); + TestUtil.assertCommutativeEquals(s, v, false); + TestUtil.assertCommutativeEquals(t, u, false); + TestUtil.assertCommutativeEquals(t, v, false); + TestUtil.assertCommutativeEquals(u, v, false); + } + + + public void testMethodContents() { + Member m = Member.methodFromString("void Foo.goo(int)"); + kindTest(m, Member.METHOD); + declaringTypeTest(m, "Foo"); + nameTest(m, "goo"); + parameterTypesTest(m, new TypeX[] { ResolvedTypeX.INT }); + returnTypeTest(m, ResolvedTypeX.VOID); + isInterfaceTest(m, false); + isPrivateTest(m, false); + isConstructorTest(m, false); + isStaticTest(m, false); + + m = Member.methodFromString("interface java.lang.Object java.util.Iterator.next()"); + kindTest(m, Member.METHOD); + declaringTypeTest(m, "java.util.Iterator"); + nameTest(m, "next"); + parameterTypesTest(m, TypeX.NONE); + returnTypeTest(m, TypeX.OBJECT); + isInterfaceTest(m, true); + isPrivateTest(m, false); + isConstructorTest(m, false); + isStaticTest(m, false); + + m = Member.methodFromString("void Foo.<init>(int, java.lang.Object)"); + kindTest(m, Member.CONSTRUCTOR); + declaringTypeTest(m, "Foo"); + nameTest(m, "<init>"); + parameterTypesTest(m, new TypeX[] { ResolvedTypeX.INT, TypeX.OBJECT } ); + returnTypeTest(m, ResolvedTypeX.VOID); + isInterfaceTest(m, false); + isPrivateTest(m, false); + isConstructorTest(m, true); + isStaticTest(m, false); + + m = Member.methodFromString("private double Foo.sqrt(double)"); + kindTest(m, Member.METHOD); + declaringTypeTest(m, "Foo"); + nameTest(m, "sqrt"); + parameterTypesTest(m, new TypeX[] { ResolvedTypeX.DOUBLE } ); + returnTypeTest(m, ResolvedTypeX.DOUBLE); + isInterfaceTest(m, false); + isPrivateTest(m, true); + isConstructorTest(m, false); + isStaticTest(m, false); + + m = Member.methodFromString("static int java.lang.Math.max(int, int)"); + kindTest(m, Member.METHOD); + declaringTypeTest(m, "java.lang.Math"); + nameTest(m, "max"); + parameterTypesTest(m, new TypeX[] { ResolvedTypeX.INT, ResolvedTypeX.INT } ); + returnTypeTest(m, ResolvedTypeX.INT); + isInterfaceTest(m, false); + isPrivateTest(m, false); + isConstructorTest(m, false); + isStaticTest(m, true); + } + + public void testFieldContents() { + Member m = Member.fieldFromString("int Foo.goo"); + kindTest(m, Member.FIELD); + declaringTypeTest(m, "Foo"); + nameTest(m, "goo"); + parameterTypesTest(m, TypeX.NONE); + returnTypeTest(m, ResolvedTypeX.INT); + isInterfaceTest(m, false); + isPrivateTest(m, false); + isConstructorTest(m, false); + isStaticTest(m, false); + + m = Member.fieldFromString("static java.util.Iterator goo.Bar.i"); + kindTest(m, Member.FIELD); + declaringTypeTest(m, "goo.Bar"); + nameTest(m, "i"); + parameterTypesTest(m, TypeX.NONE); + returnTypeTest(m, TypeX.forName("java.util.Iterator")); + isInterfaceTest(m, false); + isPrivateTest(m, false); + isConstructorTest(m, false); + isStaticTest(m, true); + } + + private void isStaticTest(Member m, boolean b) { + assertEquals(m + " is static", b, m.isStatic()); + } + private void isConstructorTest(Member m, boolean b) { + assertEquals(m + " is constructor", b, m.getKind() == Member.CONSTRUCTOR); + } + private void isPrivateTest(Member m, boolean b) { + assertEquals(m + " is private", b, m.isPrivate()); + } + private void isInterfaceTest(Member m, boolean b) { + assertEquals(m + " is interface", b, m.isInterface()); + } + private void returnTypeTest(Member m, TypeX returnType) { + assertEquals(m + " return type", returnType, m.getReturnType()); + } + private void parameterTypesTest(Member m, TypeX[] paramTypes) { + TestUtil.assertArrayEquals(m + " parameters", paramTypes, m.getParameterTypes()); + } + private void nameTest(Member m, String name) { + assertEquals(m + " name", name, m.getName()); + } + private void declaringTypeTest(Member m, String declaringName) { + assertEquals(m + " declared in", TypeX.forName(declaringName), m.getDeclaringType()); + } + private void kindTest(Member m, Member.Kind kind) { + assertEquals(m + " kind", kind, m.getKind()); + } + + + +} diff --git a/weaver/testsrc/org/aspectj/weaver/TestShadow.java b/weaver/testsrc/org/aspectj/weaver/TestShadow.java new file mode 100644 index 000000000..ae22c8000 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/TestShadow.java @@ -0,0 +1,79 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import org.aspectj.weaver.ast.Var; +import org.aspectj.bridge.SourceLocation; + +public class TestShadow extends Shadow { + + private final World world; + private final TypeX thisType; + + public TestShadow(Kind kind, Member signature, TypeX thisType, World world) { + super(kind, signature); + this.world = world; + this.thisType = thisType; + } + + public World getIWorld() { + return world; + } + + public boolean hasThis() { return true; } + + public TypeX getThisType() { + return thisType; + } + + /** this is subtly wrong. ha ha */ + public TypeX getEnclosingType() { + return thisType; + } + + public Var getThisVar() { + // we should thorw if we don't have a this + return new Var(getThisType().resolve(world)); + } + + public Var getTargetVar() { + if (! hasTarget()) throw new RuntimeException("bad"); + return new Var(getTargetType().resolve(world)); + } + + public Var getArgVar(int i) { + return new Var(getArgType(i).resolve(world)); + } + + public Var getThisEnclosingJoinPointStaticPartVar() { + throw new RuntimeException("unimplemented"); + } + + public Var getThisJoinPointStaticPartVar() { + throw new RuntimeException("unimplemented"); + } + + public Var getThisJoinPointVar() { + throw new RuntimeException("unimplemented"); + } + + public SourceLocation getSourceLocation() { + throw new RuntimeException("unimplemented"); + } + + public Member getEnclosingCodeSignature() { + throw new RuntimeException("unimplemented"); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/TypeXTestCase.java b/weaver/testsrc/org/aspectj/weaver/TypeXTestCase.java new file mode 100644 index 000000000..87b0317f8 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/TypeXTestCase.java @@ -0,0 +1,124 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver; + +import junit.framework.TestCase; + +import org.aspectj.testing.util.TestUtil; + +/** + * This is a test case for all the portions of TypeX that don't require a world. + */ +public class TypeXTestCase extends TestCase { + + public TypeXTestCase(String name) { + super(name); + } + + public void testUnresolvedTypes() { + // basic equality + String[] testNames = + new String[] {"int", "long", "int[]", "boolean[][]", + "java.lang.String", "java.lang.String[]", "void" }; + String[] testSigs = + new String[] {"I", "J", "[I", "[[Z", + "Ljava/lang/String;", "[Ljava/lang/String;", "V" }; + + String[] componentNames = + new String[] {null, null, "int", "boolean[]", + null, "java.lang.String", null }; + + int[] sizes = new int[] {1, 2, 1, 1, 1, 1, 0}; + + boolean[] isPrimitive = + new boolean[] { true, true, false, false, false, false, true }; + + nameSignatureTest(testNames, testSigs); + arrayTest(TypeX.forNames(testNames), componentNames); + arrayTest(TypeX.forSignatures(testSigs), componentNames); + + sizeTest(TypeX.forNames(testNames), sizes); + sizeTest(TypeX.forSignatures(testSigs), sizes); + + isPrimitiveTest(TypeX.forSignatures(testSigs), isPrimitive); + } + + public void testNameAndSigWithInners() { + TypeX t = TypeX.forName("java.util.Map$Entry"); + assertEquals(t.getName(), "java.util.Map$Entry"); + assertEquals(t.getSignature(), "Ljava/util/Map$Entry;"); + assertEquals(t.getDeclaringType(), TypeX.forName("java.util.Map")); + assertNull(TypeX.forName("java.util.Map").getDeclaringType()); + } + + private void isPrimitiveTest(TypeX[] types, boolean[] isPrimitives) { + for (int i = 0, len = types.length; i < len; i++) { + TypeX type = types[i]; + boolean b = isPrimitives[i]; + assertEquals(type + " is primitive: ", b, type.isPrimitive()); + } + } + + private void sizeTest(TypeX[] types, int[] sizes) { + for (int i = 0, len = types.length; i < len; i++) { + TypeX type = types[i]; + int size = sizes[i]; + assertEquals("size of " + type + ": ", size, type.getSize()); + } + } + + private void arrayTest(TypeX[] types, String[] components) { + for (int i = 0, len = types.length; i < len; i++) { + TypeX type = types[i]; + String component = components[i]; + assertEquals(type + " is array: ", component != null, type.isArray()); + if (component != null) + assertEquals(type + " componentType: ", component, + type.getComponentType().getName()); + } + } + + private void nameSignatureTest(String[] ns, String[] ss) { + for (int i = 0, len = ns.length; i < len; i++) { + String n = ns[i]; + String s = ss[i]; + TypeX tn = TypeX.forName(n); + TypeX ts = TypeX.forSignature(s); + + assertEquals("forName(n).getName()", n, + tn.getName()); + assertEquals("forSignature(s).getSignature()", s, + ts.getSignature()); + assertEquals("forName(n).getSignature()", s, + tn.getSignature()); + assertEquals("forSignature(n).getName()", n, + ts.getName()); + + TestUtil.assertCommutativeEquals(tn, tn, true); + TestUtil.assertCommutativeEquals(ts, ts, true); + TestUtil.assertCommutativeEquals(tn, ts, true); + + for (int j = 0; j < len; j++) { + if (i == j) continue; + TypeX tn1 = TypeX.forName(ns[j]); + TypeX ts1 = TypeX.forSignature(ss[j]); + TestUtil.assertCommutativeEquals(tn, tn1, false); + TestUtil.assertCommutativeEquals(ts, tn1, false); + TestUtil.assertCommutativeEquals(tn, ts1, false); + TestUtil.assertCommutativeEquals(ts, ts1, false); + } + } + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/AfterReturningWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/AfterReturningWeaveTestCase.java new file mode 100644 index 000000000..a66fc0d40 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/AfterReturningWeaveTestCase.java @@ -0,0 +1,58 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; + +import org.aspectj.weaver.ShadowMunger; + +public class AfterReturningWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public AfterReturningWeaveTestCase(String name) { + super(name); + } + + public void testAfterReturning() throws IOException { + weaveTest( + getStandardTargets(), + "AfterReturning", + makeAdviceAll("afterReturning")); + } + + public void testAfterReturningParam() throws IOException { + weaveTest( + getStandardTargets(), + "AfterReturningParam", + makeAdviceField("afterReturning", "java.lang.Object")); + } + public void testAfterReturningCheckcastParam() throws IOException { + weaveTest( + getStandardTargets(), + "AfterReturningCheckcastParam", + makeAdviceField("afterReturning", "java.rmi.server.LogStream")); + } + + public void testAfterReturningConversionParam() throws IOException { + String mungerString = + "afterReturning(): call(int *.*(..)) -> " + + "static void Aspect.ajc_afterReturning_field_get(java.lang.Object)"; + ShadowMunger cm = makeConcreteAdvice(mungerString, 1); + + weaveTest("FancyHelloWorld", "AfterReturningConversionParam", cm); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/AfterThrowingWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/AfterThrowingWeaveTestCase.java new file mode 100644 index 000000000..0202fdb69 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/AfterThrowingWeaveTestCase.java @@ -0,0 +1,43 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; + +import org.aspectj.weaver.*; + +public class AfterThrowingWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public AfterThrowingWeaveTestCase(String name) { + super(name); + } + + public void testAfterThrowing() throws IOException { + weaveTest(getStandardTargets(), "AfterThrowing", makeAdviceAll("afterThrowing")); + } + public void testAfterThrowingParam() throws IOException { + BcelWorld world = new BcelWorld(); + + ShadowMunger myMunger = + world.shadowMunger("afterThrowing(): get(* *.out) -> static void Aspect.ajc_afterThrowing_field_get(java.lang.Throwable)", + Advice.ExtraArgument); + ShadowMunger cm = myMunger.concretize(ResolvedTypeX.MISSING, world, null); + + weaveTest(getStandardTargets(), "AfterThrowingParam", cm); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/AfterWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/AfterWeaveTestCase.java new file mode 100644 index 000000000..ef91d979f --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/AfterWeaveTestCase.java @@ -0,0 +1,34 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.util.*; +import java.io.*; + +import junit.framework.TestResult; + +public class AfterWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public AfterWeaveTestCase(String name) { + super(name); + } + + + public void testAfter() throws IOException { + weaveTest(getStandardTargets(), "After", makeAdviceAll("after")); + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/ArgsWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/ArgsWeaveTestCase.java new file mode 100644 index 000000000..e0761bf0d --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/ArgsWeaveTestCase.java @@ -0,0 +1,109 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.util.*; +import java.io.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.*; + +/**. + */ +public class ArgsWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public ArgsWeaveTestCase(String name) { + super(name); + } + + + public void testAfterReturningArgs() throws IOException { + weaveTest("HelloWorld", "ArgsAfterReturningHelloWorld", makeArgsMunger("afterReturning")); + } + + + public void testFancyAfterReturningArgs() throws IOException { + weaveTest("FancyHelloWorld", "ArgsAfterReturningFancyHelloWorld", makeArgsMunger("afterReturning")); + } + + public void testThrowing() throws IOException { + weaveTest("HelloWorld", "ArgsAfterThrowingHelloWorld", makeArgsMunger("afterThrowing")); + } + + public void testLots() throws IOException { + List l = new ArrayList(); + + + BcelAdvice p1 = + makeArgsMunger("before"); + + BcelAdvice p2 = + makeArgsMunger("afterThrowing"); + + BcelAdvice p3 = + makeArgsMunger("afterReturning"); + + l.add(p1); + l.add(p2); + l.add(p3); + + + weaveTest("HelloWorld", "ArgsBeforeAfterHelloWorld", addLexicalOrder(l)); + } + + private InstructionList getArgsAdviceTag(BcelShadow shadow, String where) { + String methodName = + "ajc_" + where + "_" + shadow.getKind().toLegalJavaIdentifier(); + InstructionFactory fact = shadow.getFactory(); + InstructionList il = new InstructionList(); + + + il.append( + BcelRenderer.renderExpr( + fact, + new BcelWorld(), + shadow.getArgVar(0), + Type.OBJECT)); + + il.append( + fact.createInvoke( + "Aspect", + methodName, + Type.VOID, + new Type[] { Type.OBJECT }, + Constants.INVOKESTATIC)); + + return il; + } + + private BcelAdvice makeArgsMunger(final String kindx) { + return new BcelAdvice(AdviceKind.stringToKind(kindx), makePointcutNoZeroArg(), + Member.method(TypeX.forName("Aspect"), 0, "foo", "()V"), 0, -1, -1, null, + world.resolve(TypeX.forName("Aspect"))) { + public void specializeOn(Shadow shadow) { + super.specializeOn(shadow); + shadow.getArgVar(0); + } + public InstructionList getAdviceInstructions(BcelShadow shadow, BcelVar extraVar, InstructionHandle fk) { + return getArgsAdviceTag(shadow, kindx); + } + }; + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/AroundArgsWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/AroundArgsWeaveTestCase.java new file mode 100644 index 000000000..47b80d7ef --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/AroundArgsWeaveTestCase.java @@ -0,0 +1,41 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; + +import org.aspectj.weaver.ShadowMunger; + +public class AroundArgsWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public AroundArgsWeaveTestCase(String name) { + super(name); + } + + public void testWeave() throws IOException + { + String label = "AroundArgs"; + ShadowMunger p = + makeConcreteAdvice( + "around(list) : " + + "(call(public * add(..)) && target(list)) -> " + + "static boolean Aspect.ajc_around0" + + "(java.util.ArrayList, org.aspectj.runtime.internal.AroundClosure)"); + weaveTest(new String[] {"DynamicHelloWorld"}, label, p); + + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/AroundWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/AroundWeaveTestCase.java new file mode 100644 index 000000000..28d0e1a7a --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/AroundWeaveTestCase.java @@ -0,0 +1,93 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; +import java.lang.reflect.Modifier; +import java.util.*; + +import org.aspectj.weaver.*; + +public class AroundWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public AroundWeaveTestCase(String name) { + super(name); + } + + public void testAround() throws IOException { + aroundTest("Around", true); + } + + public void testAroundAll() throws IOException { + aroundTest("AroundAll", false); + } + + public void testAroundAndOthers() throws IOException { + aroundTestAndOthers("AroundAndOthers", true); + } + + public void testAroundAllAndOthers() throws IOException { + aroundTestAndOthers("AroundAllAndOthers", false); + } + + + private BcelAdvice makeAroundMunger(final boolean matchOnlyPrintln) { + BcelWorld world = new BcelWorld(); + final Member sig = + Member.method( + TypeX.forName("Aspect"), + Modifier.STATIC, + "ajc_around", + "(Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object;"); + + return new BcelAdvice( + AdviceKind.stringToKind("around"), + matchOnlyPrintln ? makePointcutPrintln() : makePointcutAll(), + sig, 0, -1, -1, null, TypeX.forName("Aspect").resolve(world)) + { + public void specializeOn(Shadow s) { + super.specializeOn(s); + ((BcelShadow) s).initializeForAroundClosure(); + } + }; + } + + private void aroundTest(String outName, final boolean matchOnlyPrintln) throws IOException { + weaveTest(getStandardTargets(), outName, makeAroundMunger(matchOnlyPrintln)); + } + + private void aroundTestAndOthers(String outName, final boolean matchOnlyPrintln) + throws IOException + { + + List l = new ArrayList(); + + // the afterReturning was taken out to avoid circular advice dependency + + l.addAll(makeAdviceAll("before", matchOnlyPrintln)); + //l.addAll(makeAdviceAll("afterReturning", matchOnlyPrintln)); + + l.add(makeAroundMunger(matchOnlyPrintln)); + + l.addAll(makeAdviceAll("before", matchOnlyPrintln)); + //l.addAll(makeAdviceAll("afterReturning", matchOnlyPrintln)); + + l.add(makeAroundMunger(matchOnlyPrintln)); + weaveTest(getStandardTargets(), outName, addLexicalOrder(l)); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/BcelTests.java b/weaver/testsrc/org/aspectj/weaver/bcel/BcelTests.java new file mode 100644 index 000000000..88b252b6a --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/BcelTests.java @@ -0,0 +1,52 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import junit.framework.*; + +public class BcelTests extends TestCase { + + public static Test suite() { + TestSuite suite = new TestSuite(BcelTests.class.getName()); + // abstract + //suite.addTestSuite(WeaveTestCase.class); + //$JUnit-BEGIN$ + suite.addTestSuite(AfterReturningWeaveTestCase.class); + suite.addTestSuite(AfterThrowingWeaveTestCase.class); + suite.addTestSuite(AfterWeaveTestCase.class); + suite.addTestSuite(ArgsWeaveTestCase.class); + suite.addTestSuite(AroundArgsWeaveTestCase.class); + suite.addTestSuite(AroundWeaveTestCase.class); + suite.addTestSuite(BeforeWeaveTestCase.class); + suite.addTestSuite(CheckerTestCase.class); + suite.addTestSuite(FieldSetTestCase.class); + suite.addTestSuite(HierarchyDependsTestCase.class); + suite.addTestSuite(IdWeaveTestCase.class); + suite.addTestSuite(MoveInstructionsWeaveTestCase.class); + suite.addTestSuite(NonstaticWeaveTestCase.class); + suite.addTestSuite(PatternWeaveTestCase.class); + suite.addTestSuite(PointcutResidueTestCase.class); + suite.addTestSuite(TraceJarWeaveTestCase.class); + suite.addTestSuite(TjpWeaveTestCase.class); + suite.addTestSuite(UtilityTestCase.class); + suite.addTestSuite(WeaveOrderTestCase.class); + suite.addTestSuite(WorldTestCase.class); + suite.addTestSuite(ZipTestCase.class); + //$JUnit-END$ + return suite; + } + + public BcelTests(String name) { super(name); } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/BeforeWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/BeforeWeaveTestCase.java new file mode 100644 index 000000000..04a285096 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/BeforeWeaveTestCase.java @@ -0,0 +1,31 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; + +public class BeforeWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public BeforeWeaveTestCase(String name) { + super(name); + } + + + public void testBefore() throws IOException { + weaveTest(getStandardTargets(), "Before", makeAdviceAll("before")); + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/CheckerTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/CheckerTestCase.java new file mode 100644 index 000000000..f0a2747e8 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/CheckerTestCase.java @@ -0,0 +1,48 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; + +import org.aspectj.weaver.Checker; +import org.aspectj.weaver.patterns.DeclareErrorOrWarning; +import org.aspectj.bridge.*; +import org.aspectj.bridge.MessageHandler; + +public class CheckerTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public CheckerTestCase(String name) { + super(name); + } + + + public void testStaticTjp() throws IOException { + Checker checker = new Checker( + new DeclareErrorOrWarning(true, makePointcutPrintln(), "hey, we found a println")); + + MessageHandler handler = new MessageHandler(); + world.setMessageHandler(handler); + + weaveTest("HelloWorld", "IdHelloWorld", checker); + assertEquals(1, handler.numMessages(IMessage.ERROR, false)); + + handler = new MessageHandler(); + world.setMessageHandler(handler); + weaveTest("FancyHelloWorld", "IdFancyHelloWorld", checker); + assertEquals(3, handler.numMessages(IMessage.ERROR, false)); + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/FieldSetTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/FieldSetTestCase.java new file mode 100644 index 000000000..15d1fa680 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/FieldSetTestCase.java @@ -0,0 +1,35 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; +import java.util.Collections; + +public class FieldSetTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public FieldSetTestCase(String name) { + super(name); + } + + public void testBefore() throws IOException { + weaveTest( + "FieldyHelloWorld", + "FieldSet", + makeAdviceAll("before") + ); + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/HierarchyDependsTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/HierarchyDependsTestCase.java new file mode 100644 index 000000000..939a62748 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/HierarchyDependsTestCase.java @@ -0,0 +1,67 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import junit.framework.TestCase; + +import org.apache.bcel.classfile.JavaClass; +import org.aspectj.weaver.TypeX; +import org.aspectj.weaver.patterns.*; + + +public class HierarchyDependsTestCase extends TestCase { + + /** + * Constructor for ParserTestCase. + * @param arg0 + */ + public HierarchyDependsTestCase(String arg0) { + super(arg0); + } + + + public void testHierarchyDepends() { + BcelWorld world = new BcelWorld(); + TypePatternQuestions questions = new TypePatternQuestions(); + BcelObjectType runnableType = (BcelObjectType)world.resolve("java.lang.Runnable"); + BcelObjectType numberType = (BcelObjectType)world.resolve("java.lang.Number"); + BcelObjectType integerType = (BcelObjectType)world.resolve("java.lang.Integer"); + BcelObjectType stringType = (BcelObjectType)world.resolve("java.lang.String"); + + + TypePattern numberPattern = new ExactTypePattern(numberType, false); + questions.askQuestion(numberPattern, integerType, TypePattern.STATIC); + questions.askQuestion(numberPattern, integerType, TypePattern.DYNAMIC); + assertNull(questions.anyChanges()); + + JavaClass saveClass = integerType.getJavaClass(); + integerType.replaceJavaClass(stringType.getJavaClass()); + assertNotNull(questions.anyChanges()); + + integerType.replaceJavaClass(saveClass); + assertNull(questions.anyChanges()); + + TypePattern runnablePattern = new ExactTypePattern(runnableType, false); + questions.askQuestion(runnablePattern, stringType, TypePattern.DYNAMIC); + assertNull(questions.toString(), questions.anyChanges()); + + saveClass = stringType.getJavaClass(); + stringType.replaceJavaClass(numberType.getJavaClass()); + assertNotNull(questions.toString(), questions.anyChanges()); + + stringType.replaceJavaClass(saveClass); + assertNull(questions.toString(), questions.anyChanges()); + } +} + diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/IdWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/IdWeaveTestCase.java new file mode 100644 index 000000000..031bf1c8d --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/IdWeaveTestCase.java @@ -0,0 +1,107 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; +import java.util.*; + +import org.apache.bcel.util.ClassPath; +import org.aspectj.weaver.*; +import org.aspectj.weaver.patterns.Pointcut; + +public class IdWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public IdWeaveTestCase(String name) { + super(name); + } + + public void testFancyId() throws IOException { + final List l = new ArrayList(); + Pointcut pointcut2 = makePointcutAll(); + BcelAdvice p = + new BcelAdvice(null, pointcut2, null, 0, -1, -1, null, null) { + public boolean match(Shadow shadow, World world) { + if (super.match(shadow, world)) { + l.add(shadow); + } + return false; + } + }; + weaveTest(new String[] {"FancyHelloWorld"}, "Id", p); + + checkShadowSet(l, new String[] { + "method-call(void java.io.PrintStream.println(java.lang.Object))", + "method-call(void java.io.PrintStream.println(java.lang.String))", + "method-call(java.lang.StringBuffer java.lang.StringBuffer.append(int))", + "method-call(java.lang.String java.lang.StringBuffer.toString())", + "method-execution(java.lang.String FancyHelloWorld.getName())", + "field-get(java.io.PrintStream java.lang.System.out)", + "method-call(void java.io.PrintStream.println(java.lang.String))", + "method-execution(void FancyHelloWorld.main(java.lang.String[]))", + "method-call(int java.lang.String.hashCode())", + "constructor-execution(void FancyHelloWorld.<init>())", + "constructor-call(void java.lang.StringBuffer.<init>(java.lang.String))" + }); + } + + public void testId() throws IOException { + final List l = new ArrayList(); + BcelAdvice p = new BcelAdvice(null, makePointcutAll(), null, 0, -1, -1, null, null) { + public void implementOn(Shadow shadow) { + l.add(shadow); + } + }; + weaveTest(new String[] {"HelloWorld"}, "Id", p); + + checkShadowSet(l, new String[] { + "method-execution(void HelloWorld.main(java.lang.String[]))", + "method-call(void java.io.PrintStream.println(java.lang.String))", + "field-get(java.io.PrintStream java.lang.System.out)", + "constructor-execution(void HelloWorld.<init>())", + }); + } + + // this test requires that Trace has been unzipped and placed in the correct place + public void testTraceId() throws IOException { + String saveClassDir = classDir; + try { + classDir = "testdata/dummyAspect.jar"; + + + + final List l = new ArrayList(); + BcelAdvice p = new BcelAdvice(null, makePointcutAll(), null, 0, -1, -1, null, null) { + public void implementOn(Shadow shadow) { + l.add(shadow); + } + }; + boolean tempRunTests = runTests; + runTests = false; + weaveTest(new String[] {"DummyAspect"}, "Id", p); + runTests = tempRunTests; + + checkShadowSet(l, new String[] { + "constructor-execution(void DummyAspect.<init>())", + // XXX waiting on parser stuff + //"advice-execution(void DummyAspect.ajc_before_1(java.lang.Object))", + }); + } finally { + classDir = saveClassDir; + } + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/MegaZipTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/MegaZipTestCase.java new file mode 100644 index 000000000..72ad0d0a4 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/MegaZipTestCase.java @@ -0,0 +1,111 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; + +import org.aspectj.weaver.*; + +public class MegaZipTestCase extends WeaveTestCase { + + public MegaZipTestCase(String arg0) { + super(arg0); + } + + + private BcelAdvice makeAroundMunger(final boolean matchOnlyPrintln) { + BcelWorld world = new BcelWorld(); + final Member sig = + Member.method( + TypeX.forName("fluffy.Aspect"), + Modifier.STATIC, + "aroundFun", + "(Lorg/aspectj/runtime/internal/AroundClosure;)Ljava/lang/Object;"); + + return new BcelAdvice( + AdviceKind.stringToKind("around"), + matchOnlyPrintln ? makePointcutPrintln() : makePointcutAll(), + sig, 0, -1, -1, null, null) + { + public void specializeOn(Shadow s) { + super.specializeOn(s); + ((BcelShadow) s).initializeForAroundClosure(); + } + }; + } + + public List getShadowMungers() { + List ret = new ArrayList(); + ret.add( + makeConcreteAdvice( + "before" + + "(): call(* *.println(..)) -> static void fluffy.Aspect.before_method_call()")); + ret.add( + makeConcreteAdvice( + "afterReturning" + + "(): call(* *.println(..)) -> static void fluffy.Aspect.afterReturning_method_call()")); + + ret.add( + makeConcreteAdvice( + "before" + + "(): execution(* *.*(..)) -> static void fluffy.Aspect.ignoreMe()")); + + ret.add( + makeConcreteAdvice( + "afterReturning" + + "(): execution(* *.*(..)) -> static void fluffy.Aspect.ignoreMe()")); + + ret.add( + makeConcreteAdvice( + "afterThrowing" + + "(): execution(* *.*(..)) -> static void fluffy.Aspect.afterThrowing_method_execution(java.lang.Throwable)", + 1)); + ret.add( + makeConcreteAdvice( + "after" + + "(): execution(* *.*(..)) -> static void fluffy.Aspect.ignoreMe()")); + + + ret.add(makeAroundMunger(true)); + return ret; + } + + + public void zipTest(String fileName) throws IOException { + long startTime = System.currentTimeMillis(); + File inFile = new File("testdata", fileName); + File outFile = new File("out", fileName); + outFile.delete(); + + world = new BcelWorld("c:/apps/java-1.3.1_04/lib/tools.jar"); + BcelWeaver weaver1 = new BcelWeaver(world); + + + ZipFileWeaver weaver = new ZipFileWeaver(inFile); + + weaver1.setShadowMungers(getShadowMungers()); + + weaver.weave(weaver1, outFile); + assertTrue(outFile.lastModified() > startTime); + } + + // this is something we test every now and again. + public void testBig() throws IOException { + System.out.println("could take 80 seconds..."); + zipTest("aspectjtools.jar"); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/MoveInstructionsWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/MoveInstructionsWeaveTestCase.java new file mode 100644 index 000000000..3c964c4ae --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/MoveInstructionsWeaveTestCase.java @@ -0,0 +1,73 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.util.*; +import java.io.*; + +import junit.framework.TestResult; + +import org.apache.bcel.generic.*; +import org.apache.bcel.generic.InstructionList; +import org.aspectj.weaver.*; + +public class MoveInstructionsWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public MoveInstructionsWeaveTestCase(String name) { + super(name); + } + public void testHello() throws IOException { + BcelAdvice p = new BcelAdvice(null, makePointcutAll(), null, 0, -1, -1, null, null) { + public void specializeOn(Shadow s) { + super.specializeOn(s); + ((BcelShadow) s).initializeForAroundClosure(); + } + public void implementOn(Shadow s) { + BcelShadow shadow = (BcelShadow) s; + LazyMethodGen newMethod = shadow.extractMethod(shadow.getSignature().getExtractableName() + "_extracted"); + shadow.getRange().append(shadow.makeCallToCallback(newMethod)); + + if (! shadow.isFallsThrough()) { + shadow.getRange().append(shadow.getFactory().createReturn(newMethod.getReturnType())); + } + } + }; + + weaveTest("HelloWorld", "ExtractedHelloWorld", p); + } + + static int counter = 0; + public void testFancyHello() throws IOException { + BcelAdvice p = new BcelAdvice(null, makePointcutAll(), null, 0, -1, -1, null, null) { + public void specializeOn(Shadow s) { + super.specializeOn(s); + ((BcelShadow) s).initializeForAroundClosure(); + } + public void implementOn(Shadow s) { + BcelShadow shadow = (BcelShadow) s; + LazyMethodGen newMethod = shadow.extractMethod(shadow.getSignature().getExtractableName() + "_extracted" + counter++); + shadow.getRange().append(shadow.makeCallToCallback(newMethod)); + + if (! shadow.isFallsThrough()) { + shadow.getRange().append(shadow.getFactory().createReturn(newMethod.getReturnType())); + } + } + }; + + weaveTest("FancyHelloWorld", "ExtractedFancyHelloWorld", p); + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/NonstaticWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/NonstaticWeaveTestCase.java new file mode 100644 index 000000000..75247d3f2 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/NonstaticWeaveTestCase.java @@ -0,0 +1,86 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; +import java.util.*; +import java.util.List; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.ShadowMunger; +import org.aspectj.weaver.patterns.*; + +public class NonstaticWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public NonstaticWeaveTestCase(String name) { + super(name); + } + + + public void testBefore() throws IOException { + String s = "before(): get(* *.*) -> void Aspect.ajc_before()"; + PerClause per = new PerSingleton(); + per = per.concretize(world.resolve("Aspect")); + + ShadowMunger myMunger = this.makeConcreteAdvice(s, 0, per); + + weaveTest(getStandardTargets(), "NonStaticBefore", myMunger); + } + + public void testBeforeCflow() throws IOException { + String s = "before(): get(* *.*) -> void Aspect.ajc_before()"; + PerClause per = new PatternParser("percflow(execution(void main(..)))").maybeParsePerClause(); + per.resolve(new TestScope(new String[0], new String[0], world)); + + ResolvedTypeX onAspect = world.resolve("Aspect"); + CrosscuttingMembers xcut = new CrosscuttingMembers(onAspect); + onAspect.crosscuttingMembers = xcut; + + per = per.concretize(onAspect); + + ShadowMunger myMunger = this.makeConcreteAdvice(s, 0, per); + + xcut.addConcreteShadowMunger(myMunger); + + + weaveTest(getStandardTargets(), "CflowNonStaticBefore", xcut.getShadowMungers()); + } + + public void testBeforePerThis() throws IOException { + String s = "before(): call(* println(..)) -> void Aspect.ajc_before()"; + PerClause per = new PatternParser("pertarget(call(* println(..)))").maybeParsePerClause(); + per.resolve(new TestScope(new String[0], new String[0], world)); + + ResolvedTypeX onAspect = world.resolve("Aspect"); + CrosscuttingMembers xcut = new CrosscuttingMembers(onAspect); + onAspect.crosscuttingMembers = xcut; + per = per.concretize(onAspect); + + ShadowMunger myMunger = this.makeConcreteAdvice(s, 0, per); + xcut.addConcreteShadowMunger(myMunger); + +// List mungers = new ArrayList(); +// mungers.add(myMunger); +// mungers.addAll(onAspect.getExtraConcreteShadowMungers()); + + + weaveTest(getStandardTargets(), "PerThisNonStaticBefore", xcut.getShadowMungers()); + } + + + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/PatternWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/PatternWeaveTestCase.java new file mode 100644 index 000000000..22c0a2011 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/PatternWeaveTestCase.java @@ -0,0 +1,117 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.util.*; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.patterns.*; + +public class PatternWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public PatternWeaveTestCase(String name) { + super(name); + } + + String[] none = new String[0]; + + + public void testPublic() throws IOException { + String[] publicHello = new String[] { + "method-execution(void HelloWorld.main(java.lang.String[]))", + }; + String[] publicFancyHello = new String[] { + "method-execution(void FancyHelloWorld.main(java.lang.String[]))", + "method-execution(java.lang.String FancyHelloWorld.getName())", + }; + checkPointcut("execution(public * *(..))", publicHello, publicFancyHello); + } + + public void testPrintln() throws IOException { + String[] callPrintlnHello = new String[] { + "method-call(void java.io.PrintStream.println(java.lang.String))", + }; + String[] callPrintlnFancyHello = new String[] { + "method-call(void java.io.PrintStream.println(java.lang.String))", + "method-call(void java.io.PrintStream.println(java.lang.String))", + "method-call(void java.io.PrintStream.println(java.lang.Object))", + }; + checkPointcut("call(* println(*))", callPrintlnHello, callPrintlnFancyHello); + } + + public void testMumble() throws IOException { + checkPointcut("call(* mumble(*))", none, none); + } + + public void testFooBar() throws IOException { + checkPointcut("call(FooBar *(..))", none, none); + } + + public void testGetOut() throws IOException { + String[] getOutHello = new String[] { + "field-get(java.io.PrintStream java.lang.System.out)", + }; + + checkPointcut("get(* java.lang.System.out)", getOutHello, getOutHello); + } + + private Pointcut makePointcut(String s) { + return new PatternParser(s).parsePointcut(); + } + + private void checkPointcut(String pointcutSource, String[] expectedHelloShadows, + String[] expectedFancyShadows) throws IOException + { + Pointcut sp = Pointcut.fromString(pointcutSource); + Pointcut rp = sp.resolve(new SimpleScope(world, FormalBinding.NONE)); + Pointcut cp = rp.concretize(ResolvedTypeX.MISSING, 0); + + final List l = new ArrayList(); + BcelAdvice p = new BcelAdvice(null, cp, null, 0, -1, -1, null, null) { + public void implementOn(Shadow shadow) { + l.add(shadow); + } + }; + weaveTest(new String[] {"HelloWorld"}, "PatternWeave", p); + + checkShadowSet(l, expectedHelloShadows); + + + l.clear(); + weaveTest(new String[] {"FancyHelloWorld"}, "PatternWeave", p); + + checkShadowSet(l, expectedFancyShadows); + + checkSerialize(rp); + } + + public void checkSerialize(Pointcut p) throws IOException { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + Pointcut newP = Pointcut.read(in, null); + + assertEquals("write/read", p, newP); + } + + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/PointcutResidueTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/PointcutResidueTestCase.java new file mode 100644 index 000000000..7dafd2f9b --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/PointcutResidueTestCase.java @@ -0,0 +1,236 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.patterns.*; +import org.aspectj.weaver.patterns.SimpleScope; + +public class PointcutResidueTestCase extends WeaveTestCase { + { + regenerate = false; + } + public PointcutResidueTestCase(String name) { + super(name); + } + + String[] none = new String[0]; + + + // ----- + + + + + + // ---- + + + + public void testArgResidue1() throws IOException { + checkMultiArgWeave( + "StringResidue1", + "call(* *(java.lang.Object, java.lang.Object)) && args(java.lang.String, java.lang.String)"); + } + + public void testArgResidue2() throws IOException { + checkMultiArgWeave( + "StringResidue2", + "call(* *(java.lang.Object, java.lang.Object)) && args(.., java.lang.String)"); + } + public void testArgResidue3() throws IOException { + checkMultiArgWeave( + "StringResidue3", + "call(* *(java.lang.Object, java.lang.Object)) && args(java.lang.String, ..)"); + } + + // BETAX this is a beta feature. +// public void testArgResidue4() throws IOException { +// checkMultiArgWeave( +// "StringResidue4", +// "call(* *(java.lang.Object, java.lang.Object)) && args(.., java.lang.String, ..)"); +// } + + public void testMultiArgState() throws IOException { + checkWeave( + "StateResidue", + "MultiArgHelloWorld", + "call(* *(java.lang.Object, java.lang.Object)) && args(s, ..)", + new String[] { "java.lang.String" }, + new String[] { "s" }); + checkWeave( + "StateResidue", + "MultiArgHelloWorld", + "call(* *(java.lang.Object, java.lang.Object)) && args(s, *)", + new String[] { "java.lang.String" }, + new String[] { "s" }); + } + + + + public void testAdd() throws IOException { + checkDynamicWeave("AddResidue", "call(public * add(..)) && target(java.util.ArrayList)"); + checkDynamicWeave("AddResidue", "call(public * add(..)) && (target(java.util.ArrayList) || target(java.lang.String))"); + checkDynamicWeave("AddResidue", "call(public * add(..)) && this(java.io.Serializable) && target(java.util.ArrayList) && !this(java.lang.Integer)"); + } + + public void testNot() throws IOException { + checkDynamicWeave("AddNotResidue", "call(public * add(..)) && !target(java.util.ArrayList)"); + checkDynamicWeave("AddNotResidue", "call(public * add(..)) && !(target(java.util.ArrayList) || target(java.lang.String)) "); + checkDynamicWeave("AddNotResidue", "call(public * add(..)) && target(java.lang.Object) && !target(java.util.ArrayList)"); + } + + public void testState() throws IOException { + checkWeave( + "AddStateResidue", + "DynamicHelloWorld", + "call(public * add(..)) && target(list)", + new String[] { "java.util.ArrayList" }, + new String[] { "list" }); + checkWeave( + "AddStateResidue", + "DynamicHelloWorld", + "target(foo) && !target(java.lang.Integer) && call(public * add(..))", + new String[] { "java.util.ArrayList" }, + new String[] { "foo" }); + checkDynamicWeave( + "AddResidue", + "call(public * add(..)) && (target(java.util.ArrayList) || target(java.lang.String))"); + checkDynamicWeave( + "AddResidue", + "call(public * add(..)) && this(java.io.Serializable) && target(java.util.ArrayList) && !this(java.lang.Integer)"); + } + + public void testNoResidueArgs() throws IOException { + checkDynamicWeave("NoResidue", "call(public * add(..)) && args(java.lang.Object)"); + checkDynamicWeave("NoResidue", "call(public * add(..)) && args(*)"); + checkDynamicWeave("NoResidue", "call(public * add(..))"); + } + + // ---- cflow tests + + public void testCflowState() throws IOException { + checkWeave( + "CflowStateResidue", + "DynamicHelloWorld", + "cflow(call(public * add(..)) && target(list)) && execution(public void main(..))", + new String[] { "java.util.ArrayList" }, + new String[] { "list" }); +// checkWeave( +// "CflowStateResidue", +// "DynamicHelloWorld", +// "cflow(call(public * add(..)) && target(list)) && this(obj) && execution(public void doit(..))", +// new String[] { "java.lang.Object", "java.util.ArrayList" }, +// new String[] { "obj", "list" }); +// checkWeave( +// "AddStateResidue", +// "DynamicHelloWorld", +// "target(foo) && !target(java.lang.Integer) && call(public * add(..))", +// new String[] { "java.util.ArrayList" }, +// new String[] { "foo" }); +// checkDynamicWeave( +// "AddResidue", +// "call(public * add(..)) && (target(java.util.ArrayList) || target(java.lang.String))"); +// checkDynamicWeave( +// "AddResidue", +// "call(public * add(..)) && this(java.io.Serializable) && target(java.util.ArrayList) && !this(java.lang.Integer)"); + } + + + + + + // ---- + + private void checkDynamicWeave(String label, String pointcutSource) throws IOException { + checkWeave(label, "DynamicHelloWorld", pointcutSource, new String[0], new String[0]); + } + + private void checkMultiArgWeave(String label, String pointcutSource) throws IOException { + checkWeave(label, "MultiArgHelloWorld", pointcutSource, new String[0], new String[0]); + } + + private void checkWeave( + String label, + String filename, + String pointcutSource, + String[] formalTypes, + String[] formalNames) + throws IOException + { + final Pointcut sp = Pointcut.fromString(pointcutSource); + final Pointcut rp = + sp.resolve( + new SimpleScope( + world, + SimpleScope.makeFormalBindings(TypeX.forNames(formalTypes), + formalNames) + )); + + ShadowMunger pp = + world.concreteAdvice( + AdviceKind.Before, + rp, + Member.method( + TypeX.forName("Aspect"), + Modifier.STATIC, + "ajc_before_0", + Member.typesToSignature( + ResolvedTypeX.VOID, + TypeX.forNames(formalTypes))), + 0, -1, -1, null); + + ResolvedTypeX inAspect = world.resolve("Aspect"); + CrosscuttingMembers xcut = new CrosscuttingMembers(inAspect); + inAspect.crosscuttingMembers = xcut; + + ShadowMunger cp = pp.concretize(inAspect, world, null); + + xcut.addConcreteShadowMunger(cp); + + //System.out.println("extras: " + inAspect.getExtraConcreteShadowMungers()); +// List advice = new ArrayList(); +// advice.add(cp); +// advice.addAll(inAspect.getExtraConcreteShadowMungers()); + weaveTest(new String[] { filename }, label, xcut.getShadowMungers()); + + checkSerialize(rp); + } + + public void weaveTest(String name, String outName, ShadowMunger planner) throws IOException { + List l = new ArrayList(1); + l.add(planner); + weaveTest(name, outName, l); + } + + + public void checkSerialize(Pointcut p) throws IOException { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + Pointcut newP = Pointcut.read(in, null); + + assertEquals("write/read", p, newP); + } + + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/TjpWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/TjpWeaveTestCase.java new file mode 100644 index 000000000..32aede4d7 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/TjpWeaveTestCase.java @@ -0,0 +1,97 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.util.*; +import java.io.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.*; + +public class TjpWeaveTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public TjpWeaveTestCase(String name) { + super(name); + } + + + public void testStaticTjp() throws IOException { + BcelAdvice munger = new BcelAdvice( + AdviceKind.stringToKind("before"), + makePointcutAll(), + Member.methodFromString("static void Aspect.ajc_before(org.aspectj.lang.JoinPoint$StaticPart)"), + Advice.ThisJoinPointStaticPart, -1, -1, null, null); + + weaveTest("HelloWorld", "StaticTjpBeforeHelloWorld", munger); + } + + + public void testEnclosingStaticTjp() throws IOException { + BcelAdvice munger = new BcelAdvice( + AdviceKind.stringToKind("before"), + makePointcutAll(), + Member.methodFromString("static void Aspect.ajc_before(org.aspectj.lang.JoinPoint$StaticPart)"), + Advice.ThisEnclosingJoinPointStaticPart, -1, -1, null, null); + + weaveTest("HelloWorld", "StaticEnclosingTjpBeforeHelloWorld", munger); + } + + + public void testTjp() throws IOException { + BcelAdvice munger = new BcelAdvice( + AdviceKind.stringToKind("before"), + makePointcutAll(), + Member.methodFromString("static void Aspect.ajc_before(org.aspectj.lang.JoinPoint)"), + Advice.ThisJoinPoint, -1, -1, null, null); + + weaveTest("HelloWorld", "TjpBeforeHelloWorld", munger); + } + + public void testAroundTjp() throws IOException { + BcelAdvice munger = new BcelAdvice( + AdviceKind.stringToKind("around"), + makePointcutAll(), + Member.methodFromString("static java.lang.Object Aspect.ajc_around(org.aspectj.runtime.internal.AroundClosure, org.aspectj.lang.JoinPoint)"), + Advice.ThisJoinPoint | Advice.ExtraArgument, -1, -1, null, null); + + weaveTest("HelloWorld", "TjpAroundHelloWorld", munger); + } + + public void testAround2Tjp() throws IOException { + BcelAdvice munger1 = new BcelAdvice( + AdviceKind.stringToKind("around"), + makePointcutAll(), + Member.methodFromString("static java.lang.Object Aspect.ajc_around(org.aspectj.runtime.internal.AroundClosure, org.aspectj.lang.JoinPoint)"), + Advice.ThisJoinPoint | Advice.ExtraArgument, -1, -1, null, + world.resolve(TypeX.forName("Aspect"))); + + BcelAdvice munger2 = new BcelAdvice( + AdviceKind.stringToKind("around"), + makePointcutAll(), + Member.methodFromString("static java.lang.Object Aspect.ajc_around(org.aspectj.runtime.internal.AroundClosure, org.aspectj.lang.JoinPoint)"), + Advice.ThisJoinPoint | Advice.ExtraArgument, -1, -1, null, + world.resolve(TypeX.forName("Aspect"))); + + weaveTest("HelloWorld", "TjpAround2HelloWorld", Arrays.asList(new BcelAdvice[] {munger1, munger2})); + } + + + + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/TraceJarWeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/TraceJarWeaveTestCase.java new file mode 100644 index 000000000..ed06ecd1e --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/TraceJarWeaveTestCase.java @@ -0,0 +1,40 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.IOException; + +public class TraceJarWeaveTestCase extends WeaveTestCase { + { + regenerate = true; + } + + public TraceJarWeaveTestCase(String name) { + super(name); + } + + + public void testTraceJar() throws IOException { + world = new BcelWorld(getTraceJar()); + BcelWeaver weaver = new BcelWeaver(world); + weaver.addLibraryAspect("MyTrace"); + + UnwovenClassFile classFile = makeUnwovenClassFile(classDir, "DynamicHelloWorld", outDir); + + weaver.addClassFile(classFile); + weaver.prepareForWeave(); + + weaveTestInner(weaver, classFile, "DynamicHelloWorld", "TraceJarHello"); + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/UtilityTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/UtilityTestCase.java new file mode 100644 index 000000000..a18856711 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/UtilityTestCase.java @@ -0,0 +1,52 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; +import java.io.*; + +import junit.framework.TestCase; + +import org.apache.bcel.util.ClassPath; + +public class UtilityTestCase extends TestCase { + + public UtilityTestCase(String name) { + super(name); + } + + public void disassembleTest(String name) throws IOException { + BcelWorld world = new BcelWorld("../bcweaver/bin"); + + LazyClassGen clazz = new LazyClassGen((BcelObjectType) world.resolve(name)); + clazz.print(); + System.out.println(); + } + + + public void testHelloWorld() throws IOException { + disassembleTest("Test"); + } + public void testFancyHelloWorld() throws IOException { + disassembleTest("FancyHelloWorld"); + } +// public void testSwitchy() throws IOException { +// disassembleTest("TestSwitchy"); +// } + + public static void main(String[] args) throws IOException { + BcelWorld world = new BcelWorld(); + LazyClassGen clazz = new LazyClassGen((BcelObjectType)world.resolve(args[0])); + clazz.print(); + } +} + diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/WeaveOrderTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/WeaveOrderTestCase.java new file mode 100644 index 000000000..a2a4c9787 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/WeaveOrderTestCase.java @@ -0,0 +1,155 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.util.*; +import java.io.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.patterns.*; +import org.aspectj.weaver.patterns.DeclareDominates; +import org.aspectj.weaver.*; + +/**. + */ +public class WeaveOrderTestCase extends WeaveTestCase { + { + regenerate = false; + } + + public WeaveOrderTestCase(String name) { + super(name); + } + + + public void testLexicalOrder() { + Advice a1 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.OBJECT, 1); + Advice a2 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.THROWABLE, 2); + + assertEquals(-1, a2.compareTo(a1)); + assertEquals(+1, a1.compareTo(a2)); + } + + public void testLexicalOrderWithAfter() { + Advice a1 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.OBJECT, 1); + Advice a2 = + makeConcreteAdvice(AdviceKind.After, TypeX.OBJECT, TypeX.THROWABLE, 2); + + assertEquals(+1, a2.compareTo(a1)); + assertEquals(-1, a1.compareTo(a2)); + + a1 = + makeConcreteAdvice(AdviceKind.After, TypeX.OBJECT, TypeX.OBJECT, 1); + a2 = + makeConcreteAdvice(AdviceKind.After, TypeX.OBJECT, TypeX.THROWABLE, 2); + + assertEquals(+1, a2.compareTo(a1)); + assertEquals(-1, a1.compareTo(a2)); + } + + public void testSubtypes() { + Advice a1 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.OBJECT, 1); + Advice a2 = + makeConcreteAdvice(AdviceKind.Before, TypeX.THROWABLE, TypeX.OBJECT, 1); + Advice a3 = + makeConcreteAdvice(AdviceKind.Before, TypeX.forName("java.lang.String"), TypeX.OBJECT, 1); + + assertEquals(+1, a2.compareTo(a1)); + assertEquals(-1, a1.compareTo(a2)); + + assertEquals(+1, a3.compareTo(a1)); + assertEquals(-1, a1.compareTo(a3)); + + assertEquals(0, a3.compareTo(a2)); + assertEquals(0, a2.compareTo(a3)); + } + + + public void testDominates() { + Declare dom = + new PatternParser("declare dominates: java.lang.String, java.lang.Throwable").parseDeclare(); + //??? concretize dom + ResolvedTypeX aType = world.resolve("Aspect"); + CrosscuttingMembers xcut = new CrosscuttingMembers(aType); + aType.crosscuttingMembers = xcut; + xcut.addDeclare(dom); + world.getCrosscuttingMembersSet().addFixedCrosscuttingMembers(aType); + + Advice a1 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.OBJECT, 1); + Advice a2 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.THROWABLE, 2); + Advice a3 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.forName("java.lang.String"), 2); + + assertEquals(-1, a2.compareTo(a1)); + assertEquals(+1, a1.compareTo(a2)); + + assertEquals(-1, a3.compareTo(a1)); + assertEquals(+1, a1.compareTo(a3)); + + + assertEquals(+1, a3.compareTo(a2)); + assertEquals(-1, a2.compareTo(a3)); + } + + public void testDominatesHarder() { + Declare dom = + new PatternParser("declare dominates: *, java.lang.String, java.lang.Throwable").parseDeclare(); + //??? concretize dom + ResolvedTypeX aType = world.resolve("Aspect"); + CrosscuttingMembers xcut = new CrosscuttingMembers(aType); + aType.crosscuttingMembers = xcut; + xcut.addDeclare(dom); + world.getCrosscuttingMembersSet().addFixedCrosscuttingMembers(aType); + + Advice a1 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.OBJECT, 2); + Advice a2 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.THROWABLE, 1); + Advice a3 = + makeConcreteAdvice(AdviceKind.Before, TypeX.OBJECT, TypeX.forName("java.lang.String"), 1); + + assertEquals(-1, a2.compareTo(a1)); + assertEquals(+1, a1.compareTo(a2)); + + assertEquals(-1, a3.compareTo(a1)); + assertEquals(+1, a1.compareTo(a3)); + + + assertEquals(+1, a3.compareTo(a2)); + assertEquals(-1, a2.compareTo(a3)); + } + + + + + private Advice makeConcreteAdvice(AdviceKind kind, TypeX declaringAspect, + TypeX concreteAspect, int lexicalPosition) + { + Advice a1 = new BcelAdvice(kind, makeResolvedPointcut("this(*)"), + Member.method(declaringAspect, 0, "foo", "()V"), + 0, lexicalPosition, lexicalPosition, null, null); + a1 = (Advice)a1.concretize(concreteAspect.resolve(world), world, null); + return a1; + } + + + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/WeaveTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/WeaveTestCase.java new file mode 100644 index 000000000..62c078e61 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/WeaveTestCase.java @@ -0,0 +1,324 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; +import java.io.*; +import java.util.*; +import java.util.zip.*; +import java.util.zip.ZipFile; + +import junit.framework.*; + +import org.apache.bcel.Constants; +import org.apache.bcel.generic.*; +import org.aspectj.weaver.*; +import org.aspectj.weaver.patterns.*; +import org.aspectj.testing.util.TestUtil; +import org.aspectj.util.FileUtil; + +public abstract class WeaveTestCase extends TestCase { + + public boolean regenerate = false; + public boolean runTests = true; + + public BcelWorld world = new BcelWorld(); + + public WeaveTestCase(String name) { + super(name); + } + + public static InstructionList getAdviceTag(BcelShadow shadow, String where) { + String methodName = + "ajc_" + where + "_" + shadow.getKind().toLegalJavaIdentifier(); + + InstructionFactory fact = shadow.getFactory(); + InvokeInstruction il = + fact.createInvoke("Aspect", methodName, Type.VOID, new Type[] { + }, Constants.INVOKESTATIC); + return new InstructionList(il); + } + + public void weaveTest(String name, String outName, ShadowMunger planner) throws IOException { + List l = new ArrayList(1); + l.add(planner); + weaveTest(name, outName, l); + } + + static String classDir = "../bcweaver/bin"; + static String outDir = "out"; + + + public void weaveTest(String name, String outName, List planners) throws IOException { + BcelWeaver weaver = new BcelWeaver(world); + + UnwovenClassFile classFile = makeUnwovenClassFile(classDir, name, outDir); + + weaver.addClassFile(classFile); + weaver.setShadowMungers(planners); + weaveTestInner(weaver, classFile, name, outName); + } + + + protected void weaveTestInner( + BcelWeaver weaver, + UnwovenClassFile classFile, + String name, + String outName) + throws IOException + { + //int preErrors = currentResult.errorCount(); + BcelObjectType classType = + (BcelObjectType) world.resolve(classFile.getClassName()); + LazyClassGen gen = weaver.weave(classFile, classType); + if (gen == null) { + // we didn't do any weaving, but let's make a gen anyway + gen = new LazyClassGen(classType); + } + try { + checkClass(gen, outDir, outName + ".txt"); + if (runTests) { + System.out.println( + "*******RUNNING: " + outName + " " + name + " *******"); + TestUtil.runMain(makeClassPath(outDir), name); + } + } catch (Error e) { + gen.print(System.err); + throw e; + } catch (RuntimeException e) { + gen.print(System.err); + throw e; + } + } + + public String makeClassPath(String outDir) { + return outDir + + File.pathSeparator + + getTraceJar() + + File.pathSeparator + + System.getProperty("java.class.path"); + } + + + /** '/' in the name indicates the location of the class + */ + public static UnwovenClassFile makeUnwovenClassFile( + String classDir, + String name, + String outDir) throws IOException { + File outFile = new File(outDir, name+".class"); + if (classDir.endsWith(".jar")) { + String fname = name+".class"; + UnwovenClassFile ret = + new UnwovenClassFile(outFile.getAbsolutePath(), + FileUtil.readAsByteArray(FileUtil.getStreamFromZip(classDir, fname))); + return ret; + } else { + File inFile = new File(classDir, name+".class"); + return new UnwovenClassFile(outFile.getAbsolutePath(), FileUtil.readAsByteArray(inFile)); + } + } + + public void checkClass(LazyClassGen gen, String outDir, String expectedFile) throws IOException { + if (regenerate) genClass(gen, outDir, expectedFile); + else realCheckClass(gen, outDir, expectedFile); + } + + void genClass(LazyClassGen gen, String outDir, String expectedFile) throws IOException { + //ClassGen b = getJavaClass(outDir, className); + FileOutputStream out = new FileOutputStream(new File("testdata", expectedFile)); + PrintStream ps = new PrintStream(out); + gen.print(ps); + ps.flush(); + + } + + void realCheckClass(LazyClassGen gen, String outDir, String expectedFile) throws IOException { + TestUtil.assertMultiLineStringEquals("classes", + FileUtil.readAsString(new File("testdata", expectedFile)), + gen.toLongString()); + } + + + // ---- + public ShadowMunger makeConcreteAdvice(String mungerString) { + return makeConcreteAdvice(mungerString, 0, null); + } + + public ShadowMunger makeConcreteAdvice(String mungerString, int extraArgFlag) { + return makeConcreteAdvice(mungerString, extraArgFlag, null); + } + + protected ShadowMunger makeConcreteAdvice(String mungerString, int extraArgFlag, PerClause perClause) { + Advice myMunger = + world.shadowMunger(mungerString, extraArgFlag); + +// PerSingleton s = new PerSingleton(); +// s.concretize(world.resolve("Aspect")); + //System.err.println(((KindedPointcut)myMunger.getPointcut().getPointcut()).getKind()); + Advice cm = (Advice) myMunger.concretize(myMunger.getDeclaringAspect().resolve(world), + world, perClause); + return cm; + } + + public ShadowMunger makeAdviceField(String kind, String extraArgType) { + return makeConcreteAdvice( + kind + + "(): get(* *.*) -> static void Aspect.ajc_" + + kind + + "_field_get(" + + extraArgType + + ")", + 1); + } + + public List makeAdviceAll(String kind, boolean matchOnlyPrintln) { + List ret = new ArrayList(); + if (matchOnlyPrintln) { + ret.add( + makeConcreteAdvice( + kind + + "(): call(* *.println(..)) -> static void Aspect.ajc_" + + kind + + "_method_execution()")); + } else { + ret.add( + makeConcreteAdvice( + kind + + "(): call(* *.*(..)) -> static void Aspect.ajc_" + + kind + + "_method_call()")); + ret.add( + makeConcreteAdvice( + kind + + "(): call(*.new(..)) -> static void Aspect.ajc_" + + kind + + "_constructor_call()")); + ret.add( + makeConcreteAdvice( + kind + + "(): execution(* *.*(..)) -> static void Aspect.ajc_" + + kind + + "_method_execution()")); + ret.add( + makeConcreteAdvice( + kind + + "(): execution(*.new(..)) -> static void Aspect.ajc_" + + kind + + "_constructor_execution()")); +// ret.add( +// makeConcreteMunger( +// kind +// + "(): staticinitialization(*) -> static void Aspect.ajc_" +// + kind +// + "_staticinitialization()")); + ret.add( + makeConcreteAdvice( + kind + "(): get(* *.*) -> static void Aspect.ajc_" + kind + "_field_get()")); +// ret.add( +// makeConcreteMunger( +// kind + "(): set(* *.*) -> static void Aspect.ajc_" + kind + "_field_set()")); + // XXX no test for advice execution, staticInitialization or (god help us) preInitialization + } + return ret; + } + + public List makeAdviceAll(final String kind) { + return makeAdviceAll(kind, false); + } + + public Pointcut makePointcutAll() { + return makeConcretePointcut("get(* *.*) || call(* *.*(..)) || execution(* *.*(..)) || call(*.new(..)) || execution(*.new(..))"); + } + public Pointcut makePointcutNoZeroArg() { + return makeConcretePointcut("call(* *.*(*, ..)) || execution(* *.*(*, ..)) || call(*.new(*, ..)) || execution(*.new(*, ..))"); + } + + public Pointcut makePointcutPrintln() { + return makeConcretePointcut("call(* *.println(..))"); + } + + + public Pointcut makeConcretePointcut(String s) { + return makeResolvedPointcut(s).concretize(null, 0); + } + + public Pointcut makeResolvedPointcut(String s) { + Pointcut pointcut0 = Pointcut.fromString(s); + return pointcut0.resolve(new SimpleScope(world, FormalBinding.NONE)); + } + + + // ---- + + public String[] getStandardTargets() { + return new String[] {"HelloWorld", "FancyHelloWorld"}; + } + + public String getTraceJar() { + return "testdata/tracing.jar"; + } + + // ---- + + protected void weaveTest( + String[] inClassNames, + String outKind, + ShadowMunger patternMunger) throws IOException { + for (int i = 0; i < inClassNames.length; i++) { + String inFileName = inClassNames[i]; + weaveTest(inFileName, outKind + inFileName, patternMunger); + } + } + protected void weaveTest( + String[] inClassNames, + String outKind, + List patternMungers) throws IOException { + for (int i = 0; i < inClassNames.length; i++) { + String inFileName = inClassNames[i]; + weaveTest(inFileName, outKind + inFileName, patternMungers); + } + } + + protected List addLexicalOrder(List l) { + int i = 10; + for (Iterator iter = l.iterator(); iter.hasNext();) { + Advice element = (Advice) iter.next(); + element.setLexicalPosition(i+=10); + } + return l; + } + + //XXX cut-and-paster from IdWeaveTestCase + public void checkShadowSet(List l, String[] ss) { + outer: + for (int i = 0, len = ss.length; i < len; i++) { + inner: + for (Iterator j = l.iterator(); j.hasNext(); ) { + BcelShadow shadow = (BcelShadow) j.next(); + String shadowString = shadow.toString(); + if (shadowString.equals(ss[i])) { + j.remove(); + continue outer; + } + } + assertTrue("didn't find " + ss[i] + " in " + l, false); + } + assertTrue("too many things in " + l, l.size() == 0); + } + + + + + +} + diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/WorldTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/WorldTestCase.java new file mode 100644 index 000000000..47202bb66 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/WorldTestCase.java @@ -0,0 +1,148 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.lang.reflect.Modifier; + +import org.apache.bcel.util.ClassPath; +import org.aspectj.weaver.*; + +/** + * This is a test case for the nameType parts of worlds. + */ +public class WorldTestCase extends AbstractWorldTestCase { + + public WorldTestCase(String name) { + super(name); + } + + private final BcelWorld world = new BcelWorld("testdata/tracing.jar"); + + protected World getWorld() { + return world; + } + + // XXX fix the various XXXs before expecting this test to work + public void xtestTraceJar() { + ResolvedTypeX trace = world.resolve(TypeX.forName("Trace")); + + fieldsTest(trace, Member.NONE); + Member constr = Member.methodFromString("void Trace.<init>()"); + //XXX need attribute fix - + //methodsTest(trace, new Member[] { constr }); + + interfacesTest(trace, ResolvedTypeX.NONE); + superclassTest(trace, TypeX.OBJECT); + isInterfaceTest(trace, false); + isClassTest(trace, false); + isAspectTest(trace, true); + + pointcutsTest(trace, + new Member[] { + Member.pointcut(trace, "traced", "(Ljava/lang/Object;)V"), + }); + + modifiersTest(trace.findPointcut("traced"), + Modifier.PUBLIC | Modifier.ABSTRACT); + + mungersTest(trace, + new ShadowMunger[] { + world.shadowMunger("before(foo): traced(foo) -> void Trace.ajc_before_4(java.lang.Object))", + 0), + world.shadowMunger("afterReturning(foo): traced(foo) -> void Trace.ajc_afterreturning_3(java.lang.Object, java.lang.Object))", + Advice.ExtraArgument), + world.shadowMunger("around(): execution(* doit(..)) -> java.lang.Object Trace.ajc_around_2(org.aspectj.runtime.internal.AroundClosure))", + Advice.ExtraArgument), + world.shadowMunger("around(foo): traced(foo) -> java.lang.Object Trace.ajc_around_1(java.lang.Object, org.aspectj.runtime.internal.AroundClosure))", + Advice.ExtraArgument), + }); + + ResolvedTypeX myTrace = world.resolve(TypeX.forName("MyTrace")); + + interfacesTest(myTrace, ResolvedTypeX.NONE); + superclassTest(myTrace, trace); + isInterfaceTest(myTrace, false); + isClassTest(myTrace, false); + isAspectTest(myTrace, true); + + //XXX need attribute fix - + //fieldsTest(myTrace, Member.NONE); + + + pointcutsTest(trace, + new Member[] { + Member.pointcut(trace, "traced", "(Ljava/lang/Object;)V"), + }); + + modifiersTest(myTrace.findPointcut("traced"), + Modifier.PUBLIC); + + // this tests for declared mungers + mungersTest(myTrace, ShadowMunger.NONE); + + } + + public void testIterator() { + int abstractPublic = Modifier.ABSTRACT | Modifier.PUBLIC; + ResolvedTypeX iter = world.resolve(TypeX.forName("java.util.Iterator")); + + modifiersTest(iter, abstractPublic | Modifier.INTERFACE); + fieldsTest(iter, ResolvedMember.NONE); + methodsTest(iter, + new Member[] { + Member.method(iter, 0, "hasNext", "()Z"), + Member.method(iter, 0, "remove", "()V"), + Member.method(iter, 0, "next", "()Ljava/lang/Object;"), + }); + ResolvedMember remove = iter.lookupMethod(Member.method(iter, 0, "remove", "()V")); + assertNotNull("iterator doesn't have remove" , remove); + modifiersTest(remove, abstractPublic | Modifier.INTERFACE); + exceptionsTest(remove, TypeX.NONE); + + ResolvedMember clone = iter.lookupMethod(Member.method(TypeX.OBJECT, 0, "clone", "()Ljava/lang/Object;")); + assertNotNull("iterator doesn't have clone" , clone); + modifiersTest(clone, Modifier.PROTECTED | Modifier.NATIVE); + exceptionsTest(clone, TypeX.forNames(new String[] {"java.lang.CloneNotSupportedException"})); + + interfacesTest(iter, ResolvedTypeX.NONE); + superclassTest(iter, TypeX.OBJECT); + pointcutsTest(iter, ResolvedMember.NONE); + mungersTest(iter, ShadowMunger.NONE); + isInterfaceTest(iter, true); + isClassTest(iter, false); + isAspectTest(iter, false); + } + + public void testObjectCoersion() { + assertCouldBeCoercibleFrom("java.lang.Object", "java.lang.String"); + assertCouldBeCoercibleFrom("java.lang.Integer", "java.lang.Object"); + assertCouldBeCoercibleFrom("java.io.Serializable", "java.lang.Runnable"); + assertCouldBeCoercibleFrom("java.util.Stack", "java.lang.Runnable"); + assertCouldNotBeCoercibleFrom("java.lang.Runnable", "java.lang.Integer"); + assertCouldNotBeCoercibleFrom("java.lang.Integer", "java.lang.String"); + assertCouldNotBeCoercibleFrom("java.lang.Integer", "java.lang.Runnable"); + } + + // ---- + + private void assertCouldBeCoercibleFrom(String a, String b) { + isCoerceableFromTest(world.resolve(a), world.resolve(b), true); + } + + private void assertCouldNotBeCoercibleFrom(String a, String b) { + isCoerceableFromTest(world.resolve(a), world.resolve(b), false); + } + + +} diff --git a/weaver/testsrc/org/aspectj/weaver/bcel/ZipTestCase.java b/weaver/testsrc/org/aspectj/weaver/bcel/ZipTestCase.java new file mode 100644 index 000000000..27e68fc93 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/bcel/ZipTestCase.java @@ -0,0 +1,90 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.bcel; + +import java.io.*; +import java.util.Collection; + +import junit.framework.TestCase; + +public class ZipTestCase extends TestCase { + + /** + * Constructor for ZipTestCase. + * @param arg0 + */ + public ZipTestCase(String arg0) { + super(arg0); + } + + + public void zipTest(String fileName, String aspectjar) throws IOException { + zipTest(fileName, aspectjar, false); + } + + public void zipTest(String fileName, String aspectjar, boolean isInJar) throws IOException { + File inFile = new File(fileName); + File outFile = new File("out", inFile.getName()); + + + BcelWorld world = new BcelWorld(); + //BcelWeaver weaver1 = new BcelWeaver(world); + BcelWeaver weaver = new BcelWeaver(world); + + long startTime = System.currentTimeMillis(); + weaver.addJarFile(inFile, new File(".")); + if (aspectjar != null) { + if (isInJar) { + weaver.addJarFile(new File(aspectjar), new File(".")); + } else { + weaver.addLibraryJarFile(new File(aspectjar)); + } + } + + + Collection woven = weaver.weave(outFile); + long stopTime = System.currentTimeMillis(); + + + System.out.println("handled " + woven.size() + " entries, in " + + (stopTime-startTime)/1000. + " seconds"); + assertTrue(outFile.lastModified() > startTime); + } + + public void testSmall() throws IOException { + zipTest("testdata/Regex.jar", null); + } + + public void testSmallWithAspects() throws IOException { + System.out.println("could take 4 seconds..."); + zipTest("testdata/Regex.jar", "testdata/megatrace.jar"); + } + + public void testSmallWithAspectsNoWeave() throws IOException { + System.out.println("could take 4 seconds..."); + zipTest("testdata/Regex.jar", "testdata/megatraceNoweave.jar", true); + } + + // this is something we test every now and again. + public void testBig() throws IOException { + System.out.println("could take 4 seconds..."); + zipTest("../lib/bcel/bcel.jar", null); + } + + public void xtestBigWithAspects() throws IOException { + System.out.println("could take 40 seconds..."); + zipTest("../lib/bcel/bcel.jar", "testdata/megatrace.jar"); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/AndOrNotTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/AndOrNotTestCase.java new file mode 100644 index 000000000..e1dac9ba7 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/AndOrNotTestCase.java @@ -0,0 +1,121 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.*; + +import org.aspectj.weaver.bcel.*; +import org.aspectj.util.FuzzyBoolean; + +import junit.framework.TestCase; +import org.aspectj.weaver.*; + +/** + * @author hugunin + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class AndOrNotTestCase extends TestCase { + /** + * Constructor for PatternTestCase. + * @param name + */ + public AndOrNotTestCase(String name) { + super(name); + } + + World world; + + + public void testMatch() throws IOException { + world = new BcelWorld(); + + Pointcut foo = makePointcut("this(Foo)"); + Pointcut bar = makePointcut("this(Bar)"); + Pointcut c = makePointcut("this(C)"); + + checkEquals("this(Foo) && this(Bar)", new AndPointcut(foo, bar)); + checkEquals("this(Foo) && this(Bar) && this(C)", new AndPointcut(foo, new AndPointcut(bar, c))); + + + checkEquals("this(Foo) || this(Bar)", new OrPointcut(foo, bar)); + checkEquals("this(Foo) || this(Bar) || this(C)", new OrPointcut(foo, new OrPointcut(bar, c))); + + checkEquals("this(Foo) && this(Bar) || this(C)", new OrPointcut(new AndPointcut(foo, bar), c)); + checkEquals("this(Foo) || this(Bar) && this(C)", new OrPointcut(foo, new AndPointcut(bar, c))); + checkEquals("(this(Foo) || this(Bar)) && this(C)", new AndPointcut(new OrPointcut(foo, bar), c)); + checkEquals("this(Foo) || (this(Bar) && this(C))", new OrPointcut(foo, new AndPointcut(bar, c))); + + checkEquals("!this(Foo)", new NotPointcut(foo)); + checkEquals("!this(Foo) && this(Bar)", new AndPointcut(new NotPointcut(foo), bar)); + checkEquals("!(this(Foo) && this(Bar)) || this(C)", new OrPointcut(new NotPointcut(new AndPointcut(foo, bar)), c)); + checkEquals("!!this(Foo)", new NotPointcut(new NotPointcut(foo))); + + } + + private Pointcut makePointcut(String pattern) { + return new PatternParser(pattern).parsePointcut(); + } + + private void checkEquals(String pattern, Pointcut p) throws IOException { + assertEquals(pattern, p, makePointcut(pattern)); + checkSerialization(pattern); + } + + +// private void checkMatch(Pointcut p, Signature[] matches, boolean shouldMatch) { +// for (int i=0; i<matches.length; i++) { +// boolean result = p.matches(matches[i]); +// String msg = "matches " + p + " to " + matches[i] + " expected "; +// if (shouldMatch) { +// assertTrue(msg + shouldMatch, result); +// } else { +// assertTrue(msg + shouldMatch, !result); +// } +// } +// } +// +// public void testSerialization() throws IOException { +// String[] patterns = new String[] { +// "public * *(..)", "void *.foo(A, B)", "A b()" +// }; +// +// for (int i=0, len=patterns.length; i < len; i++) { +// checkSerialization(patterns[i]); +// } +// } + + /** + * Method checkSerialization. + * @param string + */ + private void checkSerialization(String string) throws IOException { + Pointcut p = makePointcut(string); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + Pointcut newP = Pointcut.read(in, null); + + assertEquals("write/read", p, newP); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/BindingTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/BindingTestCase.java new file mode 100644 index 000000000..d1d2b3923 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/BindingTestCase.java @@ -0,0 +1,142 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.util.*; + +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.bcel.BcelShadow; + +import junit.framework.TestCase; + +import org.aspectj.bridge.AbortException; +import org.aspectj.weaver.*; + +/** + * @author hugunin + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class BindingTestCase extends TestCase { + + /** + * Constructor for ParserTestCase. + * @param arg0 + */ + public BindingTestCase(String arg0) { + super(arg0); + } + + World world = new BcelWorld(); + + + public void testResolveBindings() { + BindingTypePattern at = new BindingTypePattern(world.resolve("java.lang.Object"), 0); + BindingTypePattern bt = new BindingTypePattern(world.resolve("java.lang.Object"), 1); + + BindingTypePattern[] all = new BindingTypePattern[] {at, bt}; + BindingTypePattern[] none = new BindingTypePattern[] {null, null}; + BindingTypePattern[] a = new BindingTypePattern[] {at, null}; + BindingTypePattern[] b = new BindingTypePattern[] {null, bt}; + + checkBindings("this(b)",b); + checkBindings("this(Foo)", none); + checkBindings("this(*)", none); + checkBindings("this(a)", a); + + checkBindings("args(.., a,..,b)", all); + checkBindings("args(a,..,b, ..)", all); + + checkBindings("args(a,..,b)", all); + checkBindings("args(b)", b); + + checkBindings("args()", none); + + checkBindings("this(a) && this(b)", all); + + checkBindingFailure("this(a) && this(a)", "multiple"); + //checkBindingFailure("this(a) && this(b)"); + + checkBindingFailure("this(a) || this(b)", "inconsistent"); + checkBindingFailure("this(A) || this(b)", "inconsistent"); + checkBindingFailure("this(a) || this(B)", "inconsistent"); + checkBindings("this(a) || this(a)", a); + + checkBindings("!this(Foo)", none); + checkBindings("!this(Foo) && this(a)", a); + checkBindingFailure("!this(a)", "negation"); + //checkBindingFailure("this(a)"); + + + checkBindings("cflow(this(a))", a); + checkBindings("cflow(this(a)) && this(b)", all); + + checkBindingFailure("cflow(this(a)) || this(b)", "inconsistent"); + checkBindingFailure("cflow(this(a)) && this(a)", "multiple"); + + checkBindingFailure("!cflow(this(a))", "negation"); + + // todo + // this should fail since a isn't visible to if + //checkBindingFailure("cflow(if(a != null)) && this(a)"); + //checkBinding("cflow(if(a != null) && this(a))", a); + + } + + + /** + * Method checkBindingFailure. (assumes an env where "a" and "b" are formals). + * @param string + */ + private void checkBindingFailure(String pattern, String prefix) { + PatternParser parser = new PatternParser(pattern); + Pointcut p = parser.parsePointcut(); + Bindings actualBindings = new Bindings(2); + try { + p.resolveBindings(makeSimpleScope(), actualBindings); + } catch (AbortException re) { + assertEquals(prefix, re.getIMessage().getMessage().substring(0, prefix.length())); + //System.out.println("expected exception: " + re); + return; + } + assertTrue("should have failed", false); + } + + + /** + * Method checkBindings. + * @param string + * @param i + */ + private void checkBindings(String pattern, BindingTypePattern[] expectedBindings) { + PatternParser parser = new PatternParser(pattern); + Pointcut p = parser.parsePointcut(); + Bindings actualBindings = new Bindings(expectedBindings.length); + + TestScope simpleScope = makeSimpleScope(); + p.resolveBindings(simpleScope, actualBindings); + //System.out.println(actualBindings); + + new Bindings(expectedBindings).checkEquals(actualBindings, simpleScope); + } + + + public TestScope makeSimpleScope() { + return new TestScope(new String[] {"int", "java.lang.String"}, new String[] {"a", "b"}, world); + } +} + diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/ConcretizationTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/ConcretizationTestCase.java new file mode 100644 index 000000000..1f71719ce --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/ConcretizationTestCase.java @@ -0,0 +1,161 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.Modifier; +import java.util.*; + +import org.aspectj.testing.util.TestUtil; +import org.aspectj.weaver.*; +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.bcel.WeaveTestCase; + +public class ConcretizationTestCase extends WeaveTestCase { + { + regenerate = false; + } + public ConcretizationTestCase(String name) { + super(name); + } + + String[] none = new String[0]; + + + public void testCflowResidual() throws IOException { + + BcelAdvice a = (BcelAdvice) makeConcreteTestAdviceEntryPart(); + + TestShadow shadow = new TestShadow(Shadow.MethodCall, + Member.methodFromString("int Aspect.i(int x)"), + TypeX.OBJECT, + world); + + ExposedState state = new ExposedState(1); + + a.specializeOn(shadow); + + //System.err.println(shadow); + //System.err.println(a); + + //System.err.println(a.exposedState); + + + } + + + + public Advice makeConcreteTestAdviceEntryPart() throws IOException { + // XXX copied from below, refactor later + + + // returns the advice for the entry part of cflow(foo(a)) + Pointcut in = + createResolvedPointcut( + "cflow(foo(a)) && (args(b) && !cflow(foo(int)))", + new String[] { "b", "a" }, + new String[] { "float", "int" }); + + ResolvedPointcutDefinition ref = + new ResolvedPointcutDefinition( + TypeX.forName("Aspect"), + 0, + "foo", + new TypeX[] { ResolvedTypeX.INT }, + createResolvedPointcut( + "args(refA)", + new String[] { "refA" }, + new String[] { "int" })); + BcelObjectType target = (BcelObjectType) world.resolve("Aspect"); + + // now munge this to get the pointcut in it + + target.addPointcutDefinition(ref); + CrosscuttingMembers xcut = new CrosscuttingMembers(target); + target.crosscuttingMembers = xcut; + + Advice adviceMember = + new BcelAdvice( + AdviceKind.Before, + in, + Member.method(TypeX.forName("FOO"), 0, "garadf", "(FI)V"), + 0, + 0, 0, null, + null); + // The pointcut to concretize + + // this returns the actual advice, but we don't care about it now. + in.concretize(target, 2, adviceMember); + + List c = (List)xcut.getCflowEntries(); //target.getExtraConcreteShadowMungers(); + + return (Advice) c.get(0); + } + + public void XtestCflow() throws IOException { + Pointcut in = createResolvedPointcut("cflow(foo(a)) && (args(b) && !cflow(foo(int)))", + new String[] {"b", "a"}, new String[] {"float", "int"} ); + + ResolvedPointcutDefinition ref = + new ResolvedPointcutDefinition(TypeX.forName("Aspect"), + 0, "foo", new TypeX[] { ResolvedTypeX.INT }, + createResolvedPointcut("args(refA)", + new String[] {"refA"}, new String[] {"int"})); + + List expectedSlots = new ArrayList(); + expectedSlots.add(new ConcreteCflowPointcut.Slot(1, ResolvedTypeX.INT, 0)); + + checkConcr(in, ref, expectedSlots); + } + + public void checkConcr( + Pointcut in, + ResolvedPointcutDefinition referredTo, + List expectedSlots) throws IOException { + + BcelObjectType target = (BcelObjectType)world.resolve("Aspect"); + + // now munge this to get the pointcut in it + + target.addPointcutDefinition(referredTo); + + + Advice adviceMember = new BcelAdvice(AdviceKind.Before, in, + Member.method(TypeX.forName("FOO"), 0, "garadf", "(FI)V"), 0, 0, 0, null, null); + + // The pointcut to concretize + AndPointcut ap = (AndPointcut)in.concretize(target, 2, adviceMember); + + + ConcreteCflowPointcut conc = (ConcreteCflowPointcut)ap.left; + + List slots = conc.slots; + TestUtil.assertSetEquals(expectedSlots, slots); + + } + + + public Pointcut createResolvedPointcut( + String pointcutSource, String[] formalNames, String[] formalTypes) { + final Pointcut sp = Pointcut.fromString(pointcutSource); + final Pointcut rp = + sp.resolve( + new SimpleScope( + world, + SimpleScope.makeFormalBindings(TypeX.forNames(formalTypes), + formalNames) + )); + return rp; + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/DeclareErrorOrWarningTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/DeclareErrorOrWarningTestCase.java new file mode 100644 index 000000000..7c125b48c --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/DeclareErrorOrWarningTestCase.java @@ -0,0 +1,61 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import junit.framework.TestCase; + +public class DeclareErrorOrWarningTestCase extends TestCase { + + public DeclareErrorOrWarningTestCase(String name) { + super(name); + } + + + public void testParse() throws IOException { + DeclareErrorOrWarning d = + parse("declare error: call(void foo()): \"that is bad\";"); + assertTrue(d.isError()); + assertEquals(d.getPointcut(), + new PatternParser("call(void foo())").parsePointcut()); + assertEquals("that is bad", d.getMessage()); + checkSerialization(d); + + d = parse("declare warning: bar() && baz(): \"boo!\";"); + assertTrue(!d.isError()); + assertEquals(d.getPointcut(), + new PatternParser("bar() && baz()").parsePointcut()); + assertEquals("boo!", d.getMessage()); + checkSerialization(d); + + } + + private DeclareErrorOrWarning parse(String string) { + return (DeclareErrorOrWarning)new PatternParser(string).parseDeclare(); + } + + private void checkSerialization(Declare declare) throws IOException { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + declare.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + Declare newDeclare = Declare.read(in, null); + + assertEquals("write/read", declare, newDeclare); + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/ModifiersPatternTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/ModifiersPatternTestCase.java new file mode 100644 index 000000000..38bc0fdad --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/ModifiersPatternTestCase.java @@ -0,0 +1,140 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.*; + +import org.aspectj.weaver.bcel.*; +import org.aspectj.util.FuzzyBoolean; + +import junit.framework.TestCase; +import org.aspectj.weaver.*; + +public class ModifiersPatternTestCase extends TestCase { + /** + * Constructor for PatternTestCase. + * @param name + */ + public ModifiersPatternTestCase(String name) { + super(name); + } + + World world; + + public void testMatch() { + world = new BcelWorld(); + + int[] publicMatches = new int[] { + Modifier.PUBLIC, + Modifier.PUBLIC | Modifier.STATIC, + Modifier.PUBLIC | Modifier.STATIC | Modifier.STRICT | Modifier.FINAL, + }; + + int[] publicFailures = new int[] { + Modifier.PRIVATE, + 0, + Modifier.STATIC | Modifier.STRICT | Modifier.FINAL, + }; + + int[] publicStaticMatches = new int[] { + Modifier.PUBLIC | Modifier.STATIC, + Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL | Modifier.STRICT, + }; + + int[] publicStaticFailures = new int[] { + 0, + Modifier.PUBLIC, + Modifier.STATIC, + }; + + int[] trickMatches = new int[] { + Modifier.PRIVATE, + Modifier.PRIVATE | Modifier.ABSTRACT, + Modifier.PRIVATE | Modifier.FINAL, + }; + + int[] trickFailures = new int[] { + Modifier.PUBLIC, + Modifier.PRIVATE | Modifier.STATIC, + Modifier.PRIVATE | Modifier.STRICT, + }; + + + int[] none = new int[0]; + + checkMatch("", publicMatches, none); + checkMatch("", publicFailures, none); + checkMatch("!public", publicFailures, publicMatches); + checkMatch("public", publicMatches, publicFailures); + checkMatch("public static", none, publicFailures); + checkMatch("public static", publicStaticMatches, publicStaticFailures); + + checkMatch("private !static !strictfp", trickMatches, trickFailures); + checkMatch("private !static !strictfp", none, publicMatches); + checkMatch("private !static !strictfp", none, publicStaticMatches); + } + + private ModifiersPattern makeModifiersPattern(String pattern) { + return new PatternParser(pattern).parseModifiersPattern(); + } + + private void checkMatch(String pattern, int[] shouldMatch, int[] shouldFail) { + ModifiersPattern p = makeModifiersPattern(pattern); + checkMatch(p, shouldMatch, true); + checkMatch(p, shouldFail, false); + } + + private void checkMatch(ModifiersPattern p, int[] matches, boolean shouldMatch) { + for (int i=0; i<matches.length; i++) { + boolean result = p.matches(matches[i]); + String msg = "matches " + p + " to " + Modifier.toString(matches[i]) + " expected "; + if (shouldMatch) { + assertTrue(msg + shouldMatch, result); + } else { + assertTrue(msg + shouldMatch, !result); + } + } + } + + public void testSerialization() throws IOException { + String[] patterns = new String[] { + "", "!public", "public", "public static", + "private !static !strictfp", + }; + + for (int i=0, len=patterns.length; i < len; i++) { + checkSerialization(patterns[i]); + } + } + + /** + * Method checkSerialization. + * @param string + */ + private void checkSerialization(String string) throws IOException { + ModifiersPattern p = makeModifiersPattern(string); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + ModifiersPattern newP = ModifiersPattern.read(in); + + assertEquals("write/read", p, newP); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternParserTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternParserTestCase.java new file mode 100644 index 000000000..22e180250 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternParserTestCase.java @@ -0,0 +1,65 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.patterns.*; + +import junit.framework.TestCase; + +/** + * @author hugunin + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class NamePatternParserTestCase extends TestCase { + /** + * Constructor for PatternTestCase. + * @param name + */ + public NamePatternParserTestCase(String name) { + super(name); + } + + public void testMatch() { + checkMatch(NamePatternTestCase.matchAll); + checkMatch(NamePatternTestCase.match1); + checkMatch(NamePatternTestCase.match2); + + + NamePattern p = new PatternParser("abc *").parseNamePattern(); + assertEquals(new NamePattern("abc"), p); + } + + /** + * Method checkMatch. + * @param string + * @param matchAll + * @param b + */ + private void checkMatch(String[] patterns) { + for (int i=0, len=patterns.length; i < len; i++) { + String pattern = patterns[i]; + ITokenSource tokenSource = BasicTokenSource.makeTokenSource(pattern); + NamePattern p1 = new PatternParser(tokenSource).parseNamePattern(); + NamePattern p2 = new NamePattern(pattern); + assertEquals("pattern: " + pattern, p2, p1); + assertEquals("eof", IToken.EOF, tokenSource.next()); + } + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternTestCase.java new file mode 100644 index 000000000..3382dd4e7 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/NamePatternTestCase.java @@ -0,0 +1,118 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import org.aspectj.weaver.patterns.*; + +import junit.framework.TestCase; + +/** + * @author hugunin + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class NamePatternTestCase extends TestCase { + static String[] matchAll = new String[] { + "*****", + "*" + }; + + + static String[] match1 = new String[] { + "abcde", "abc*", "abcd*", "abcde*", + "*e", "*cde", "*abcde", + "a*e", "ab*e", "abc*de", + "*a*b*c*d*e*", "a*c*e", "a***bcde", + "*d*", + }; + + static String[] match2 = new String[] { + "abababab", + "aba*", "abab*", "abababab*", + "*b", "*ab", "*ababab", "*abababab", + "a*b", "ab*b", "abab*abab", + "*a*b*a*b*a*b*a*b*", "a*****b", "a**b", "ab*b*b", + }; + + /** + * Constructor for PatternTestCase. + * @param name + */ + public NamePatternTestCase(String name) { + super(name); + } + + public void testMatch() { + checkMatch("abcde", matchAll, true); + checkMatch("abcde", match1, true); + checkMatch("abcde", match2, false); + + checkMatch("abababab", matchAll, true); + checkMatch("abababab", match1, false); + checkMatch("abababab", match2, true); + + } + + /** + * Method checkMatch. + * @param string + * @param matchAll + * @param b + */ + private void checkMatch(String string, String[] patterns, boolean shouldMatch) { + for (int i=0, len=patterns.length; i < len; i++) { + NamePattern p = new NamePattern(patterns[i]); + checkMatch(string, p, shouldMatch); + } + } + + private void checkMatch(String string, NamePattern p, boolean shouldMatch) { + String msg = "matching " + string + " to " + p; + assertEquals(msg, shouldMatch, p.matches(string)); + } + + + public void testSerialization() throws IOException { + checkSerialization(matchAll); + checkSerialization(match1); + checkSerialization(match2); + } + + private void checkSerialization(String[] patterns) throws IOException { + for (int i=0, len=patterns.length; i < len; i++) { + NamePattern p = new NamePattern(patterns[i]); + checkSerialization(p); + } + } + + + private void checkSerialization(NamePattern p) throws IOException { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + NamePattern newP = NamePattern.read(in); + + assertEquals("write/read", p, newP); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/ParserTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/ParserTestCase.java new file mode 100644 index 000000000..d6f17f3e9 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/ParserTestCase.java @@ -0,0 +1,70 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.util.*; + +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.bcel.BcelShadow; + +import junit.framework.TestCase; +import org.aspectj.weaver.*; + +/** + * @author hugunin + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class ParserTestCase extends TestCase { + + public ParserTestCase(String arg0) { + super(arg0); + } + + World world = new BcelWorld(); + + public void testNamePatterns() { + + +// checkNoMatch("abc *", "abcd"); +// checkNoMatch("* d", "abcd"); + } + + + + public void testParse() { + PatternParser parser = new PatternParser("execution(void Hello.*(..))"); + KindedPointcut p = (KindedPointcut) parser.parsePointcut(); + //System.out.println(p); + assertEquals(p.kind, BcelShadow.MethodExecution); + assertTrue(p.signature.getName().matches("foobar")); + + + try { + new PatternParser("initialization(void foo())").parsePointcut(); + this.fail("should have been a parse error"); + } catch (ParserException pe) { + // good + } + + + + } +} + + diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/PatternsTests.java b/weaver/testsrc/org/aspectj/weaver/patterns/PatternsTests.java new file mode 100644 index 000000000..e66fd3e12 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/PatternsTests.java @@ -0,0 +1,41 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import junit.framework.*; + +public class PatternsTests extends TestCase { + + public static Test suite() { + TestSuite suite = new TestSuite(PatternsTests.class.getName()); + //$JUnit-BEGIN$ + suite.addTestSuite(AndOrNotTestCase.class); + suite.addTestSuite(BindingTestCase.class); + suite.addTestSuite(DeclareErrorOrWarningTestCase.class); + suite.addTestSuite(ModifiersPatternTestCase.class); + suite.addTestSuite(NamePatternParserTestCase.class); + suite.addTestSuite(NamePatternTestCase.class); + suite.addTestSuite(ParserTestCase.class); + suite.addTestSuite(SignaturePatternTestCase.class); + suite.addTestSuite(ThisOrTargetTestCase.class); + suite.addTestSuite(TypePatternListTestCase.class); + suite.addTestSuite(TypePatternTestCase.class); + suite.addTestSuite(WithinTestCase.class); + //$JUnit-END$ + return suite; + } + + public PatternsTests(String name) { super(name); } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/SignaturePatternTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/SignaturePatternTestCase.java new file mode 100644 index 000000000..b7c8789dc --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/SignaturePatternTestCase.java @@ -0,0 +1,175 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import junit.framework.*; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.bcel.*; + +public class SignaturePatternTestCase extends TestCase { + /** + * Constructor for PatternTestCase. + * @param name + */ + public SignaturePatternTestCase(String name) { + super(name); + } + + BcelWorld world = new BcelWorld(); + + public void testThrowsMatch() throws IOException { + Member onlyDerivedOnDerived = Member.methodFromString("static void fluffy.Derived.onlyDerived()"); + Member mOnBase = Member.methodFromString("void fluffy.Base.m()"); + Member mOnDerived = Member.methodFromString("void fluffy.Derived.m()"); + + checkMatch(makeMethodPat("* fluffy.Base.*(..) throws java.lang.CloneNotSupportedException"), + new Member[] { mOnBase }, + new Member[] { mOnDerived }); + + checkMatch(makeMethodPat("* fluffy.Derived.*(..) throws java.lang.CloneNotSupportedException"), + new Member[] { }, + new Member[] { mOnBase, mOnDerived }); + + //XXX need pattern checks + Member[] NONE = new Member[] {}; + Member[] M = new Member[] { onlyDerivedOnDerived }; + Member[] NO_EXCEPTIONS = new Member[] { mOnDerived }; + Member[] BOTH = new Member[] {mOnDerived, onlyDerivedOnDerived}; + + checkMatch(makeMethodPat("* *(..)"), M, NONE); + checkMatch(makeMethodPat("* *(..) throws !*"), NO_EXCEPTIONS, M); + checkMatch(makeMethodPat("* *(..) throws *"), M, NO_EXCEPTIONS); + checkMatch(makeMethodPat("* *(..) throws *, !*"), NONE, BOTH); + + checkMatch(makeMethodPat("* *(..) throws (!*)"), NONE, BOTH); + checkMatch(makeMethodPat("* *(..) throws !(!*)"), BOTH, NONE); + + checkMatch(makeMethodPat("* *(..) throws *..IOException"), M, NO_EXCEPTIONS); + checkMatch(makeMethodPat("* *(..) throws *..IOException, *..Clone*"), M, NO_EXCEPTIONS); + checkMatch(makeMethodPat("* *(..) throws *..IOException, !*..Clone*"), NONE, BOTH); + checkMatch(makeMethodPat("* *(..) throws !*..IOException"), NO_EXCEPTIONS, M); + } + + public void testInstanceMethodMatch() throws IOException { + Member objectToString = Member.methodFromString("java.lang.String java.lang.Object.toString()"); + Member integerToString = Member.methodFromString("java.lang.String java.lang.Integer.toString()"); + Member integerIntValue = Member.methodFromString("int java.lang.Integer.intValue()"); + //Member objectToString = Member.methodFromString("java.lang.String java.lang.Object.toString()"); + + checkMatch(makeMethodPat("* java.lang.Object.*(..)"), + new Member[] { objectToString, integerToString }, + new Member[] { integerIntValue }); + + checkMatch(makeMethodPat("* java.lang.Integer.*(..)"), + new Member[] { integerIntValue, integerToString }, + new Member[] { objectToString }); + } + + + public void testStaticMethodMatch() throws IOException { + Member onlyBaseOnBase = Member.methodFromString("static void fluffy.Base.onlyBase()"); + Member onlyBaseOnDerived = Member.methodFromString("static void fluffy.Derived.onlyBase()"); + Member onlyDerivedOnDerived = Member.methodFromString("static void fluffy.Derived.onlyDerived()"); + Member bothOnBase = Member.methodFromString("static void fluffy.Base.both()"); + Member bothOnDerived = Member.methodFromString("static void fluffy.Derived.both()"); + + checkMatch(makeMethodPat("* fluffy.Base.*(..)"), + new Member[] { onlyBaseOnBase, onlyBaseOnDerived, bothOnBase }, + new Member[] { onlyDerivedOnDerived, bothOnDerived }); + + checkMatch(makeMethodPat("* fluffy.Derived.*(..)"), + new Member[] { onlyBaseOnDerived, bothOnDerived, onlyDerivedOnDerived }, + new Member[] { onlyBaseOnBase, bothOnBase }); + } + + public void testFieldMatch() throws IOException { + Member onlyBaseOnBase = Member.fieldFromString("int fluffy.Base.onlyBase"); + Member onlyBaseOnDerived = Member.fieldFromString("int fluffy.Derived.onlyBase"); + Member onlyDerivedOnDerived = Member.fieldFromString("int fluffy.Derived.onlyDerived"); + Member bothOnBase = Member.fieldFromString("int fluffy.Base.both"); + Member bothOnDerived = Member.fieldFromString("int fluffy.Derived.both"); + + checkMatch(makeFieldPat("* fluffy.Base.*"), + new Member[] { onlyBaseOnBase, onlyBaseOnDerived, bothOnBase }, + new Member[] { onlyDerivedOnDerived, bothOnDerived }); + + checkMatch(makeFieldPat("* fluffy.Derived.*"), + new Member[] { onlyBaseOnDerived, bothOnDerived, onlyDerivedOnDerived }, + new Member[] { onlyBaseOnBase, bothOnBase }); + } + + public void testConstructorMatch() throws IOException { + Member onBase = Member.methodFromString("void fluffy.Base.<init>()"); + Member onDerived = Member.methodFromString("void fluffy.Derived.<init>()"); + Member onBaseWithInt = Member.methodFromString("void fluffy.Base.<init>(int)"); + + + checkMatch(makeMethodPat("fluffy.Base.new(..)"), + new Member[] { onBase, onBaseWithInt }, + new Member[] { onDerived }); + + checkMatch(makeMethodPat("fluffy.Derived.new(..)"), + new Member[] { onDerived}, + new Member[] { onBase, onBaseWithInt }); + } + + + + + + public void checkMatch(SignaturePattern p, Member[] yes, Member[] no) throws IOException { + p = p.resolveBindings(new TestScope(world, new FormalBinding[0]), new Bindings(0)); + + for (int i=0; i < yes.length; i++) { + checkMatch(p, yes[i], true); + } + + for (int i=0; i < no.length; i++) { + checkMatch(p, no[i], false); + } + + checkSerialization(p); + } + + private void checkMatch(SignaturePattern p, Member member, boolean b) { + boolean matches = p.matches(member, world); + assertEquals(p.toString() + " matches " + member.toString(), b, matches); + } + + + private SignaturePattern makeMethodPat(String pattern) { + return new PatternParser(pattern).parseMethodOrConstructorSignaturePattern(); + } + + private SignaturePattern makeFieldPat(String pattern) { + return new PatternParser(pattern).parseFieldSignaturePattern(); + } + + private void checkSerialization(SignaturePattern p) throws IOException { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + SignaturePattern newP = SignaturePattern.read(in, null); + + assertEquals("write/read", p, newP); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/TestScope.java b/weaver/testsrc/org/aspectj/weaver/patterns/TestScope.java new file mode 100644 index 000000000..d18f8f63c --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/TestScope.java @@ -0,0 +1,30 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import org.aspectj.weaver.*; + +public class TestScope extends SimpleScope { + + public TestScope( + World world, + FormalBinding[] bindings) + { + super(world, bindings); + } + + public TestScope(String[] formalTypes, String[] formalNames, World world) { + super(world, SimpleScope.makeFormalBindings(TypeX.forNames(formalTypes), formalNames)); + } +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/ThisOrTargetTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/ThisOrTargetTestCase.java new file mode 100644 index 000000000..9fd2a9e07 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/ThisOrTargetTestCase.java @@ -0,0 +1,102 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.lang.reflect.*; + +import org.aspectj.weaver.bcel.*; +import org.aspectj.util.FuzzyBoolean; + +import junit.framework.TestCase; +import org.aspectj.weaver.*; + +/** + * @author hugunin + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class ThisOrTargetTestCase extends TestCase { + /** + * Constructor for PatternTestCase. + * @param name + */ + public ThisOrTargetTestCase(String name) { + super(name); + } + + World world; + + + public void testMatch() throws IOException { + world = new BcelWorld(); + + + + } + + private Pointcut makePointcut(String pattern) { + return new PatternParser(pattern).parsePointcut(); + } + + private void checkEquals(String pattern, Pointcut p) throws IOException { + assertEquals(pattern, p, makePointcut(pattern)); + checkSerialization(pattern); + } + + +// private void checkMatch(Pointcut p, Signature[] matches, boolean shouldMatch) { +// for (int i=0; i<matches.length; i++) { +// boolean result = p.matches(matches[i]); +// String msg = "matches " + p + " to " + matches[i] + " expected "; +// if (shouldMatch) { +// assertTrue(msg + shouldMatch, result); +// } else { +// assertTrue(msg + shouldMatch, !result); +// } +// } +// } +// +// public void testSerialization() throws IOException { +// String[] patterns = new String[] { +// "public * *(..)", "void *.foo(A, B)", "A b()" +// }; +// +// for (int i=0, len=patterns.length; i < len; i++) { +// checkSerialization(patterns[i]); +// } +// } + + /** + * Method checkSerialization. + * @param string + */ + private void checkSerialization(String string) throws IOException { + Pointcut p = makePointcut(string); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + Pointcut newP = Pointcut.read(in, null); + + assertEquals("write/read", p, newP); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/TypePatternListTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/TypePatternListTestCase.java new file mode 100644 index 000000000..e756d11f4 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/TypePatternListTestCase.java @@ -0,0 +1,190 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.Arrays; + +import org.aspectj.weaver.bcel.*; +import org.aspectj.util.*; + +import junit.framework.TestCase; +import org.aspectj.weaver.*; + +/** + * @author hugunin + * + * To change this generated comment edit the template variable "typecomment": + * Window>Preferences>Java>Templates. + * To enable and disable the creation of type comments go to + * Window>Preferences>Java>Code Generation. + */ +public class TypePatternListTestCase extends TestCase { + /** + * Constructor for PatternTestCase. + * @param name + */ + public TypePatternListTestCase(String name) { + super(name); + } + + World world; + + //XXX when instanceof matching works add tests for that here + + + public void testMatch() { + world = new BcelWorld(); + + checkStaticMatch("()", new String[] {}, FuzzyBoolean.YES); + checkStaticMatch("()", new String[] {"java.lang.Object"}, FuzzyBoolean.NO); + + checkStaticMatch("(java.lang.Object)", new String[] {"java.lang.Object"}, FuzzyBoolean.YES); + + checkStaticMatch("(java.lang.String)", new String[] {"java.lang.Object"}, FuzzyBoolean.NO); + + checkStaticMatch("(java.lang.Object)", new String[] {"java.lang.String"}, FuzzyBoolean.NO); + + checkStaticMatch("()", new String[] {"java.lang.Object"}, FuzzyBoolean.NO); + + checkStaticMatch("(..)", new String[] {}, FuzzyBoolean.YES); + checkStaticMatch("(..)", new String[] {"int", "char"}, FuzzyBoolean.YES); + + + checkStaticMatch("(int,..,int)", new String[] {"int", "int"}, FuzzyBoolean.YES); + + checkStaticMatch("(int,..)", new String[] {}, FuzzyBoolean.NO); + checkStaticMatch("(int,..)", new String[] {"int"}, FuzzyBoolean.YES); + + checkStaticMatch("(..,int,..)", new String[] {"int"}, FuzzyBoolean.YES); + + // these checks are taken from new/ExpandedDotPattern.java + stupidCheck("( .., .., ..)", new boolean[] { true, true, true, true, true }); + stupidCheck("( .., .., int)", new boolean[] { false, true, true, true, true }); + stupidCheck("( .., int, ..)", new boolean[] { false, true, true, true, true }); + stupidCheck("( .., int, int)", new boolean[] { false, false, true, true, true }); + stupidCheck("(int, .., ..)", new boolean[] { false, true, true, true, true }); + stupidCheck("(int, .., int)", new boolean[] { false, false, true, true, true }); + stupidCheck("(int, int, ..)", new boolean[] { false, false, true, true, true }); + stupidCheck("(int, int, int)", new boolean[] { false, false, false, true, false }); + + stupidCheck("( .., .., .., ..)", new boolean[] { true, true, true, true, true }); + stupidCheck("( .., .., .., int)", new boolean[] { false, true, true, true, true }); + stupidCheck("( .., .., int, ..)", new boolean[] { false, true, true, true, true }); + stupidCheck("( .., .., int, int)", new boolean[] { false, false, true, true, true }); + stupidCheck("( .., int, .., ..)", new boolean[] { false, true, true, true, true }); + stupidCheck("( .., int, .., int)", new boolean[] { false, false, true, true, true }); + stupidCheck("( .., int, int, ..)", new boolean[] { false, false, true, true, true }); + stupidCheck("( .., int, int, int)", new boolean[] { false, false, false, true, true }); + + stupidCheck("(int, .., .., ..)", new boolean[] { false, true, true, true, true }); + stupidCheck("(int, .., .., int)", new boolean[] { false, false, true, true, true }); + stupidCheck("(int, .., int, ..)", new boolean[] { false, false, true, true, true }); + stupidCheck("(int, .., int, int)", new boolean[] { false, false, false, true, true }); + stupidCheck("(int, int, .., ..)", new boolean[] { false, false, true, true, true }); + stupidCheck("(int, int, .., int)", new boolean[] { false, false, false, true, true }); + stupidCheck("(int, int, int, ..)", new boolean[] { false, false, false, true, true }); + stupidCheck("(int, int, int, int)", new boolean[] { false, false, false, false, true }); + } + + private TypePatternList makeArgumentsPattern(String pattern) { + return new PatternParser(pattern).parseArgumentsPattern(); + } + + private void checkStaticMatch(String pattern, String[] names, + FuzzyBoolean shouldMatchStatically) { + // We're only doing TypePattern.STATIC matching here because my intent was + // to test the wildcarding, and we don't do DYNAMIC matching on wildcarded things. + + TypePatternList p = makeArgumentsPattern(pattern); + ResolvedTypeX[] types = new ResolvedTypeX[names.length]; + for (int i = 0; i < names.length; i++) { + types[i] = world.resolve(names[i]); + } + + p.resolveBindings(makeTestScope(), Bindings.NONE, false); + //System.out.println("type: " + type); + FuzzyBoolean result = p.matches(types, TypePattern.STATIC); + String msg = "matches statically " + pattern + " to " + Arrays.asList(types); + assertEquals(msg, shouldMatchStatically, result); + } + + private TestScope makeTestScope() { + TestScope scope = new TestScope(CollectionUtil.NO_STRINGS, CollectionUtil.NO_STRINGS, world); + return scope; + } + + public void stupidCheck(String pattern, boolean[] matches) { + TypePatternList p = makeArgumentsPattern(pattern); + p.resolveBindings(makeTestScope(), Bindings.NONE, false); + + int len = matches.length; + + for (int j = 0; j < len; j++) { + + ResolvedTypeX[] types = new ResolvedTypeX[j]; + for (int i = 0; i < j; i++) { + types[i] = world.resolve("int"); + } + + FuzzyBoolean result = p.matches(types, TypePattern.STATIC); + String msg = "matches statically " + pattern + " to " + Arrays.asList(types); + assertEquals(msg, FuzzyBoolean.fromBoolean(matches[j]), result); + } + } + + public void testSerialization() throws IOException { + String[] patterns = new String[] { + "( .., .., .., int)", + "( .., .., int, ..)", + "( .., .., int, int)", + "( .., int, .., ..)", + "( .., int, .., int)", + "( .., int, int, ..)", + "( .., int, int, int)", + + "(int, .., .., ..)", + "(int, .., .., int)", + "(int, .., int, ..)", + "(int, .., int, int)", + "(int, int, .., ..)", + "(int, int, .., int)", + "(int, int, int, ..)", + "(int, int, int, int)" + }; + + for (int i=0, len=patterns.length; i < len; i++) { + checkSerialization(patterns[i]); + } + } + + /** + * Method checkSerialization. + * @param string + */ + private void checkSerialization(String string) throws IOException { + TypePatternList p = makeArgumentsPattern(string); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + TypePatternList newP = TypePatternList.read(in, null); + + assertEquals("write/read", p, newP); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/TypePatternTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/TypePatternTestCase.java new file mode 100644 index 000000000..5b3c702e8 --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/TypePatternTestCase.java @@ -0,0 +1,290 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; +import java.util.*; + +import org.aspectj.weaver.bcel.*; +import org.aspectj.bridge.AbortException; +import org.aspectj.util.FuzzyBoolean; + +import junit.framework.TestCase; +import org.aspectj.weaver.*; + +public class TypePatternTestCase extends TestCase { + /** + * Constructor for PatternTestCase. + * @param name + */ + public TypePatternTestCase(String name) { + super(name); + } + + World world; + + public void testStaticMatch() { + world = new BcelWorld(); + + checkMatch("java.lang.Object", "java.lang.Object", true); + checkMatch("java.lang.Object+", "java.lang.Object", true); + checkMatch("java.lang.Object+", "java.lang.String", true); + checkMatch("java.lang.String+", "java.lang.Object", false); + checkMatch("java.lang.Integer", "java.lang.String", false); + + checkMatch("java.lang.Integer", "int", false); + + checkMatch("java.lang.Number+", "java.lang.Integer", true); + + + checkMatch("java..*", "java.lang.Integer", true); + checkMatch("java..*", "java.lang.reflect.Modifier", true); + checkMatch("java..*", "int", false); + checkMatch("java..*", "javax.swing.Action", false); + checkMatch("java..*+", "javax.swing.Action", true); + + checkMatch("*.*.Object", "java.lang.Object", true); + checkMatch("*.Object", "java.lang.Object", false); + checkMatch("*..*", "java.lang.Object", true); + checkMatch("*..*", "int", false); + checkMatch("java..Modifier", "java.lang.reflect.Modifier", true); + checkMatch("java.lang.reflect.Mod..ifier", "java.lang.reflect.Modifier", false); + + checkMatch("java..reflect..Modifier", "java.lang.reflect.Modifier", true); + checkMatch("java..lang..Modifier", "java.lang.reflect.Modifier", true); + checkMatch("java..*..Modifier", "java.lang.reflect.Modifier", true); + checkMatch("java..*..*..Modifier", "java.lang.reflect.Modifier", true); + checkMatch("java..*..*..*..Modifier", "java.lang.reflect.Modifier", false); + //checkMatch("java..reflect..Modifier", "java.lang.reflect.Modxifier", false); + checkMatch("ja*va..Modifier", "java.lang.reflect.Modifier", true); + checkMatch("java..*..Mod*ifier", "java.lang.reflect.Modifier", true); + + } + + + // three levels: + // 0. defined in current compilation unit, or imported by name + // 1. defined in current package/type/whatever + // 2. defined in package imported by * + /** + * We've decided not to test this here, but rather in any compilers + */ + public void testImportResolve() { + world = new BcelWorld(); +// checkIllegalImportResolution("List", new String[] { "java.util", "java.awt", }, +// ZERO_STRINGS); + + + } + + + // Assumption for bcweaver: Already resolved type patterns with no *s or ..'s into exact type + // patterns. Exact type patterns don't have import lists. non-exact-type pattens don't + // care about precedence, so the current package can be included with all the other packages, + // and we don't care about compilation units, and we don't care about ordering. + + // only giving this wild-type patterns + public void testImportMatch() { + world = new BcelWorld(); + + checkImportMatch("*List", new String[] { "java.awt.", }, ZERO_STRINGS, "java.awt.List", true); + checkImportMatch("*List", new String[] { "java.awt.", }, ZERO_STRINGS, "java.awt.List", true); + checkImportMatch("*List", new String[] { "java.awt.", }, ZERO_STRINGS, "java.util.List", false); + checkImportMatch("*List", new String[] { "java.util.", }, ZERO_STRINGS, "java.awt.List", false); + checkImportMatch("*List", new String[] { "java.util.", }, ZERO_STRINGS, "java.util.List", true); + + checkImportMatch("*List", ZERO_STRINGS, new String[] { "java.awt.List", }, "java.awt.List", true); + + checkImportMatch("awt.*List", ZERO_STRINGS, new String[] { "java.awt.List", }, "java.awt.List", false); + checkImportMatch("*Foo", ZERO_STRINGS, new String[] { "java.awt.List", }, "java.awt.List", false); + + checkImportMatch("*List", new String[] { "java.util.", "java.awt.", }, + ZERO_STRINGS, "java.util.List", true); + checkImportMatch("*List", new String[] { "java.util.", "java.awt.", }, + ZERO_STRINGS, "java.awt.List", true); + + checkImportMatch("*..List", new String[] { "java.util." }, ZERO_STRINGS, "java.util.List", true); + checkImportMatch("*..List", new String[] { "java.util." }, ZERO_STRINGS, "java.awt.List", true); + + } + + public void testImportMatchWithInners() { + world = new BcelWorld(); + checkImportMatch("*Entry", new String[] { "java.util.", "java.util.Map$"}, ZERO_STRINGS, + "java.util.Map$Entry", true); + + checkImportMatch("java.util.Map.*Entry", ZERO_STRINGS, ZERO_STRINGS, + "java.util.Map$Entry", true); + + checkImportMatch("*Entry", new String[] { "java.util.", }, ZERO_STRINGS, + "java.util.Map$Entry", false); + + checkImportMatch("*.Entry", new String[] { "java.util.", }, ZERO_STRINGS, + "java.util.Map$Entry", true); + + checkImportMatch("Map.*", new String[] { "java.util.", }, ZERO_STRINGS, + "java.util.Map$Entry", true); + + checkImportMatch("Map.*", ZERO_STRINGS, new String[] { "java.util.Map" }, + "java.util.Map$Entry", true); + } + + private void checkImportMatch( + String wildPattern, + String[] importedPackages, + String[] importedNames, + String matchName, + boolean shouldMatch) + { + WildTypePattern p = makeResolvedWildTypePattern(wildPattern, importedPackages, importedNames); + checkPatternMatch(p, matchName, shouldMatch); + } + + + private WildTypePattern makeResolvedWildTypePattern( + String wildPattern, + String[] importedPackages, + String[] importedNames) + { + WildTypePattern unresolved = (WildTypePattern) new PatternParser(wildPattern).parseTypePattern(); + + WildTypePattern resolved = resolve(unresolved, importedPackages, importedNames); + return resolved; + + } + + private WildTypePattern resolve( + WildTypePattern unresolved, + String[] importedPrefixes, + String[] importedNames) + { + + TestScope scope = makeTestScope(); + scope.setImportedPrefixes(importedPrefixes); + scope.setImportedNames(importedNames); + return (WildTypePattern) unresolved.resolveBindings(scope, Bindings.NONE, false); + } + + + + public static final String[] ZERO_STRINGS = new String[0]; + + public void testInstanceofMatch() { + world = new BcelWorld(); + + checkInstanceofMatch("java.lang.Object", "java.lang.Object", FuzzyBoolean.YES); + + checkIllegalInstanceofMatch("java.lang.Object+", "java.lang.Object"); + checkIllegalInstanceofMatch("java.lang.Object+", "java.lang.String"); + checkIllegalInstanceofMatch("java.lang.String+", "java.lang.Object"); + checkIllegalInstanceofMatch("java.lang.*", "java.lang.Object"); + checkInstanceofMatch("java.lang.Integer", "java.lang.String", FuzzyBoolean.NO); + + checkInstanceofMatch("java.lang.Number", "java.lang.Integer", FuzzyBoolean.YES); + checkInstanceofMatch("java.lang.Integer", "java.lang.Number", FuzzyBoolean.MAYBE); + + + checkIllegalInstanceofMatch("java..Integer", "java.lang.Integer"); + + + checkInstanceofMatch("*", "java.lang.Integer", FuzzyBoolean.YES); + + + } + + private void checkIllegalInstanceofMatch(String pattern, String name) { + try { + TypePattern p = makeTypePattern(pattern); + ResolvedTypeX type = world.resolve(name); + FuzzyBoolean result = p.matchesInstanceof(type); + } catch (AbortException e) { + return; + } + assertTrue("matching " + pattern + " with " + name + " should fail", false); + } + + private void checkInstanceofMatch(String pattern, String name, FuzzyBoolean shouldMatch) { + TypePattern p = makeTypePattern(pattern); + ResolvedTypeX type = world.resolve(name); + + p = p.resolveBindings(makeTestScope(), null, false); + + + //System.out.println("type: " + p); + FuzzyBoolean result = p.matchesInstanceof(type); + String msg = "matches " + pattern + " to " + type; + assertEquals(msg, shouldMatch, result); + } + + private TestScope makeTestScope() { + TestScope scope = new TestScope(ZERO_STRINGS, ZERO_STRINGS, world); + return scope; + } + + private TypePattern makeTypePattern(String pattern) { + return new PatternParser(pattern).parseSingleTypePattern(); + } + + private void checkMatch(String pattern, String name, boolean shouldMatch) { + TypePattern p = makeTypePattern(pattern); + p = p.resolveBindings(makeTestScope(), null, false); + checkPatternMatch(p, name, shouldMatch); + } + + private void checkPatternMatch( + TypePattern p, + String name, + boolean shouldMatch) + { + ResolvedTypeX type = world.resolve(name); + //System.out.println("type: " + type); + boolean result = p.matchesStatically(type); + String msg = "matches " + p + " to " + type + " expected "; + if (shouldMatch) { + assertTrue(msg + shouldMatch, result); + } else { + assertTrue(msg + shouldMatch, !result); + } + } + + public void testSerialization() throws IOException { + String[] patterns = new String[] { + "java.lang.Object", "java.lang.Object+", "java.lang.Integer", + "int", "java..*", "java..util..*", "*.*.Object", "*", + }; + + for (int i=0, len=patterns.length; i < len; i++) { + checkSerialization(patterns[i]); + } + } + + /** + * Method checkSerialization. + * @param string + */ + private void checkSerialization(String string) throws IOException { + TypePattern p = makeTypePattern(string); + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + TypePattern newP = TypePattern.read(in, null); + + assertEquals("write/read", p, newP); + } + +} diff --git a/weaver/testsrc/org/aspectj/weaver/patterns/WithinTestCase.java b/weaver/testsrc/org/aspectj/weaver/patterns/WithinTestCase.java new file mode 100644 index 000000000..4d8fef75b --- /dev/null +++ b/weaver/testsrc/org/aspectj/weaver/patterns/WithinTestCase.java @@ -0,0 +1,102 @@ +/* ******************************************************************* + * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC). + * All rights reserved. + * This program and the accompanying materials are made available + * under the terms of the Common Public License v1.0 + * which accompanies this distribution and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * Xerox/PARC initial implementation + * ******************************************************************/ + + +package org.aspectj.weaver.patterns; + +import java.io.*; + +import junit.framework.TestCase; + +import org.aspectj.weaver.*; +import org.aspectj.weaver.bcel.*; +import org.aspectj.weaver.bcel.BcelWorld; +import org.aspectj.util.FuzzyBoolean; + +public class WithinTestCase extends TestCase { + + World world = new BcelWorld(); + + public WithinTestCase(String name) { + super(name); + } + + public void testMatch() throws IOException { + Shadow getOutFromArrayList = new TestShadow( + Shadow.FieldGet, + Member.fieldFromString("java.io.PrintStream java.lang.System.out"), + TypeX.forName("java.util.ArrayList"), + world); + + checkMatch(makePointcut("within(*)"), getOutFromArrayList, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.util.*)"), getOutFromArrayList, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.lang.*)"), getOutFromArrayList, FuzzyBoolean.NO); + checkMatch(makePointcut("within(java.util.List+)"), getOutFromArrayList, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.uti*.List+)"), getOutFromArrayList, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.uti*..*)"), getOutFromArrayList, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.util.*List)"), getOutFromArrayList, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.util.List*)"), getOutFromArrayList, FuzzyBoolean.NO); + + + Shadow getOutFromEntry = new TestShadow( + Shadow.FieldGet, + Member.fieldFromString("java.io.PrintStream java.lang.System.out"), + TypeX.forName("java.util.Map$Entry"), + world); + + checkMatch(makePointcut("within(*)"), getOutFromEntry, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.util.*)"), getOutFromEntry, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.util.Map.*)"), getOutFromEntry, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.util..*)"), getOutFromEntry, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.util.Map..*)"), getOutFromEntry, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.lang.*)"), getOutFromEntry, FuzzyBoolean.NO); + checkMatch(makePointcut("within(java.util.List+)"), getOutFromEntry, FuzzyBoolean.NO); + checkMatch(makePointcut("within(java.util.Map+)"), getOutFromEntry, FuzzyBoolean.YES); + checkMatch(makePointcut("within(java.lang.Object+)"), getOutFromEntry, FuzzyBoolean.YES); + + //this is something we should in type patterns tests + //checkMatch(makePointcut("within(*List)"), getOut, FuzzyBoolean.NO); + + } + + public Pointcut makePointcut(String pattern) { + Pointcut pointcut0 = Pointcut.fromString(pattern); + + Bindings bindingTable = new Bindings(0); + IScope scope = new SimpleScope(world, FormalBinding.NONE); + + pointcut0.resolveBindings(scope, bindingTable); + Pointcut pointcut1 = pointcut0; + return pointcut1.concretize1(null, new IntMap()); + } + + + private void checkMatch(Pointcut p, Shadow s, FuzzyBoolean shouldMatch) throws IOException { + FuzzyBoolean doesMatch = p.match(s); + assertEquals(p + " matches " + s, shouldMatch, doesMatch); + checkSerialization(p); + } + + private void checkSerialization(Pointcut p) throws IOException { + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bo); + p.write(out); + out.close(); + + ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); + DataInputStream in = new DataInputStream(bi); + Pointcut newP = Pointcut.read(in, null); + + assertEquals("write/read", p, newP); + } + +} |