You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

AspectDeclaration.java 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889
  1. /* *******************************************************************
  2. * Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
  3. * All rights reserved.
  4. * This program and the accompanying materials are made available
  5. * under the terms of the Common Public License v1.0
  6. * which accompanies this distribution and is available at
  7. * http://www.eclipse.org/legal/cpl-v10.html
  8. *
  9. * Contributors:
  10. * PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.ajdt.internal.compiler.ast;
  13. import java.lang.reflect.Modifier;
  14. import java.util.*;
  15. import org.aspectj.ajdt.internal.compiler.lookup.*;
  16. import org.aspectj.weaver.*;
  17. import org.aspectj.weaver.patterns.*;
  18. import org.aspectj.org.eclipse.jdt.internal.compiler.ClassFile;
  19. import org.aspectj.org.eclipse.jdt.internal.compiler.CompilationResult;
  20. //import org.aspectj.org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
  21. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.Clinit;
  22. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
  23. //import org.aspectj.org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
  24. import org.aspectj.org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
  25. import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.CodeStream;
  26. import org.aspectj.org.eclipse.jdt.internal.compiler.codegen.Label;
  27. import org.aspectj.org.eclipse.jdt.internal.compiler.env.IGenericType;
  28. import org.aspectj.org.eclipse.jdt.internal.compiler.lookup.*;
  29. //import org.aspectj.org.eclipse.jdt.internal.compiler.parser.Parser;
  30. // (we used to...) making all aspects member types avoids a nasty hierarchy pain
  31. // switched from MemberTypeDeclaration to TypeDeclaration
  32. public class AspectDeclaration extends TypeDeclaration {
  33. //public IAjDeclaration[] ajDeclarations;
  34. private AjAttribute.Aspect aspectAttribute;
  35. public PerClause perClause;
  36. public ResolvedMember aspectOfMethod;
  37. public ResolvedMember hasAspectMethod;
  38. public Map accessForInline = new HashMap();
  39. public Map superAccessForInline = new HashMap();
  40. public boolean isPrivileged;
  41. public EclipseSourceType concreteName;
  42. public ResolvedTypeX.Name typeX;
  43. public EclipseFactory factory; //??? should use this consistently
  44. public int adviceCounter = 1; // Used as a part of the generated name for advice methods
  45. // for better error messages in 1.0 to 1.1 transition
  46. public TypePattern dominatesPattern;
  47. public AspectDeclaration(CompilationResult compilationResult) {
  48. super(compilationResult);
  49. //perClause = new PerSingleton();
  50. }
  51. public boolean isAbstract() {
  52. return (modifiers & AccAbstract) != 0;
  53. }
  54. public void resolve() {
  55. if (binding == null) {
  56. ignoreFurtherInvestigation = true;
  57. return;
  58. }
  59. super.resolve();
  60. }
  61. public void checkSpec(ClassScope scope) {
  62. if (ignoreFurtherInvestigation) return;
  63. if (dominatesPattern != null) {
  64. scope.problemReporter().signalError(
  65. dominatesPattern.getStart(), dominatesPattern.getEnd(),
  66. "dominates has changed for 1.1, use 'declare precedence: " +
  67. new String(this.name) + ", " + dominatesPattern.toString() + ";' " +
  68. "in the body of the aspect instead");
  69. }
  70. if (!isAbstract()) {
  71. MethodBinding[] methods = binding.methods();
  72. for (int i=0, len = methods.length; i < len; i++) {
  73. MethodBinding m = methods[i];
  74. if (m.isConstructor()) {
  75. // this make all constructors in aspects invisible and thus uncallable
  76. //XXX this only works for aspects that come from source
  77. methods[i] = new MethodBinding(m, binding) {
  78. public boolean canBeSeenBy(
  79. InvocationSite invocationSite,
  80. Scope scope) {
  81. return false;
  82. }
  83. };
  84. if (m.parameters != null && m.parameters.length != 0) {
  85. scope.problemReporter().signalError(m.sourceStart(), m.sourceEnd(),
  86. "only zero-argument constructors allowed in concrete aspect");
  87. }
  88. }
  89. }
  90. }
  91. if (this.enclosingType != null) {
  92. if (!Modifier.isStatic(modifiers)) {
  93. scope.problemReporter().signalError(sourceStart, sourceEnd,
  94. "inner aspects must be static");
  95. ignoreFurtherInvestigation = true;
  96. return;
  97. }
  98. }
  99. EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
  100. ResolvedTypeX myType = typeX;
  101. //if (myType == null) System.err.println("bad myType for: " + this);
  102. ResolvedTypeX superType = myType.getSuperclass();
  103. // can't be Serializable/Cloneable unless -XserializableAspects
  104. if (!world.isXSerializableAspects()) {
  105. if (world.getWorld().getCoreType(TypeX.SERIALIZABLE).isAssignableFrom(myType)) {
  106. scope.problemReporter().signalError(sourceStart, sourceEnd,
  107. "aspects may not implement Serializable");
  108. ignoreFurtherInvestigation = true;
  109. return;
  110. }
  111. if (world.getWorld().getCoreType(TypeX.CLONEABLE).isAssignableFrom(myType)) {
  112. scope.problemReporter().signalError(sourceStart, sourceEnd,
  113. "aspects may not implement Cloneable");
  114. ignoreFurtherInvestigation = true;
  115. return;
  116. }
  117. }
  118. if (superType.isAspect()) {
  119. if (!superType.isAbstract()) {
  120. scope.problemReporter().signalError(sourceStart, sourceEnd,
  121. "can not extend a concrete aspect");
  122. ignoreFurtherInvestigation = true;
  123. return;
  124. }
  125. }
  126. }
  127. private FieldBinding initFailureField= null;
  128. public void generateCode(ClassFile enclosingClassFile) {
  129. if (ignoreFurtherInvestigation) {
  130. if (binding == null)
  131. return;
  132. ClassFile.createProblemType(
  133. this,
  134. scope.referenceCompilationUnit().compilationResult);
  135. return;
  136. }
  137. // make me and my binding public
  138. this.modifiers = AstUtil.makePublic(this.modifiers);
  139. this.binding.modifiers = AstUtil.makePublic(this.binding.modifiers);
  140. if (!isAbstract()) {
  141. initFailureField = factory.makeFieldBinding(AjcMemberMaker.initFailureCauseField(typeX));
  142. binding.addField(initFailureField);
  143. if (perClause == null) {
  144. // we've already produced an error for this
  145. } else if (perClause.getKind() == PerClause.SINGLETON) {
  146. binding.addField(factory.makeFieldBinding(AjcMemberMaker.perSingletonField(
  147. typeX)));
  148. methods[0] = new AspectClinit((Clinit)methods[0], compilationResult, false, true, initFailureField);
  149. } else if (perClause.getKind() == PerClause.PERCFLOW) {
  150. binding.addField(
  151. factory.makeFieldBinding(
  152. AjcMemberMaker.perCflowField(
  153. typeX)));
  154. methods[0] = new AspectClinit((Clinit)methods[0], compilationResult, true, false, null);
  155. } else if (perClause.getKind() == PerClause.PEROBJECT) {
  156. // binding.addField(
  157. // world.makeFieldBinding(
  158. // AjcMemberMaker.perCflowField(
  159. // typeX)));
  160. } else {
  161. throw new RuntimeException("unimplemented");
  162. }
  163. }
  164. if (EclipseFactory.DEBUG) System.out.println(toString());
  165. super.generateCode(enclosingClassFile);
  166. }
  167. public boolean needClassInitMethod() {
  168. return true;
  169. }
  170. protected void generateAttributes(ClassFile classFile) {
  171. if (!isAbstract()) generatePerSupportMembers(classFile);
  172. generateInlineAccessMembers(classFile);
  173. classFile.extraAttributes.add(
  174. new EclipseAttributeAdapter(new AjAttribute.Aspect(perClause)));
  175. if (binding.privilegedHandler != null) {
  176. ResolvedMember[] members = ((PrivilegedHandler)binding.privilegedHandler).getMembers();
  177. classFile.extraAttributes.add(
  178. new EclipseAttributeAdapter(new AjAttribute.PrivilegedAttribute(members)));
  179. }
  180. //XXX need to get this attribute on anyone with a pointcut for good errors
  181. classFile.extraAttributes.add(
  182. new EclipseAttributeAdapter(new AjAttribute.SourceContextAttribute(
  183. new String(compilationResult().getFileName()),
  184. compilationResult().lineSeparatorPositions)));
  185. super.generateAttributes(classFile);
  186. }
  187. private void generateInlineAccessMembers(ClassFile classFile) {
  188. for (Iterator i = superAccessForInline.values().iterator(); i.hasNext(); ) {
  189. AccessForInlineVisitor.SuperAccessMethodPair pair = (AccessForInlineVisitor.SuperAccessMethodPair)i.next();
  190. generateSuperAccessMethod(classFile, pair.accessMethod, pair.originalMethod);
  191. }
  192. for (Iterator i = accessForInline.entrySet().iterator(); i.hasNext(); ) {
  193. Map.Entry e = (Map.Entry)i.next();
  194. generateInlineAccessMethod(classFile, (Binding)e.getValue(), (ResolvedMember)e.getKey());
  195. }
  196. }
  197. private void generatePerSupportMembers(ClassFile classFile) {
  198. if (isAbstract()) return;
  199. //XXX otherwise we need to have this (error handling?)
  200. if (aspectOfMethod == null) return;
  201. if (perClause == null) {
  202. System.err.println("has null perClause: " + this);
  203. return;
  204. }
  205. EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  206. if (perClause.getKind() == PerClause.SINGLETON) {
  207. generatePerSingletonAspectOfMethod(classFile);
  208. generatePerSingletonHasAspectMethod(classFile);
  209. generatePerSingletonAjcClinitMethod(classFile);
  210. } else if (perClause.getKind() == PerClause.PERCFLOW) {
  211. generatePerCflowAspectOfMethod(classFile);
  212. generatePerCflowHasAspectMethod(classFile);
  213. generatePerCflowPushMethod(classFile);
  214. generatePerCflowAjcClinitMethod(classFile);
  215. } else if (perClause.getKind() == PerClause.PEROBJECT) {
  216. TypeBinding interfaceType =
  217. generatePerObjectInterface(classFile);
  218. world.addTypeBinding(interfaceType);
  219. generatePerObjectAspectOfMethod(classFile, interfaceType);
  220. generatePerObjectHasAspectMethod(classFile, interfaceType);
  221. generatePerObjectBindMethod(classFile, interfaceType);
  222. } else {
  223. throw new RuntimeException("unimplemented");
  224. }
  225. }
  226. private static interface BodyGenerator {
  227. public void generate(CodeStream codeStream);
  228. }
  229. private void generateMethod(ClassFile classFile, ResolvedMember member, BodyGenerator gen) {
  230. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  231. generateMethod(classFile, world.makeMethodBinding(member), gen);
  232. }
  233. private void generateMethod(ClassFile classFile, MethodBinding methodBinding, BodyGenerator gen) {
  234. generateMethod(classFile,methodBinding,null,gen);
  235. }
  236. protected List makeEffectiveSignatureAttribute(ResolvedMember sig,Shadow.Kind kind,boolean weaveBody) {
  237. List l = new ArrayList(1);
  238. l.add(new EclipseAttributeAdapter(
  239. new AjAttribute.EffectiveSignatureAttribute(sig, kind, weaveBody)));
  240. return l;
  241. }
  242. /*
  243. * additionalAttributes allows us to pass some optional attributes we want to attach to the method we generate.
  244. * Currently this is used for inline accessor methods that have been generated to allow private field references or
  245. * private method calls to be inlined (PR71377). In these cases the optional attribute is an effective signature
  246. * attribute which means calls to these methods are able to masquerade as any join point (a field set, field get or
  247. * method call). The effective signature attribute is 'unwrapped' in BcelClassWeaver.matchInvokeInstruction()
  248. */
  249. private void generateMethod(ClassFile classFile, MethodBinding methodBinding, List additionalAttributes/*ResolvedMember realMember*/, BodyGenerator gen) {
  250. // EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  251. classFile.generateMethodInfoHeader(methodBinding);
  252. int methodAttributeOffset = classFile.contentsOffset;
  253. int attributeNumber;
  254. if (additionalAttributes!=null) { // mini optimization
  255. List attrs = new ArrayList();
  256. attrs.addAll(AstUtil.getAjSyntheticAttribute());
  257. attrs.addAll(additionalAttributes);
  258. attributeNumber = classFile.generateMethodInfoAttribute(methodBinding, false, attrs);
  259. } else {
  260. attributeNumber = classFile.generateMethodInfoAttribute(methodBinding, false, AstUtil.getAjSyntheticAttribute());
  261. }
  262. int codeAttributeOffset = classFile.contentsOffset;
  263. classFile.generateCodeAttributeHeader();
  264. CodeStream codeStream = classFile.codeStream;
  265. // Use reset() rather than init()
  266. // XXX We need a scope to keep reset happy, initializerScope is *not* the right one, but it works !
  267. // codeStream.init(classFile);
  268. // codeStream.initializeMaxLocals(methodBinding);
  269. MethodDeclaration md = AstUtil.makeMethodDeclaration(methodBinding);
  270. md.scope = initializerScope;
  271. codeStream.reset(md,classFile);
  272. // body starts here
  273. gen.generate(codeStream);
  274. // body ends here
  275. classFile.completeCodeAttribute(codeAttributeOffset);
  276. attributeNumber++;
  277. classFile.completeMethodInfo(methodAttributeOffset, attributeNumber);
  278. }
  279. private void generatePerCflowAspectOfMethod(
  280. ClassFile classFile)
  281. {
  282. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  283. generateMethod(classFile, aspectOfMethod, new BodyGenerator() {
  284. public void generate(CodeStream codeStream) {
  285. // body starts here
  286. codeStream.getstatic(
  287. world.makeFieldBinding(
  288. AjcMemberMaker.perCflowField(
  289. typeX)));
  290. codeStream.invokevirtual(world.makeMethodBindingForCall(
  291. AjcMemberMaker.cflowStackPeekInstance()));
  292. codeStream.checkcast(binding);
  293. codeStream.areturn();
  294. // body ends here
  295. }});
  296. }
  297. private void generatePerCflowHasAspectMethod(ClassFile classFile) {
  298. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  299. generateMethod(classFile, hasAspectMethod, new BodyGenerator() {
  300. public void generate(CodeStream codeStream) {
  301. // body starts here
  302. codeStream.getstatic(
  303. world.makeFieldBinding(
  304. AjcMemberMaker.perCflowField(
  305. typeX)));
  306. codeStream.invokevirtual(world.makeMethodBindingForCall(
  307. AjcMemberMaker.cflowStackIsValid()));
  308. codeStream.ireturn();
  309. // body ends here
  310. }});
  311. }
  312. private void generatePerCflowPushMethod(
  313. ClassFile classFile)
  314. {
  315. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  316. generateMethod(classFile, world.makeMethodBinding(AjcMemberMaker.perCflowPush(
  317. EclipseFactory.fromBinding(binding))),
  318. new BodyGenerator() {
  319. public void generate(CodeStream codeStream) {
  320. // body starts here
  321. codeStream.getstatic(
  322. world.makeFieldBinding(
  323. AjcMemberMaker.perCflowField(
  324. typeX)));
  325. codeStream.new_(binding);
  326. codeStream.dup();
  327. codeStream.invokespecial(
  328. new MethodBinding(0, "<init>".toCharArray(),
  329. BaseTypes.VoidBinding, new TypeBinding[0],
  330. new ReferenceBinding[0], binding));
  331. codeStream.invokevirtual(world.makeMethodBindingForCall(
  332. AjcMemberMaker.cflowStackPushInstance()));
  333. codeStream.return_();
  334. // body ends here
  335. }});
  336. }
  337. private void generatePerCflowAjcClinitMethod(
  338. ClassFile classFile)
  339. {
  340. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  341. generateMethod(classFile, world.makeMethodBinding(AjcMemberMaker.ajcPreClinitMethod(
  342. EclipseFactory.fromBinding(binding))),
  343. new BodyGenerator() {
  344. public void generate(CodeStream codeStream) {
  345. // body starts here
  346. codeStream.new_(world.makeTypeBinding(AjcMemberMaker.CFLOW_STACK_TYPE));
  347. codeStream.dup();
  348. codeStream.invokespecial(world.makeMethodBindingForCall(AjcMemberMaker.cflowStackInit()));
  349. codeStream.putstatic(
  350. world.makeFieldBinding(
  351. AjcMemberMaker.perCflowField(
  352. typeX)));
  353. codeStream.return_();
  354. // body ends here
  355. }});
  356. }
  357. private TypeBinding generatePerObjectInterface(
  358. ClassFile classFile)
  359. {
  360. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  361. TypeX interfaceTypeX =
  362. AjcMemberMaker.perObjectInterfaceType(typeX);
  363. HelperInterfaceBinding interfaceType =
  364. new HelperInterfaceBinding(this.binding, interfaceTypeX);
  365. world.addTypeBinding(interfaceType);
  366. interfaceType.addMethod(world, AjcMemberMaker.perObjectInterfaceGet(typeX));
  367. interfaceType.addMethod(world, AjcMemberMaker.perObjectInterfaceSet(typeX));
  368. interfaceType.generateClass(compilationResult, classFile);
  369. return interfaceType;
  370. }
  371. private void generatePerObjectAspectOfMethod(
  372. ClassFile classFile,
  373. final TypeBinding interfaceType)
  374. {
  375. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  376. generateMethod(classFile, aspectOfMethod, new BodyGenerator() {
  377. public void generate(CodeStream codeStream) {
  378. // body starts here
  379. Label wrongType = new Label(codeStream);
  380. Label popWrongType = new Label(codeStream);
  381. codeStream.aload_0();
  382. codeStream.instance_of(interfaceType);
  383. codeStream.ifeq(wrongType);
  384. codeStream.aload_0();
  385. codeStream.checkcast(interfaceType);
  386. codeStream.invokeinterface(world.makeMethodBindingForCall(
  387. AjcMemberMaker.perObjectInterfaceGet(typeX)));
  388. codeStream.dup();
  389. codeStream.ifnull(popWrongType);
  390. codeStream.areturn();
  391. popWrongType.place();
  392. codeStream.pop();
  393. wrongType.place();
  394. codeStream.new_(world.makeTypeBinding(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION));
  395. codeStream.dup();
  396. codeStream.invokespecial(world.makeMethodBindingForCall(
  397. AjcMemberMaker.noAspectBoundExceptionInit()
  398. ));
  399. codeStream.athrow();
  400. // body ends here
  401. }});
  402. }
  403. private void generatePerObjectHasAspectMethod(ClassFile classFile,
  404. final TypeBinding interfaceType) {
  405. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  406. generateMethod(classFile, hasAspectMethod, new BodyGenerator() {
  407. public void generate(CodeStream codeStream) {
  408. // body starts here
  409. Label wrongType = new Label(codeStream);
  410. codeStream.aload_0();
  411. codeStream.instance_of(interfaceType);
  412. codeStream.ifeq(wrongType);
  413. codeStream.aload_0();
  414. codeStream.checkcast(interfaceType);
  415. codeStream.invokeinterface(world.makeMethodBindingForCall(
  416. AjcMemberMaker.perObjectInterfaceGet(typeX)));
  417. codeStream.ifnull(wrongType);
  418. codeStream.iconst_1();
  419. codeStream.ireturn();
  420. wrongType.place();
  421. codeStream.iconst_0();
  422. codeStream.ireturn();
  423. // body ends here
  424. }});
  425. }
  426. private void generatePerObjectBindMethod(
  427. ClassFile classFile,
  428. final TypeBinding interfaceType)
  429. {
  430. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  431. generateMethod(classFile, AjcMemberMaker.perObjectBind(EclipseFactory.fromBinding(binding)),
  432. new BodyGenerator() {
  433. public void generate(CodeStream codeStream) {
  434. // body starts here
  435. Label wrongType = new Label(codeStream);
  436. codeStream.aload_0();
  437. codeStream.instance_of(interfaceType);
  438. codeStream.ifeq(wrongType); //XXX this case might call for screaming
  439. codeStream.aload_0();
  440. codeStream.checkcast(interfaceType);
  441. codeStream.invokeinterface(world.makeMethodBindingForCall(
  442. AjcMemberMaker.perObjectInterfaceGet(typeX)));
  443. //XXX should do a check for null here and throw a NoAspectBound
  444. codeStream.ifnonnull(wrongType);
  445. codeStream.aload_0();
  446. codeStream.checkcast(interfaceType);
  447. codeStream.new_(binding);
  448. codeStream.dup();
  449. codeStream.invokespecial(
  450. new MethodBinding(0, "<init>".toCharArray(),
  451. BaseTypes.VoidBinding, new TypeBinding[0],
  452. new ReferenceBinding[0], binding));
  453. codeStream.invokeinterface(world.makeMethodBindingForCall(
  454. AjcMemberMaker.perObjectInterfaceSet(typeX)));
  455. wrongType.place();
  456. codeStream.return_();
  457. // body ends here
  458. }});
  459. }
  460. private void generatePerSingletonAspectOfMethod(ClassFile classFile) {
  461. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  462. generateMethod(classFile, aspectOfMethod, new BodyGenerator() {
  463. public void generate(CodeStream codeStream) {
  464. // Old style aspectOf() method which confused decompilers
  465. // // body starts here
  466. // codeStream.getstatic(world.makeFieldBinding(AjcMemberMaker.perSingletonField(
  467. // typeX)));
  468. // Label isNull = new Label(codeStream);
  469. // codeStream.dup();
  470. // codeStream.ifnull(isNull);
  471. // codeStream.areturn();
  472. // isNull.place();
  473. //
  474. // codeStream.incrStackSize(+1); // the dup trick above confuses the stack counter
  475. // codeStream.new_(world.makeTypeBinding(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION));
  476. // codeStream.dup();
  477. // codeStream.ldc(typeX.getNameAsIdentifier());
  478. // codeStream.getstatic(initFailureField);
  479. // codeStream.invokespecial(world.makeMethodBindingForCall(
  480. // AjcMemberMaker.noAspectBoundExceptionInitWithCause()
  481. // ));
  482. // codeStream.athrow();
  483. // // body ends here
  484. // The stuff below generates code that looks like this:
  485. /*
  486. * if (ajc$perSingletonInstance == null)
  487. * throw new NoAspectBoundException("A", ajc$initFailureCause);
  488. * else
  489. * return ajc$perSingletonInstance;
  490. */
  491. // body starts here (see end of each line for what it is doing!)
  492. FieldBinding fb = world.makeFieldBinding(AjcMemberMaker.perSingletonField(typeX));
  493. codeStream.getstatic(fb); // GETSTATIC
  494. Label isNonNull = new Label(codeStream);
  495. codeStream.ifnonnull(isNonNull); // IFNONNULL
  496. codeStream.new_(world.makeTypeBinding(AjcMemberMaker.NO_ASPECT_BOUND_EXCEPTION)); // NEW
  497. codeStream.dup(); // DUP
  498. codeStream.ldc(typeX.getNameAsIdentifier()); // LDC
  499. codeStream.getstatic(initFailureField); // GETSTATIC
  500. codeStream.invokespecial(world.makeMethodBindingForCall(
  501. AjcMemberMaker.noAspectBoundExceptionInitWithCause())); // INVOKESPECIAL
  502. codeStream.athrow(); // ATHROW
  503. isNonNull.place();
  504. codeStream.getstatic(fb); // GETSTATIC
  505. codeStream.areturn(); // ARETURN
  506. // body ends here
  507. }});
  508. }
  509. private void generatePerSingletonHasAspectMethod(ClassFile classFile) {
  510. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  511. generateMethod(classFile, hasAspectMethod, new BodyGenerator() {
  512. public void generate(CodeStream codeStream) {
  513. // body starts here
  514. codeStream.getstatic(world.makeFieldBinding(AjcMemberMaker.perSingletonField(
  515. typeX)));
  516. Label isNull = new Label(codeStream);
  517. codeStream.ifnull(isNull);
  518. codeStream.iconst_1();
  519. codeStream.ireturn();
  520. isNull.place();
  521. codeStream.iconst_0();
  522. codeStream.ireturn();
  523. // body ends here
  524. }});
  525. }
  526. private void generatePerSingletonAjcClinitMethod(
  527. ClassFile classFile)
  528. {
  529. final EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(this.scope);
  530. generateMethod(classFile, world.makeMethodBinding(AjcMemberMaker.ajcPostClinitMethod(
  531. EclipseFactory.fromBinding(binding))),
  532. new BodyGenerator() {
  533. public void generate(CodeStream codeStream) {
  534. // body starts here
  535. codeStream.new_(binding);
  536. codeStream.dup();
  537. codeStream.invokespecial(
  538. new MethodBinding(0, "<init>".toCharArray(),
  539. BaseTypes.VoidBinding, new TypeBinding[0],
  540. new ReferenceBinding[0], binding));
  541. codeStream.putstatic(
  542. world.makeFieldBinding(
  543. AjcMemberMaker.perSingletonField(
  544. typeX)));
  545. codeStream.return_();
  546. // body ends here
  547. }});
  548. }
  549. private void generateSuperAccessMethod(ClassFile classFile, final MethodBinding accessMethod, final ResolvedMember method) {
  550. generateMethod(classFile, accessMethod,
  551. new BodyGenerator() {
  552. public void generate(CodeStream codeStream) {
  553. // body starts here
  554. codeStream.aload_0();
  555. AstUtil.generateParameterLoads(accessMethod.parameters, codeStream);
  556. codeStream.invokespecial(
  557. factory.makeMethodBinding(method));
  558. AstUtil.generateReturn(accessMethod.returnType, codeStream);
  559. // body ends here
  560. }});
  561. }
  562. private void generateInlineAccessMethod(ClassFile classFile, final Binding binding, final ResolvedMember member) {
  563. if (binding instanceof InlineAccessFieldBinding) {
  564. generateInlineAccessors(classFile, (InlineAccessFieldBinding)binding, member);
  565. } else {
  566. generateInlineAccessMethod(classFile, (MethodBinding)binding, member);
  567. }
  568. }
  569. private void generateInlineAccessors(ClassFile classFile, final InlineAccessFieldBinding accessField, final ResolvedMember field) {
  570. final FieldBinding fieldBinding = factory.makeFieldBinding(field);
  571. generateMethod(classFile, accessField.reader,
  572. makeEffectiveSignatureAttribute(field,Shadow.FieldGet,false),
  573. new BodyGenerator() {
  574. public void generate(CodeStream codeStream) {
  575. // body starts here
  576. if (field.isStatic()) {
  577. codeStream.getstatic(fieldBinding);
  578. } else {
  579. codeStream.aload_0();
  580. codeStream.getfield(fieldBinding);
  581. }
  582. AstUtil.generateReturn(accessField.reader.returnType, codeStream);
  583. // body ends here
  584. }});
  585. generateMethod(classFile, accessField.writer,
  586. makeEffectiveSignatureAttribute(field,Shadow.FieldSet,false),
  587. new BodyGenerator() {
  588. public void generate(CodeStream codeStream) {
  589. // body starts here
  590. if (field.isStatic()) {
  591. codeStream.load(fieldBinding.type, 0);
  592. codeStream.putstatic(fieldBinding);
  593. } else {
  594. codeStream.aload_0();
  595. codeStream.load(fieldBinding.type, 1);
  596. codeStream.putfield(fieldBinding);
  597. }
  598. codeStream.return_();
  599. // body ends here
  600. }});
  601. }
  602. private void generateInlineAccessMethod(ClassFile classFile, final MethodBinding accessMethod, final ResolvedMember method) {
  603. generateMethod(classFile, accessMethod,
  604. makeEffectiveSignatureAttribute(method, Shadow.MethodCall, false),
  605. new BodyGenerator() {
  606. public void generate(CodeStream codeStream) {
  607. // body starts here
  608. AstUtil.generateParameterLoads(accessMethod.parameters, codeStream);
  609. if (method.isStatic()) {
  610. codeStream.invokestatic(factory.makeMethodBinding(method));
  611. } else {
  612. codeStream.invokevirtual(factory.makeMethodBinding(method));
  613. }
  614. AstUtil.generateReturn(accessMethod.returnType, codeStream);
  615. // body ends here
  616. }});
  617. }
  618. private PerClause.Kind lookupPerClauseKind(ReferenceBinding binding) {
  619. PerClause perClause;
  620. if (binding instanceof BinaryTypeBinding) {
  621. ResolvedTypeX superTypeX = factory.fromEclipse(binding);
  622. perClause = superTypeX.getPerClause();
  623. } else if (binding instanceof SourceTypeBinding ) {
  624. SourceTypeBinding sourceSc = (SourceTypeBinding)binding;
  625. if (sourceSc.scope.referenceContext instanceof AspectDeclaration) {
  626. perClause = ((AspectDeclaration)sourceSc.scope.referenceContext).perClause;
  627. } else {
  628. return null;
  629. }
  630. } else {
  631. //XXX need to handle this too
  632. return null;
  633. }
  634. if (perClause == null) {
  635. return lookupPerClauseKind(binding.superclass());
  636. } else {
  637. return perClause.getKind();
  638. }
  639. }
  640. private void buildPerClause(ClassScope scope) {
  641. EclipseFactory world = EclipseFactory.fromScopeLookupEnvironment(scope);
  642. if (perClause == null) {
  643. PerClause.Kind kind = lookupPerClauseKind(binding.superclass);
  644. if (kind == null) {
  645. perClause = new PerSingleton();
  646. } else {
  647. perClause = new PerFromSuper(kind);
  648. }
  649. }
  650. aspectAttribute = new AjAttribute.Aspect(perClause);
  651. if (ignoreFurtherInvestigation) return; //???
  652. if (!isAbstract()) {
  653. if (perClause.getKind() == PerClause.SINGLETON) {
  654. aspectOfMethod = AjcMemberMaker.perSingletonAspectOfMethod(typeX);
  655. hasAspectMethod = AjcMemberMaker.perSingletonHasAspectMethod(typeX);
  656. } else if (perClause.getKind() == PerClause.PERCFLOW) {
  657. aspectOfMethod = AjcMemberMaker.perCflowAspectOfMethod(typeX);
  658. hasAspectMethod = AjcMemberMaker.perCflowHasAspectMethod(typeX);
  659. } else if (perClause.getKind() == PerClause.PEROBJECT) {
  660. aspectOfMethod = AjcMemberMaker.perObjectAspectOfMethod(typeX);
  661. hasAspectMethod = AjcMemberMaker.perObjectHasAspectMethod(typeX);
  662. } else {
  663. throw new RuntimeException("bad per clause: " + perClause);
  664. }
  665. binding.addMethod(world.makeMethodBinding(aspectOfMethod));
  666. binding.addMethod(world.makeMethodBinding(hasAspectMethod));
  667. }
  668. resolvePerClause(); //XXX might be too soon for some error checking
  669. }
  670. private PerClause resolvePerClause() {
  671. EclipseScope iscope = new EclipseScope(new FormalBinding[0], scope);
  672. perClause.resolve(iscope);
  673. return perClause;
  674. }
  675. public void buildInterTypeAndPerClause(ClassScope classScope) {
  676. factory = EclipseFactory.fromScopeLookupEnvironment(scope);
  677. if (isPrivileged) {
  678. binding.privilegedHandler = new PrivilegedHandler(this);
  679. }
  680. checkSpec(classScope);
  681. if (ignoreFurtherInvestigation) return;
  682. buildPerClause(scope);
  683. if (methods != null) {
  684. for (int i = 0; i < methods.length; i++) {
  685. if (methods[i] instanceof InterTypeDeclaration) {
  686. EclipseTypeMunger m = ((InterTypeDeclaration)methods[i]).build(classScope);
  687. if (m != null) concreteName.typeMungers.add(m);
  688. } else if (methods[i] instanceof DeclareDeclaration) {
  689. Declare d = ((DeclareDeclaration)methods[i]).build(classScope);
  690. if (d != null) concreteName.declares.add(d);
  691. }
  692. }
  693. }
  694. concreteName.getDeclaredPointcuts();
  695. }
  696. // public String toString(int tab) {
  697. // return tabString(tab) + toStringHeader() + toStringBody(tab);
  698. // }
  699. //
  700. // public String toStringBody(int tab) {
  701. //
  702. // String s = " {"; //$NON-NLS-1$
  703. //
  704. //
  705. // if (memberTypes != null) {
  706. // for (int i = 0; i < memberTypes.length; i++) {
  707. // if (memberTypes[i] != null) {
  708. // s += "\n" + memberTypes[i].toString(tab + 1); //$NON-NLS-1$
  709. // }
  710. // }
  711. // }
  712. // if (fields != null) {
  713. // for (int fieldI = 0; fieldI < fields.length; fieldI++) {
  714. // if (fields[fieldI] != null) {
  715. // s += "\n" + fields[fieldI].toString(tab + 1); //$NON-NLS-1$
  716. // if (fields[fieldI].isField())
  717. // s += ";"; //$NON-NLS-1$
  718. // }
  719. // }
  720. // }
  721. // if (methods != null) {
  722. // for (int i = 0; i < methods.length; i++) {
  723. // if (methods[i] != null) {
  724. // s += "\n" + methods[i].toString(tab + 1); //$NON-NLS-1$
  725. // }
  726. // }
  727. // }
  728. // s += "\n" + tabString(tab) + "}"; //$NON-NLS-2$ //$NON-NLS-1$
  729. // return s;
  730. // }
  731. public StringBuffer printHeader(int indent, StringBuffer output) {
  732. printModifiers(this.modifiers, output);
  733. output.append("aspect " );
  734. output.append(name);
  735. if (superclass != null) {
  736. output.append(" extends "); //$NON-NLS-1$
  737. superclass.print(0, output);
  738. }
  739. if (superInterfaces != null && superInterfaces.length > 0) {
  740. output.append((kind() == IGenericType.INTERFACE_DECL) ? " extends " : " implements ");//$NON-NLS-2$ //$NON-NLS-1$
  741. for (int i = 0; i < superInterfaces.length; i++) {
  742. if (i > 0) output.append( ", "); //$NON-NLS-1$
  743. superInterfaces[i].print(0, output);
  744. }
  745. }
  746. return output;
  747. //XXX we should append the per-clause
  748. }
  749. }