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.

BcelShadow.java 64KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790
  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. * Xerox/PARC initial implementation
  11. * ******************************************************************/
  12. package org.aspectj.weaver.bcel;
  13. import java.io.File;
  14. import java.lang.reflect.Modifier;
  15. import java.util.*;
  16. import org.apache.bcel.Constants;
  17. import org.apache.bcel.classfile.Field;
  18. import org.apache.bcel.generic.*;
  19. import org.aspectj.bridge.SourceLocation;
  20. import org.aspectj.weaver.*;
  21. import org.aspectj.weaver.Shadow.Kind;
  22. import org.aspectj.weaver.ast.Var;
  23. /*
  24. * Some fun implementation stuff:
  25. *
  26. * * expressionKind advice is non-execution advice
  27. * * may have a target.
  28. * * if the body is extracted, it will be extracted into
  29. * a static method. The first argument to the static
  30. * method is the target
  31. * * advice may expose a this object, but that's the advice's
  32. * consideration, not ours. This object will NOT be cached in another
  33. * local, but will always come from frame zero.
  34. *
  35. * * non-expressionKind advice is execution advice
  36. * * may have a this.
  37. * * target is same as this, and is exposed that way to advice
  38. * (i.e., target will not be cached, will always come from frame zero)
  39. * * if the body is extracted, it will be extracted into a method
  40. * with same static/dynamic modifier as enclosing method. If non-static,
  41. * target of callback call will be this.
  42. *
  43. * * because of these two facts, the setup of the actual arguments (including
  44. * possible target) callback method is the same for both kinds of advice:
  45. * push the targetVar, if it exists (it will not exist for advice on static
  46. * things), then push all the argVars.
  47. *
  48. * Protected things:
  49. *
  50. * * the above is sufficient for non-expressionKind advice for protected things,
  51. * since the target will always be this.
  52. *
  53. * * For expressionKind things, we have to modify the signature of the callback
  54. * method slightly. For non-static expressionKind things, we modify
  55. * the first argument of the callback method NOT to be the type specified
  56. * by the method/field signature (the owner), but rather we type it to
  57. * the currentlyEnclosing type. We are guaranteed this will be fine,
  58. * since the verifier verifies that the target is a subtype of the currently
  59. * enclosingType.
  60. *
  61. * Worries:
  62. *
  63. * * ConstructorCalls will be weirder than all of these, since they
  64. * supposedly don't have a target (according to AspectJ), but they clearly
  65. * do have a target of sorts, just one that needs to be pushed on the stack,
  66. * dupped, and not touched otherwise until the constructor runs.
  67. *
  68. */
  69. public class BcelShadow extends Shadow {
  70. private ShadowRange range;
  71. private final BcelWorld world;
  72. private final LazyMethodGen enclosingMethod;
  73. private final BcelShadow enclosingShadow;
  74. private boolean fallsThrough;
  75. // ---- initialization
  76. /**
  77. * This generates an unassociated shadow, rooted in a particular method but not rooted
  78. * to any particular point in the code. It should be given to a rooted ShadowRange
  79. * in the {@link ShadowRange#associateWithShadow(BcelShadow)} method.
  80. */
  81. public BcelShadow(
  82. BcelWorld world,
  83. Kind kind,
  84. Member signature,
  85. LazyMethodGen enclosingMethod,
  86. BcelShadow enclosingShadow)
  87. {
  88. super(kind, signature);
  89. this.world = world;
  90. this.enclosingMethod = enclosingMethod;
  91. this.enclosingShadow = enclosingShadow;
  92. fallsThrough = kind.argsOnStack();
  93. }
  94. // ---- copies all state, including Shadow's mungers...
  95. public BcelShadow copyInto(LazyMethodGen recipient, BcelShadow enclosing) {
  96. BcelShadow s = new BcelShadow(world, getKind(), getSignature(), recipient, enclosing);
  97. List src = mungers;
  98. List dest = s.mungers;
  99. for (Iterator i = src.iterator(); i.hasNext(); ) {
  100. dest.add(i.next());
  101. }
  102. return s;
  103. }
  104. // ---- overridden behaviour
  105. public World getIWorld() {
  106. return world;
  107. }
  108. private void deleteNewAndDup() {
  109. final ConstantPoolGen cpg = getEnclosingClass().getConstantPoolGen();
  110. int depth = 1;
  111. InstructionHandle ih = range.getStart();
  112. while (true) {
  113. Instruction inst = ih.getInstruction();
  114. if (inst instanceof INVOKESPECIAL
  115. && ((INVOKESPECIAL) inst).getName(cpg).equals("<init>")) {
  116. depth++;
  117. } else if (inst instanceof NEW) {
  118. depth--;
  119. if (depth == 0) break;
  120. }
  121. ih = ih.getPrev();
  122. }
  123. // now IH points to the NEW. We're followed by the DUP, and that is followed
  124. // by the actual instruciton we care about.
  125. InstructionHandle newHandle = ih;
  126. InstructionHandle endHandle = newHandle.getNext();
  127. InstructionHandle nextHandle;
  128. if (endHandle.getInstruction() instanceof DUP) {
  129. nextHandle = endHandle.getNext();
  130. retargetFrom(newHandle, nextHandle);
  131. retargetFrom(endHandle, nextHandle);
  132. } else if (endHandle.getInstruction() instanceof DUP_X1) {
  133. InstructionHandle dupHandle = endHandle;
  134. endHandle = endHandle.getNext();
  135. nextHandle = endHandle.getNext();
  136. if (endHandle.getInstruction() instanceof SWAP) {}
  137. else {
  138. // XXX see next XXX comment
  139. throw new RuntimeException("Unhandled kind of new " + endHandle);
  140. }
  141. retargetFrom(newHandle, nextHandle);
  142. retargetFrom(dupHandle, nextHandle);
  143. retargetFrom(endHandle, nextHandle);
  144. } else {
  145. // XXX we want to fail gracefully here. This should not be picked out as a join point,
  146. // probably. So change BcelClassWeaver.match appropriately.
  147. throw new RuntimeException("Unhandled kind of new");
  148. }
  149. // assert (dupHandle.getInstruction() instanceof DUP);
  150. try {
  151. range.getBody().delete(newHandle, endHandle);
  152. } catch (TargetLostException e) {
  153. throw new BCException("shouldn't happen");
  154. }
  155. }
  156. private void retargetFrom(InstructionHandle old, InstructionHandle fresh) {
  157. InstructionTargeter[] sources = old.getTargeters();
  158. if (sources != null) {
  159. for (int i = sources.length - 1; i >= 0; i--) {
  160. sources[i].updateTarget(old, fresh);
  161. }
  162. }
  163. }
  164. protected void prepareForMungers() {
  165. // if we're a constructor call, we need to remove the new:dup or the new:dup_x1:swap,
  166. // and store all our
  167. // arguments on the frame.
  168. // ??? This is a bit of a hack (for the Java langauge). We do this because
  169. // we sometime add code "outsideBefore" when dealing with weaving join points. We only
  170. // do this for exposing state that is on the stack. It turns out to just work for
  171. // everything except for constructor calls and exception handlers. If we were to clean
  172. // this up, every ShadowRange would have three instructionHandle points, the start of
  173. // the arg-setup code, the start of the running code, and the end of the running code.
  174. if (getKind() == ConstructorCall) {
  175. deleteNewAndDup();
  176. initializeArgVars();
  177. } else if (getKind() == ExceptionHandler) {
  178. ShadowRange range = getRange();
  179. InstructionList body = range.getBody();
  180. InstructionHandle start = range.getStart();
  181. InstructionHandle freshIh = body.insert(start, getFactory().NOP);
  182. InstructionTargeter[] targeters = start.getTargeters();
  183. for (int i = 0; i < targeters.length; i++) {
  184. InstructionTargeter t = targeters[i];
  185. if (t instanceof ExceptionRange) {
  186. ExceptionRange er = (ExceptionRange) t;
  187. er.updateTarget(start, freshIh, body);
  188. }
  189. }
  190. }
  191. // now we ask each munger to request our state
  192. for (Iterator iter = mungers.iterator(); iter.hasNext();) {
  193. ShadowMunger munger = (ShadowMunger) iter.next();
  194. munger.specializeOn(this);
  195. }
  196. // If we are an expression kind, we require our target/arguments on the stack
  197. // before we do our actual thing. However, they may have been removed
  198. // from the stack as the shadowMungers have requested state.
  199. // if any of our shadowMungers requested either the arguments or target,
  200. // the munger will have added code
  201. // to pop the target/arguments into temporary variables, represented by
  202. // targetVar and argVars. In such a case, we must make sure to re-push the
  203. // values.
  204. // If we are nonExpressionKind, we don't expect arguments on the stack
  205. // so this is moot. If our argVars happen to be null, then we know that
  206. // no ShadowMunger has squirrelled away our arguments, so they're still
  207. // on the stack.
  208. InstructionFactory fact = getFactory();
  209. if (getKind().argsOnStack() && argVars != null) {
  210. range.insert(
  211. BcelRenderer.renderExprs(fact, world, argVars),
  212. Range.InsideBefore);
  213. if (targetVar != null) {
  214. range.insert(
  215. BcelRenderer.renderExpr(fact, world, targetVar),
  216. Range.InsideBefore);
  217. }
  218. if (getKind() == ConstructorCall) {
  219. range.insert((Instruction) fact.createDup(1), Range.InsideBefore);
  220. range.insert(
  221. fact.createNew(
  222. (ObjectType) BcelWorld.makeBcelType(
  223. getSignature().getDeclaringType())),
  224. Range.InsideBefore);
  225. }
  226. }
  227. }
  228. // ---- getters
  229. public ShadowRange getRange() {
  230. return range;
  231. }
  232. public void setRange(ShadowRange range) {
  233. this.range = range;
  234. }
  235. public int getSourceLine() {
  236. if (range == null) return 0;
  237. int ret = Utility.getSourceLine(range.getStart());
  238. if (ret < 0) return 0;
  239. return ret;
  240. }
  241. // overrides
  242. public TypeX getEnclosingType() {
  243. return world.resolve(getEnclosingClass().getClassName());
  244. }
  245. public LazyClassGen getEnclosingClass() {
  246. return enclosingMethod.getEnclosingClass();
  247. }
  248. public BcelWorld getWorld() {
  249. return world;
  250. }
  251. // ---- factory methods
  252. public static BcelShadow makeConstructorExecution(
  253. BcelWorld world,
  254. LazyMethodGen enclosingMethod,
  255. InstructionHandle justBeforeStart)
  256. {
  257. final InstructionList body = enclosingMethod.getBody();
  258. BcelShadow s =
  259. new BcelShadow(
  260. world,
  261. ConstructorExecution,
  262. world.makeMethodSignature(enclosingMethod),
  263. enclosingMethod,
  264. null);
  265. ShadowRange r = new ShadowRange(body);
  266. r.associateWithShadow(s);
  267. r.associateWithTargets(
  268. Range.genStart(body, justBeforeStart.getNext()),
  269. Range.genEnd(body));
  270. return s;
  271. }
  272. public static BcelShadow makeStaticInitialization(
  273. BcelWorld world,
  274. LazyMethodGen enclosingMethod)
  275. {
  276. InstructionList body = enclosingMethod.getBody();
  277. InstructionHandle ih = body.getStart();
  278. if (ih.getInstruction() instanceof InvokeInstruction) {
  279. InvokeInstruction ii = (InvokeInstruction)ih.getInstruction();
  280. if (ii.getName(enclosingMethod.getEnclosingClass().getConstantPoolGen()).equals(NameMangler.AJC_CLINIT_NAME)) {
  281. ih = ih.getNext();
  282. }
  283. }
  284. BcelShadow s =
  285. new BcelShadow(
  286. world,
  287. StaticInitialization,
  288. world.makeMethodSignature(enclosingMethod),
  289. enclosingMethod,
  290. null);
  291. ShadowRange r = new ShadowRange(body);
  292. r.associateWithShadow(s);
  293. r.associateWithTargets(
  294. Range.genStart(body, ih),
  295. Range.genEnd(body));
  296. return s;
  297. }
  298. /** Make the shadow for an exception handler. Currently makes an empty shadow that
  299. * only allows before advice to be woven into it.
  300. */
  301. public static BcelShadow makeExceptionHandler(
  302. BcelWorld world,
  303. ExceptionRange exceptionRange,
  304. LazyMethodGen enclosingMethod,
  305. InstructionHandle startOfHandler,
  306. BcelShadow enclosingShadow)
  307. {
  308. InstructionList body = enclosingMethod.getBody();
  309. TypeX catchType = exceptionRange.getCatchType();
  310. TypeX inType = enclosingMethod.getEnclosingClass().getType();
  311. BcelShadow s =
  312. new BcelShadow(
  313. world,
  314. ExceptionHandler,
  315. Member.makeExceptionHandlerSignature(inType, catchType),
  316. enclosingMethod,
  317. enclosingShadow);
  318. ShadowRange r = new ShadowRange(body);
  319. r.associateWithShadow(s);
  320. InstructionHandle start = Range.genStart(body, startOfHandler);
  321. InstructionHandle end = Range.genEnd(body, start);
  322. r.associateWithTargets(start, end);
  323. exceptionRange.updateTarget(startOfHandler, start, body);
  324. return s;
  325. }
  326. /** create an init join point associated w/ an interface in the body of a constructor */
  327. public static BcelShadow makeIfaceInitialization(
  328. BcelWorld world,
  329. LazyMethodGen constructor,
  330. BcelShadow ifaceCExecShadow,
  331. Member interfaceConstructorSignature)
  332. {
  333. InstructionList body = constructor.getBody();
  334. TypeX inType = constructor.getEnclosingClass().getType();
  335. BcelShadow s =
  336. new BcelShadow(
  337. world,
  338. Initialization,
  339. interfaceConstructorSignature,
  340. constructor,
  341. null);
  342. s.fallsThrough = true;
  343. ShadowRange r = new ShadowRange(body);
  344. r.associateWithShadow(s);
  345. InstructionHandle start = Range.genStart(body, ifaceCExecShadow.getRange().getStart());
  346. InstructionHandle end = Range.genEnd(body, ifaceCExecShadow.getRange().getEnd());
  347. r.associateWithTargets(start, end);
  348. return s;
  349. }
  350. public static BcelShadow makeIfaceConstructorExecution(
  351. BcelWorld world,
  352. LazyMethodGen constructor,
  353. InstructionHandle next,
  354. Member interfaceConstructorSignature)
  355. {
  356. final InstructionFactory fact = constructor.getEnclosingClass().getFactory();
  357. InstructionList body = constructor.getBody();
  358. TypeX inType = constructor.getEnclosingClass().getType();
  359. BcelShadow s =
  360. new BcelShadow(
  361. world,
  362. ConstructorExecution,
  363. interfaceConstructorSignature,
  364. constructor,
  365. null);
  366. s.fallsThrough = true;
  367. ShadowRange r = new ShadowRange(body);
  368. r.associateWithShadow(s);
  369. // ??? this may or may not work
  370. InstructionHandle start = Range.genStart(body, next);
  371. //InstructionHandle end = Range.genEnd(body, body.append(start, fact.NOP));
  372. InstructionHandle end = Range.genStart(body, next);
  373. //body.append(start, fact.NOP);
  374. r.associateWithTargets(start, end);
  375. return s;
  376. }
  377. /** Create an initialization join point associated with a constructor, but not
  378. * with any body of code yet. If this is actually matched, it's range will be set
  379. * when we inline self constructors.
  380. *
  381. * @param constructor The constructor starting this initialization.
  382. */
  383. public static BcelShadow makeUnfinishedInitialization(
  384. BcelWorld world,
  385. LazyMethodGen constructor)
  386. {
  387. return new BcelShadow(
  388. world,
  389. Initialization,
  390. world.makeMethodSignature(constructor),
  391. constructor,
  392. null);
  393. }
  394. public static BcelShadow makeUnfinishedPreinitialization(
  395. BcelWorld world,
  396. LazyMethodGen constructor)
  397. {
  398. BcelShadow ret = new BcelShadow(
  399. world,
  400. PreInitialization,
  401. world.makeMethodSignature(constructor),
  402. constructor,
  403. null);
  404. ret.fallsThrough = true;
  405. return ret;
  406. }
  407. public static BcelShadow makeMethodExecution(
  408. BcelWorld world,
  409. LazyMethodGen enclosingMethod)
  410. {
  411. return makeShadowForMethod(world, enclosingMethod, MethodExecution,
  412. world.makeMethodSignature(enclosingMethod));
  413. }
  414. public static BcelShadow makeShadowForMethod(BcelWorld world,
  415. LazyMethodGen enclosingMethod, Shadow.Kind kind, Member sig)
  416. {
  417. final InstructionList body = enclosingMethod.getBody();
  418. BcelShadow s =
  419. new BcelShadow(
  420. world,
  421. kind,
  422. sig,
  423. enclosingMethod,
  424. null);
  425. ShadowRange r = new ShadowRange(body);
  426. r.associateWithShadow(s);
  427. r.associateWithTargets(
  428. Range.genStart(body),
  429. Range.genEnd(body));
  430. return s;
  431. }
  432. public static BcelShadow makeAdviceExecution(
  433. BcelWorld world,
  434. LazyMethodGen enclosingMethod)
  435. {
  436. final InstructionList body = enclosingMethod.getBody();
  437. BcelShadow s =
  438. new BcelShadow(
  439. world,
  440. AdviceExecution,
  441. world.makeMethodSignature(enclosingMethod),
  442. enclosingMethod,
  443. null);
  444. ShadowRange r = new ShadowRange(body);
  445. r.associateWithShadow(s);
  446. r.associateWithTargets(Range.genStart(body), Range.genEnd(body));
  447. return s;
  448. }
  449. // constructor call shadows are <em>initially</em> just around the
  450. // call to the constructor. If ANY advice gets put on it, we move
  451. // the NEW instruction inside the join point, which involves putting
  452. // all the arguments in temps.
  453. public static BcelShadow makeConstructorCall(
  454. BcelWorld world,
  455. LazyMethodGen enclosingMethod,
  456. InstructionHandle callHandle,
  457. BcelShadow enclosingShadow)
  458. {
  459. final InstructionList body = enclosingMethod.getBody();
  460. Member sig = world.makeMethodSignature(
  461. enclosingMethod.getEnclosingClass(),
  462. (InvokeInstruction) callHandle.getInstruction());
  463. BcelShadow s =
  464. new BcelShadow(
  465. world,
  466. ConstructorCall,
  467. sig,
  468. enclosingMethod,
  469. enclosingShadow);
  470. ShadowRange r = new ShadowRange(body);
  471. r.associateWithShadow(s);
  472. r.associateWithTargets(
  473. Range.genStart(body, callHandle),
  474. Range.genEnd(body, callHandle));
  475. retargetAllBranches(callHandle, r.getStart());
  476. return s;
  477. }
  478. public static BcelShadow makeMethodCall(
  479. BcelWorld world,
  480. LazyMethodGen enclosingMethod,
  481. InstructionHandle callHandle,
  482. BcelShadow enclosingShadow)
  483. {
  484. final InstructionList body = enclosingMethod.getBody();
  485. BcelShadow s =
  486. new BcelShadow(
  487. world,
  488. MethodCall,
  489. world.makeMethodSignature(
  490. enclosingMethod.getEnclosingClass(),
  491. (InvokeInstruction) callHandle.getInstruction()),
  492. enclosingMethod,
  493. enclosingShadow);
  494. ShadowRange r = new ShadowRange(body);
  495. r.associateWithShadow(s);
  496. r.associateWithTargets(
  497. Range.genStart(body, callHandle),
  498. Range.genEnd(body, callHandle));
  499. retargetAllBranches(callHandle, r.getStart());
  500. return s;
  501. }
  502. public static BcelShadow makeShadowForMethodCall(
  503. BcelWorld world,
  504. LazyMethodGen enclosingMethod,
  505. InstructionHandle callHandle,
  506. BcelShadow enclosingShadow,
  507. Kind kind,
  508. ResolvedMember sig)
  509. {
  510. final InstructionList body = enclosingMethod.getBody();
  511. BcelShadow s =
  512. new BcelShadow(
  513. world,
  514. kind,
  515. sig,
  516. enclosingMethod,
  517. enclosingShadow);
  518. ShadowRange r = new ShadowRange(body);
  519. r.associateWithShadow(s);
  520. r.associateWithTargets(
  521. Range.genStart(body, callHandle),
  522. Range.genEnd(body, callHandle));
  523. retargetAllBranches(callHandle, r.getStart());
  524. return s;
  525. }
  526. public static BcelShadow makeFieldGet(
  527. BcelWorld world,
  528. LazyMethodGen enclosingMethod,
  529. InstructionHandle getHandle,
  530. BcelShadow enclosingShadow)
  531. {
  532. final InstructionList body = enclosingMethod.getBody();
  533. BcelShadow s =
  534. new BcelShadow(
  535. world,
  536. FieldGet,
  537. world.makeFieldSignature(
  538. enclosingMethod.getEnclosingClass(),
  539. (FieldInstruction) getHandle.getInstruction()),
  540. enclosingMethod,
  541. enclosingShadow);
  542. ShadowRange r = new ShadowRange(body);
  543. r.associateWithShadow(s);
  544. r.associateWithTargets(
  545. Range.genStart(body, getHandle),
  546. Range.genEnd(body, getHandle));
  547. retargetAllBranches(getHandle, r.getStart());
  548. return s;
  549. }
  550. public static BcelShadow makeFieldSet(
  551. BcelWorld world,
  552. LazyMethodGen enclosingMethod,
  553. InstructionHandle setHandle,
  554. BcelShadow enclosingShadow)
  555. {
  556. final InstructionList body = enclosingMethod.getBody();
  557. BcelShadow s =
  558. new BcelShadow(
  559. world,
  560. FieldSet,
  561. world.makeFieldSignature(
  562. enclosingMethod.getEnclosingClass(),
  563. (FieldInstruction) setHandle.getInstruction()),
  564. enclosingMethod,
  565. enclosingShadow);
  566. ShadowRange r = new ShadowRange(body);
  567. r.associateWithShadow(s);
  568. r.associateWithTargets(
  569. Range.genStart(body, setHandle),
  570. Range.genEnd(body, setHandle));
  571. retargetAllBranches(setHandle, r.getStart());
  572. return s;
  573. }
  574. public static void retargetAllBranches(InstructionHandle from, InstructionHandle to) {
  575. InstructionTargeter[] sources = from.getTargeters();
  576. if (sources != null) {
  577. for (int i = sources.length - 1; i >= 0; i--) {
  578. InstructionTargeter source = sources[i];
  579. if (source instanceof BranchInstruction) {
  580. source.updateTarget(from, to);
  581. }
  582. }
  583. }
  584. }
  585. // ---- type access methods
  586. public boolean hasThis() {
  587. if (getKind() == PreInitialization) return false;
  588. return !getEnclosingCodeSignature().isStatic();
  589. //???return !enclosingMethod.isStatic();
  590. }
  591. public TypeX getThisType() {
  592. if (!hasThis()) return ResolvedTypeX.MISSING;
  593. return getEnclosingCodeSignature().getDeclaringType();
  594. //???return TypeX.forName(getEnclosingClass().getClassName());
  595. }
  596. public boolean isTargetDifferentFromThis() {
  597. return hasTarget() && isExpressionKind();
  598. }
  599. private ObjectType getTargetBcelType() {
  600. return (ObjectType) world.makeBcelType(getTargetType());
  601. }
  602. private Type getArgBcelType(int arg) {
  603. return world.makeBcelType(getArgType(arg));
  604. }
  605. // ---- kinding
  606. public boolean isExpressionKind() {
  607. if (getKind() == PreInitialization) return true;
  608. return getKind().argsOnStack();
  609. }
  610. // ---- argument getting methods
  611. private BcelVar thisVar = null;
  612. private BcelVar targetVar = null;
  613. private BcelVar[] argVars = null;
  614. public Var getThisVar() {
  615. if (!hasThis()) {
  616. throw new IllegalStateException("no this");
  617. }
  618. initializeThisVar();
  619. return thisVar;
  620. }
  621. public Var getTargetVar() {
  622. if (!hasTarget()) {
  623. throw new IllegalStateException("no target");
  624. }
  625. initializeTargetVar();
  626. return targetVar;
  627. }
  628. public Var getArgVar(int i) {
  629. initializeArgVars();
  630. return argVars[i];
  631. }
  632. // reflective thisJoinPoint support
  633. private BcelVar thisJoinPointVar = null;
  634. private BcelVar thisJoinPointStaticPartVar = null;
  635. private BcelVar thisEnclosingJoinPointStaticPartVar = null;
  636. public final Var getThisJoinPointVar() {
  637. return getThisJoinPointBcelVar();
  638. }
  639. public final Var getThisJoinPointStaticPartVar() {
  640. return getThisJoinPointStaticPartBcelVar();
  641. }
  642. public final Var getThisEnclosingJoinPointStaticPartVar() {
  643. return getThisEnclosingJoinPointStaticPartBcelVar();
  644. }
  645. public BcelVar getThisJoinPointBcelVar() {
  646. if (thisJoinPointVar == null) {
  647. thisJoinPointVar = genTempVar(TypeX.forName("org.aspectj.lang.JoinPoint"));
  648. InstructionFactory fact = getFactory();
  649. InstructionList il = new InstructionList();
  650. BcelVar staticPart = getThisJoinPointStaticPartBcelVar();
  651. staticPart.appendLoad(il, fact);
  652. if (hasThis()) {
  653. ((BcelVar)getThisVar()).appendLoad(il, fact);
  654. } else {
  655. il.append(new ACONST_NULL());
  656. }
  657. if (hasTarget()) {
  658. ((BcelVar)getTargetVar()).appendLoad(il, fact);
  659. } else {
  660. il.append(new ACONST_NULL());
  661. }
  662. il.append(makeArgsObjectArray());
  663. il.append(fact.createInvoke("org.aspectj.runtime.reflect.Factory",
  664. "makeJP", LazyClassGen.tjpType,
  665. new Type[] { LazyClassGen.staticTjpType,
  666. Type.OBJECT, Type.OBJECT, new ArrayType(Type.OBJECT, 1)},
  667. Constants.INVOKESTATIC));
  668. il.append(thisJoinPointVar.createStore(fact));
  669. range.insert(il, Range.OutsideBefore);
  670. }
  671. return thisJoinPointVar;
  672. }
  673. public BcelVar getThisJoinPointStaticPartBcelVar() {
  674. if (thisJoinPointStaticPartVar == null) {
  675. Field field = getEnclosingClass().getTjpField(this);
  676. thisJoinPointStaticPartVar =
  677. new BcelFieldRef(
  678. world.resolve(TypeX.forName("org.aspectj.lang.JoinPoint$StaticPart")),
  679. getEnclosingClass().getClassName(),
  680. field.getName());
  681. }
  682. return thisJoinPointStaticPartVar;
  683. }
  684. public BcelVar getThisEnclosingJoinPointStaticPartBcelVar() {
  685. if (enclosingShadow == null) {
  686. // the enclosing of an execution is itself
  687. return getThisJoinPointStaticPartBcelVar();
  688. } else {
  689. return enclosingShadow.getThisJoinPointStaticPartBcelVar();
  690. }
  691. }
  692. public Member getEnclosingCodeSignature() {
  693. if (enclosingShadow == null) {
  694. return getSignature();
  695. } else {
  696. return enclosingShadow.getSignature();
  697. }
  698. }
  699. private InstructionList makeArgsObjectArray() {
  700. InstructionFactory fact = getFactory();
  701. BcelVar arrayVar = genTempVar(TypeX.OBJECTARRAY);
  702. final InstructionList il = new InstructionList();
  703. int alen = getArgCount() ;
  704. il.append(Utility.createConstant(fact, alen));
  705. il.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1));
  706. arrayVar.appendStore(il, fact);
  707. int stateIndex = 0;
  708. for (int i = 0, len = getArgCount(); i<len; i++) {
  709. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, (BcelVar)getArgVar(i));
  710. stateIndex++;
  711. }
  712. arrayVar.appendLoad(il, fact);
  713. return il;
  714. }
  715. // ---- initializing var tables
  716. /* initializing this is doesn't do anything, because this
  717. * is protected from side-effects, so we don't need to copy its location
  718. */
  719. private void initializeThisVar() {
  720. if (thisVar != null) return;
  721. thisVar = new BcelVar(getThisType().resolve(world), 0);
  722. thisVar.setPositionInAroundState(0);
  723. }
  724. public void initializeTargetVar() {
  725. InstructionFactory fact = getFactory();
  726. if (targetVar != null) return;
  727. if (! isExpressionKind()) {
  728. initializeThisVar();
  729. targetVar = thisVar;
  730. } else {
  731. initializeArgVars(); // gotta pop off the args before we find the target
  732. TypeX type = getTargetType();
  733. targetVar = genTempVar(type, "ajc$target");
  734. range.insert(targetVar.createStore(fact), Range.OutsideBefore);
  735. targetVar.setPositionInAroundState(hasThis() ? 1 : 0);
  736. }
  737. }
  738. public void initializeArgVars() {
  739. if (argVars != null) return;
  740. InstructionFactory fact = getFactory();
  741. int len = getArgCount();
  742. argVars = new BcelVar[len];
  743. int positionOffset = (hasTarget() ? 0 : 1) + (hasThis() ? 0 : 1);
  744. if (getKind().argsOnStack()) {
  745. // we move backwards because we're popping off the stack
  746. for (int i = len - 1; i >= 0; i--) {
  747. TypeX type = getArgType(i);
  748. BcelVar tmp = genTempVar(type, "ajc$arg" + i);
  749. range.insert(tmp.createStore(getFactory()), Range.OutsideBefore);
  750. int position = i;
  751. if (hasTarget()) position += positionOffset;
  752. tmp.setPositionInAroundState(position);
  753. argVars[i] = tmp;
  754. }
  755. } else {
  756. int index = 0;
  757. if (hasThis()) index++;
  758. for (int i = 0; i < len; i++) {
  759. TypeX type = getArgType(i);
  760. BcelVar tmp = genTempVar(type, "ajc$arg" + i);
  761. range.insert(tmp.createCopyFrom(fact, index), Range.OutsideBefore);
  762. argVars[i] = tmp;
  763. int position = i;
  764. if (hasTarget()) position += positionOffset;
  765. tmp.setPositionInAroundState(position);
  766. index += type.getSize();
  767. }
  768. }
  769. }
  770. public void initializeForAroundClosure() {
  771. initializeArgVars();
  772. if (hasTarget()) initializeTargetVar();
  773. if (hasThis()) initializeThisVar();
  774. }
  775. // ---- weave methods
  776. void weaveBefore(BcelAdvice munger) {
  777. range.insert(
  778. munger.getAdviceInstructions(this, null, range.getRealStart()),
  779. Range.InsideBefore);
  780. }
  781. public void weaveAfter(BcelAdvice munger) {
  782. weaveAfterThrowing(munger, TypeX.THROWABLE);
  783. weaveAfterReturning(munger);
  784. }
  785. /**
  786. * We guarantee that the return value is on the top of the stack when
  787. * munger.getAdviceInstructions() will be run
  788. * (Unless we have a void return type in which case there's nothing)
  789. */
  790. public void weaveAfterReturning(BcelAdvice munger) {
  791. InstructionFactory fact = getFactory();
  792. List returns = new ArrayList();
  793. Instruction ret = null;
  794. for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) {
  795. if (ih.getInstruction() instanceof ReturnInstruction) {
  796. returns.add(ih);
  797. ret = ih.getInstruction().copy();
  798. }
  799. }
  800. InstructionList retList;
  801. InstructionHandle afterAdvice;
  802. if (ret != null) {
  803. retList = new InstructionList(ret);
  804. afterAdvice = retList.getStart();
  805. } else /* if (munger.hasDynamicTests()) */ {
  806. retList = new InstructionList(fact.NOP);
  807. afterAdvice = retList.getStart();
  808. // } else {
  809. // retList = new InstructionList();
  810. // afterAdvice = null;
  811. }
  812. InstructionList advice = new InstructionList();
  813. BcelVar tempVar = null;
  814. if (munger.hasExtraParameter()) {
  815. TypeX tempVarType = getReturnType();
  816. if (tempVarType.equals(ResolvedTypeX.VOID)) {
  817. tempVar = genTempVar(TypeX.OBJECT);
  818. advice.append(getFactory().ACONST_NULL);
  819. tempVar.appendStore(advice, getFactory());
  820. } else {
  821. tempVar = genTempVar(tempVarType);
  822. advice.append(getFactory().createDup(tempVarType.getSize()));
  823. tempVar.appendStore(advice, getFactory());
  824. }
  825. }
  826. advice.append(munger.getAdviceInstructions(this, tempVar, afterAdvice));
  827. if (ret != null) {
  828. InstructionHandle gotoTarget = advice.getStart();
  829. for (Iterator i = returns.iterator(); i.hasNext(); ) {
  830. InstructionHandle ih = (InstructionHandle) i.next();
  831. Utility.replaceInstruction(ih, fact.createBranchInstruction(Constants.GOTO, gotoTarget), enclosingMethod);
  832. }
  833. range.append(advice);
  834. range.append(retList);
  835. } else {
  836. range.append(advice);
  837. range.append(retList);
  838. }
  839. }
  840. public void weaveAfterThrowing(BcelAdvice munger, TypeX catchType) {
  841. // a good optimization would be not to generate anything here
  842. // if the shadow is GUARANTEED empty (i.e., there's NOTHING, not even
  843. // a shadow, inside me).
  844. if (getRange().getStart().getNext() == getRange().getEnd()) return;
  845. InstructionFactory fact = getFactory();
  846. InstructionList handler = new InstructionList();
  847. BcelVar exceptionVar = genTempVar(catchType);
  848. exceptionVar.appendStore(handler, fact);
  849. InstructionList endHandler = new InstructionList(
  850. exceptionVar.createLoad(fact));
  851. handler.append(munger.getAdviceInstructions(this, exceptionVar, endHandler.getStart()));
  852. handler.append(endHandler);
  853. handler.append(fact.ATHROW);
  854. InstructionHandle handlerStart = handler.getStart();
  855. if (isFallsThrough()) {
  856. InstructionHandle jumpTarget = handler.append(fact.NOP);
  857. handler.insert(fact.createBranchInstruction(Constants.GOTO, jumpTarget));
  858. }
  859. InstructionHandle protectedEnd = handler.getStart();
  860. range.insert(handler, Range.InsideAfter);
  861. enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(),
  862. handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType), //???Type.THROWABLE,
  863. // high priority if our args are on the stack
  864. isExpressionKind());
  865. }
  866. public void weaveSoftener(BcelAdvice munger, TypeX catchType) {
  867. InstructionFactory fact = getFactory();
  868. InstructionList handler = new InstructionList();
  869. BcelVar exceptionVar = genTempVar(catchType);
  870. exceptionVar.appendStore(handler, fact);
  871. handler.append(fact.createNew(NameMangler.SOFT_EXCEPTION_TYPE));
  872. handler.append(fact.createDup(1));
  873. handler.append(exceptionVar.createLoad(fact));
  874. handler.append(fact.createInvoke(NameMangler.SOFT_EXCEPTION_TYPE, "<init>",
  875. Type.VOID, new Type[] { Type.THROWABLE }, Constants.INVOKESPECIAL)); //??? special
  876. handler.append(fact.ATHROW);
  877. InstructionHandle handlerStart = handler.getStart();
  878. if (isFallsThrough()) {
  879. InstructionHandle jumpTarget = range.getEnd();//handler.append(fact.NOP);
  880. handler.insert(fact.createBranchInstruction(Constants.GOTO, jumpTarget));
  881. }
  882. InstructionHandle protectedEnd = handler.getStart();
  883. range.insert(handler, Range.InsideAfter);
  884. enclosingMethod.addExceptionHandler(range.getStart().getNext(), protectedEnd.getPrev(),
  885. handlerStart, (ObjectType)BcelWorld.makeBcelType(catchType),
  886. // high priority if our args are on the stack
  887. isExpressionKind());
  888. }
  889. public void weavePerObjectEntry(final BcelAdvice munger, final BcelVar onVar) {
  890. final InstructionFactory fact = getFactory();
  891. InstructionList entryInstructions = new InstructionList();
  892. InstructionList entrySuccessInstructions = new InstructionList();
  893. onVar.appendLoad(entrySuccessInstructions, fact);
  894. entrySuccessInstructions.append(
  895. Utility.createInvoke(fact, world,
  896. AjcMemberMaker.perObjectBind(munger.getConcreteAspect())));
  897. InstructionList testInstructions =
  898. munger.getTestInstructions(this, entrySuccessInstructions.getStart(),
  899. range.getRealStart(),
  900. entrySuccessInstructions.getStart());
  901. entryInstructions.append(testInstructions);
  902. entryInstructions.append(entrySuccessInstructions);
  903. range.insert(entryInstructions, Range.InsideBefore);
  904. }
  905. public void weaveCflowEntry(final BcelAdvice munger, final Member cflowStackField) {
  906. final boolean isPer = munger.getKind() == AdviceKind.PerCflowBelowEntry ||
  907. munger.getKind() == AdviceKind.PerCflowEntry;
  908. final Type objectArrayType = new ArrayType(Type.OBJECT, 1);
  909. final InstructionFactory fact = getFactory();
  910. final BcelVar testResult = genTempVar(ResolvedTypeX.BOOLEAN);
  911. InstructionList entryInstructions = new InstructionList();
  912. {
  913. InstructionList entrySuccessInstructions = new InstructionList();
  914. if (munger.hasDynamicTests()) {
  915. entryInstructions.append(Utility.createConstant(fact, 0));
  916. testResult.appendStore(entryInstructions, fact);
  917. entrySuccessInstructions.append(Utility.createConstant(fact, 1));
  918. testResult.appendStore(entrySuccessInstructions, fact);
  919. }
  920. if (isPer) {
  921. entrySuccessInstructions.append(
  922. fact.createInvoke(munger.getConcreteAspect().getName(),
  923. NameMangler.PERCFLOW_PUSH_METHOD,
  924. Type.VOID,
  925. new Type[] { },
  926. Constants.INVOKESTATIC));
  927. } else {
  928. BcelVar[] cflowStateVars = munger.getExposedStateAsBcelVars();
  929. BcelVar arrayVar = genTempVar(TypeX.OBJECTARRAY);
  930. int alen = cflowStateVars.length;
  931. entrySuccessInstructions.append(Utility.createConstant(fact, alen));
  932. entrySuccessInstructions.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1));
  933. arrayVar.appendStore(entrySuccessInstructions, fact);
  934. for (int i = 0; i < alen; i++) {
  935. arrayVar.appendConvertableArrayStore(entrySuccessInstructions, fact, i, cflowStateVars[i]);
  936. }
  937. entrySuccessInstructions.append(
  938. Utility.createGet(fact, cflowStackField));
  939. arrayVar.appendLoad(entrySuccessInstructions, fact);
  940. entrySuccessInstructions.append(
  941. fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "push", Type.VOID,
  942. new Type[] { objectArrayType },
  943. Constants.INVOKEVIRTUAL));
  944. }
  945. InstructionList testInstructions =
  946. munger.getTestInstructions(this, entrySuccessInstructions.getStart(),
  947. range.getRealStart(),
  948. entrySuccessInstructions.getStart());
  949. entryInstructions.append(testInstructions);
  950. entryInstructions.append(entrySuccessInstructions);
  951. }
  952. // this is the same for both per and non-per
  953. weaveAfter(new BcelAdvice(null, null, null, 0, 0, 0, null, null) {
  954. public InstructionList getAdviceInstructions(BcelShadow s, BcelVar extraArgVar, InstructionHandle ifNoAdvice) {
  955. InstructionList exitInstructions = new InstructionList();
  956. if (munger.hasDynamicTests()) {
  957. testResult.appendLoad(exitInstructions, fact);
  958. exitInstructions.append(fact.createBranchInstruction(Constants.IFEQ, ifNoAdvice));
  959. }
  960. exitInstructions.append(
  961. Utility.createGet(fact, cflowStackField));
  962. exitInstructions.append(
  963. fact.createInvoke(NameMangler.CFLOW_STACK_TYPE, "pop", Type.VOID, new Type[] {}, Constants.INVOKEVIRTUAL));
  964. return exitInstructions;
  965. }});
  966. range.insert(entryInstructions, Range.InsideBefore);
  967. }
  968. public void weaveAroundInline(
  969. BcelAdvice munger,
  970. boolean hasDynamicTest)
  971. {
  972. /* Implementation notes:
  973. *
  974. * AroundInline still extracts the instructions of the original shadow into
  975. * an extracted method. This allows inlining of even that advice that doesn't
  976. * call proceed or calls proceed more than once.
  977. *
  978. * It extracts the instructions of the original shadow into a method.
  979. *
  980. * Then it inlines the instructions of the advice in its place, taking care
  981. * to treat the closure argument specially (it doesn't exist).
  982. *
  983. * Then it searches in the instructions of the advice for any call to the
  984. * proceed method.
  985. *
  986. * At such a call, there is stuff on the stack representing the arguments to
  987. * proceed. Pop these into the frame.
  988. *
  989. * Now build the stack for the call to the extracted method, taking values
  990. * either from the join point state or from the new frame locs from proceed.
  991. * Now call the extracted method. The right return value should be on the
  992. * stack, so no cast is necessary.
  993. *
  994. * If only one call to proceed is made, we can re-inline the original shadow.
  995. * We are not doing that presently.
  996. */
  997. // start by exposing various useful things into the frame
  998. final InstructionFactory fact = getFactory();
  999. // now generate the aroundBody method
  1000. LazyMethodGen extractedMethod =
  1001. extractMethod(
  1002. NameMangler.aroundCallbackMethodName(
  1003. getSignature(),
  1004. getEnclosingClass()));
  1005. // the shadow is now empty. First, create a correct call
  1006. // to the around advice. This includes both the call (which may involve
  1007. // value conversion of the advice arguments) and the return
  1008. // (which may involve value conversion of the return value). Right now
  1009. // we push a null for the unused closure. It's sad, but there it is.
  1010. InstructionList advice = new InstructionList();
  1011. InstructionHandle adviceMethodInvocation;
  1012. {
  1013. // ??? we don't actually need to push NULL for the closure if we take care
  1014. advice.append(munger.getAdviceArgSetup(this, null, new InstructionList(fact.ACONST_NULL)));
  1015. adviceMethodInvocation =
  1016. advice.append(
  1017. Utility.createInvoke(fact, getWorld(), munger.getSignature()));
  1018. advice.append(
  1019. Utility.createConversion(
  1020. getFactory(),
  1021. world.makeBcelType(munger.getSignature().getReturnType()),
  1022. extractedMethod.getReturnType()));
  1023. if (! isFallsThrough()) {
  1024. advice.append(fact.createReturn(extractedMethod.getReturnType()));
  1025. }
  1026. }
  1027. // now, situate the call inside the possible dynamic tests,
  1028. // and actually add the whole mess to the shadow
  1029. if (! hasDynamicTest) {
  1030. range.append(advice);
  1031. } else {
  1032. InstructionList callback = makeCallToCallback(extractedMethod);
  1033. if (! isExpressionKind()) {
  1034. callback.append(fact.createReturn(extractedMethod.getReturnType()));
  1035. } else {
  1036. advice.append(fact.createBranchInstruction(Constants.GOTO, range.getEnd()));
  1037. }
  1038. range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart()));
  1039. range.append(advice);
  1040. range.append(callback);
  1041. }
  1042. // now the range contains everything we need. We now inline the advice method.
  1043. LazyMethodGen adviceMethod =
  1044. ((BcelObjectType) munger.getConcreteAspect())
  1045. .getLazyClassGen()
  1046. .getLazyMethodGen(munger.getSignature());
  1047. BcelClassWeaver.inlineMethod(adviceMethod, enclosingMethod, adviceMethodInvocation);
  1048. // now search through the advice, looking for a call to PROCEED.
  1049. // Then we replace the call to proceed with some argument setup, and a
  1050. // call to the extracted method.
  1051. String proceedName =
  1052. NameMangler.proceedMethodName(munger.getSignature().getName());
  1053. InstructionHandle curr = getRange().getStart();
  1054. InstructionHandle end = getRange().getEnd();
  1055. ConstantPoolGen cpg = extractedMethod.getEnclosingClass().getConstantPoolGen();
  1056. while (curr != end) {
  1057. InstructionHandle next = curr.getNext();
  1058. Instruction inst = curr.getInstruction();
  1059. if ((inst instanceof INVOKESTATIC)
  1060. && proceedName.equals(((INVOKESTATIC) inst).getMethodName(cpg))) {
  1061. enclosingMethod.getBody().append(curr, getRedoneProceedCall(fact, extractedMethod, munger));
  1062. Utility.deleteInstruction(curr, enclosingMethod);
  1063. }
  1064. curr = next;
  1065. }
  1066. // and that's it.
  1067. }
  1068. private InstructionList getRedoneProceedCall(
  1069. InstructionFactory fact,
  1070. LazyMethodGen callbackMethod,
  1071. BcelAdvice munger)
  1072. {
  1073. InstructionList ret = new InstructionList();
  1074. // we have on stack all the arguments for the ADVICE call.
  1075. // we have in frame somewhere all the arguments for the non-advice call.
  1076. List argVarList = new ArrayList();
  1077. // start w/ stuff
  1078. if (targetVar != null) argVarList.add(targetVar);
  1079. for (int i = 0, len = getArgCount(); i < len; i++) {
  1080. argVarList.add(argVars[i]);
  1081. }
  1082. BcelVar[] adviceVars = munger.getExposedStateAsBcelVars();
  1083. //??? this is too easy
  1084. // for (int i=0; i < adviceVars.length; i++) {
  1085. // if (adviceVars[i] != null)
  1086. // adviceVars[i].setPositionInAroundState(i);
  1087. // }
  1088. IntMap proceedMap = makeProceedArgumentMap(adviceVars);
  1089. // System.out.println(proceedMap);
  1090. // System.out.println(Arrays.asList(adviceVars));
  1091. ResolvedTypeX[] proceedParamTypes = world.resolve(munger.getSignature().getParameterTypes());
  1092. BcelVar[] proceedVars =
  1093. Utility.pushAndReturnArrayOfVars(proceedParamTypes, ret, fact, enclosingMethod);
  1094. Type[] stateTypes = callbackMethod.getArgumentTypes();
  1095. for (int i=0, len=stateTypes.length; i < len; i++) {
  1096. Type stateType = stateTypes[i];
  1097. ResolvedTypeX stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
  1098. if (proceedMap.hasKey(i)) {
  1099. //throw new RuntimeException("unimplemented");
  1100. proceedVars[proceedMap.get(i)].appendLoadAndConvert(ret, fact, stateTypeX);
  1101. } else {
  1102. ((BcelVar) argVarList.get(i)).appendLoad(ret, fact);
  1103. }
  1104. }
  1105. ret.append(Utility.createInvoke(fact, callbackMethod));
  1106. ret.append(Utility.createConversion(fact, callbackMethod.getReturnType(),
  1107. BcelWorld.makeBcelType(munger.getSignature().getReturnType())));
  1108. return ret;
  1109. }
  1110. public void weaveAroundClosure(
  1111. BcelAdvice munger,
  1112. boolean hasDynamicTest)
  1113. {
  1114. InstructionFactory fact = getFactory();
  1115. // MOVE OUT ALL THE INSTRUCTIONS IN MY SHADOW INTO ANOTHER METHOD!
  1116. LazyMethodGen callbackMethod =
  1117. extractMethod(
  1118. NameMangler.aroundCallbackMethodName(
  1119. getSignature(),
  1120. getEnclosingClass()));
  1121. BcelVar[] adviceVars = munger.getExposedStateAsBcelVars();
  1122. String closureClassName =
  1123. NameMangler.makeClosureClassName(
  1124. getEnclosingClass().getType(),
  1125. getEnclosingClass().getNewGeneratedNameTag());
  1126. Member constructorSig = new Member(Member.CONSTRUCTOR,
  1127. TypeX.forName(closureClassName), 0, "<init>",
  1128. "([Ljava/lang/Object;)V");
  1129. BcelVar closureHolder = null;
  1130. // This is not being used currently since getKind() == preinitializaiton
  1131. // cannot happen in around advice
  1132. if (getKind() == PreInitialization) {
  1133. closureHolder = genTempVar(AjcMemberMaker.AROUND_CLOSURE_TYPE);
  1134. }
  1135. InstructionList closureInstantiation =
  1136. makeClosureInstantiation(constructorSig, closureHolder);
  1137. LazyMethodGen constructor =
  1138. makeClosureClassAndReturnConstructor(
  1139. closureClassName,
  1140. callbackMethod,
  1141. makeProceedArgumentMap(adviceVars)
  1142. );
  1143. InstructionList returnConversionCode;
  1144. if (getKind() == PreInitialization) {
  1145. returnConversionCode = new InstructionList();
  1146. BcelVar stateTempVar = genTempVar(TypeX.OBJECTARRAY);
  1147. closureHolder.appendLoad(returnConversionCode, fact);
  1148. returnConversionCode.append(
  1149. Utility.createInvoke(
  1150. fact,
  1151. world,
  1152. AjcMemberMaker.aroundClosurePreInitializationGetter()));
  1153. stateTempVar.appendStore(returnConversionCode, fact);
  1154. Type[] stateTypes = getSuperConstructorParameterTypes();
  1155. returnConversionCode.append(fact.ALOAD_0); // put "this" back on the stack
  1156. for (int i = 0, len = stateTypes.length; i < len; i++) {
  1157. stateTempVar.appendConvertableArrayLoad(
  1158. returnConversionCode,
  1159. fact,
  1160. i,
  1161. world.resolve(BcelWorld.fromBcel(stateTypes[i])));
  1162. }
  1163. } else {
  1164. returnConversionCode =
  1165. Utility.createConversion(
  1166. getFactory(),
  1167. world.makeBcelType(munger.getSignature().getReturnType()),
  1168. callbackMethod.getReturnType());
  1169. if (! isFallsThrough()) {
  1170. returnConversionCode.append(fact.createReturn(callbackMethod.getReturnType()));
  1171. }
  1172. }
  1173. InstructionList advice = new InstructionList();
  1174. advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation));
  1175. // advice.append(closureInstantiation);
  1176. advice.append(munger.getNonTestAdviceInstructions(this));
  1177. advice.append(returnConversionCode);
  1178. if (! hasDynamicTest) {
  1179. range.append(advice);
  1180. } else {
  1181. InstructionList callback = makeCallToCallback(callbackMethod);
  1182. InstructionList postCallback = new InstructionList();
  1183. if (! isExpressionKind()) {
  1184. callback.append(fact.createReturn(callbackMethod.getReturnType()));
  1185. } else {
  1186. advice.append(fact.createBranchInstruction(Constants.GOTO, postCallback.append(fact.NOP)));
  1187. }
  1188. range.append(munger.getTestInstructions(this, advice.getStart(), callback.getStart(), advice.getStart()));
  1189. range.append(advice);
  1190. range.append(callback);
  1191. range.append(postCallback);
  1192. }
  1193. }
  1194. // exposed for testing
  1195. InstructionList makeCallToCallback(LazyMethodGen callbackMethod) {
  1196. InstructionFactory fact = getFactory();
  1197. InstructionList callback = new InstructionList();
  1198. if (thisVar != null) {
  1199. callback.append(fact.ALOAD_0);
  1200. }
  1201. if (targetVar != null && targetVar != thisVar) {
  1202. callback.append(BcelRenderer.renderExpr(fact, world, targetVar));
  1203. }
  1204. callback.append(BcelRenderer.renderExprs(fact, world, argVars));
  1205. // remember to render tjps
  1206. if (thisJoinPointVar != null) {
  1207. callback.append(BcelRenderer.renderExpr(fact, world, thisJoinPointVar));
  1208. }
  1209. callback.append(Utility.createInvoke(fact, callbackMethod));
  1210. return callback;
  1211. }
  1212. /** side-effect-free */
  1213. private InstructionList makeClosureInstantiation(Member constructor, BcelVar holder) {
  1214. // LazyMethodGen constructor) {
  1215. InstructionFactory fact = getFactory();
  1216. BcelVar arrayVar = genTempVar(TypeX.OBJECTARRAY);
  1217. //final Type objectArrayType = new ArrayType(Type.OBJECT, 1);
  1218. final InstructionList il = new InstructionList();
  1219. int alen = getArgCount() + (thisVar == null ? 0 : 1) +
  1220. ((targetVar != null && targetVar != thisVar) ? 1 : 0) +
  1221. (thisJoinPointVar == null ? 0 : 1);
  1222. il.append(Utility.createConstant(fact, alen));
  1223. il.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1));
  1224. arrayVar.appendStore(il, fact);
  1225. int stateIndex = 0;
  1226. if (thisVar != null) {
  1227. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisVar);
  1228. thisVar.setPositionInAroundState(stateIndex);
  1229. stateIndex++;
  1230. }
  1231. if (targetVar != null && targetVar != thisVar) {
  1232. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, targetVar);
  1233. targetVar.setPositionInAroundState(stateIndex);
  1234. stateIndex++;
  1235. }
  1236. for (int i = 0, len = getArgCount(); i<len; i++) {
  1237. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, argVars[i]);
  1238. argVars[i].setPositionInAroundState(stateIndex);
  1239. stateIndex++;
  1240. }
  1241. if (thisJoinPointVar != null) {
  1242. arrayVar.appendConvertableArrayStore(il, fact, stateIndex, thisJoinPointVar);
  1243. thisJoinPointVar.setPositionInAroundState(stateIndex);
  1244. stateIndex++;
  1245. }
  1246. il.append(fact.createNew(new ObjectType(constructor.getDeclaringType().getName())));
  1247. il.append(new DUP());
  1248. arrayVar.appendLoad(il, fact);
  1249. il.append(Utility.createInvoke(fact, world, constructor));
  1250. if (getKind() == PreInitialization) {
  1251. il.append(fact.DUP);
  1252. holder.appendStore(il, fact);
  1253. }
  1254. return il;
  1255. }
  1256. private IntMap makeProceedArgumentMap(BcelVar[] adviceArgs) {
  1257. //System.err.println("coming in with " + Arrays.asList(adviceArgs));
  1258. IntMap ret = new IntMap();
  1259. for(int i = 0, len = adviceArgs.length; i < len; i++) {
  1260. BcelVar v = (BcelVar) adviceArgs[i];
  1261. if (v == null) continue; // XXX we don't know why this is required
  1262. int pos = v.getPositionInAroundState();
  1263. if (pos >= 0) { // need this test to avoid args bound via cflow
  1264. ret.put(pos, i);
  1265. }
  1266. }
  1267. //System.err.println("returning " + ret);
  1268. return ret;
  1269. }
  1270. /**
  1271. *
  1272. *
  1273. * @param callbackMethod the method we will call back to when our run method gets called.
  1274. *
  1275. * @param proceedMap A map from state position to proceed argument position. May be
  1276. * non covering on state position.
  1277. */
  1278. private LazyMethodGen makeClosureClassAndReturnConstructor(
  1279. String closureClassName,
  1280. LazyMethodGen callbackMethod,
  1281. IntMap proceedMap)
  1282. {
  1283. String superClassName = "org.aspectj.runtime.internal.AroundClosure";
  1284. Type objectArrayType = new ArrayType(Type.OBJECT, 1);
  1285. LazyClassGen closureClass = new LazyClassGen(closureClassName,
  1286. superClassName,
  1287. getEnclosingClass().getFileName(),
  1288. Modifier.PUBLIC,
  1289. new String[] {});
  1290. InstructionFactory fact = new InstructionFactory(closureClass.getConstantPoolGen());
  1291. // constructor
  1292. LazyMethodGen constructor = new LazyMethodGen(Modifier.PUBLIC,
  1293. Type.VOID,
  1294. "<init>",
  1295. new Type[] {objectArrayType},
  1296. new String[] {},
  1297. closureClass);
  1298. InstructionList cbody = constructor.getBody();
  1299. cbody.append(fact.createLoad(Type.OBJECT, 0));
  1300. cbody.append(fact.createLoad(objectArrayType, 1));
  1301. cbody.append(fact.createInvoke(superClassName, "<init>", Type.VOID,
  1302. new Type[] {objectArrayType}, Constants.INVOKESPECIAL));
  1303. cbody.append(fact.createReturn(Type.VOID));
  1304. closureClass.addMethodGen(constructor);
  1305. // method
  1306. LazyMethodGen runMethod = new LazyMethodGen(Modifier.PUBLIC,
  1307. Type.OBJECT,
  1308. "run",
  1309. new Type[] {objectArrayType},
  1310. new String[] {},
  1311. closureClass);
  1312. InstructionList mbody = runMethod.getBody();
  1313. BcelVar proceedVar = new BcelVar(TypeX.OBJECTARRAY.resolve(world), 1);
  1314. // int proceedVarIndex = 1;
  1315. BcelVar stateVar = new BcelVar(TypeX.OBJECTARRAY.resolve(world), runMethod.allocateLocal(1));
  1316. // int stateVarIndex = runMethod.allocateLocal(1);
  1317. mbody.append(fact.createThis());
  1318. mbody.append(fact.createGetField(superClassName, "state", objectArrayType));
  1319. mbody.append(stateVar.createStore(fact));
  1320. // mbody.append(fact.createStore(objectArrayType, stateVarIndex));
  1321. Type[] stateTypes = callbackMethod.getArgumentTypes();
  1322. for (int i=0, len=stateTypes.length; i < len; i++) {
  1323. Type stateType = stateTypes[i];
  1324. ResolvedTypeX stateTypeX = BcelWorld.fromBcel(stateType).resolve(world);
  1325. if (proceedMap.hasKey(i)) {
  1326. mbody.append(
  1327. proceedVar.createConvertableArrayLoad(fact, proceedMap.get(i),
  1328. stateTypeX));
  1329. } else {
  1330. mbody.append(
  1331. stateVar.createConvertableArrayLoad(fact, i,
  1332. stateTypeX));
  1333. }
  1334. }
  1335. mbody.append(Utility.createInvoke(fact, callbackMethod));
  1336. if (getKind() == PreInitialization) {
  1337. mbody.append(Utility.createSet(
  1338. fact,
  1339. AjcMemberMaker.aroundClosurePreInitializationField()));
  1340. mbody.append(fact.ACONST_NULL);
  1341. } else {
  1342. mbody.append(
  1343. Utility.createConversion(
  1344. fact,
  1345. callbackMethod.getReturnType(),
  1346. Type.OBJECT));
  1347. }
  1348. mbody.append(fact.createReturn(Type.OBJECT));
  1349. closureClass.addMethodGen(runMethod);
  1350. // class
  1351. getEnclosingClass().addGeneratedInner(closureClass);
  1352. return constructor;
  1353. }
  1354. // ---- extraction methods
  1355. public LazyMethodGen extractMethod(String newMethodName) {
  1356. LazyMethodGen.assertGoodBody(range.getBody(), newMethodName);
  1357. if (!getKind().allowsExtraction()) throw new BCException();
  1358. LazyMethodGen freshMethod = createMethodGen(newMethodName);
  1359. // System.err.println("******");
  1360. // System.err.println("ABOUT TO EXTRACT METHOD for" + this);
  1361. // enclosingMethod.print(System.err);
  1362. // System.err.println("INTO");
  1363. // freshMethod.print(System.err);
  1364. // System.err.println("WITH REMAP");
  1365. // System.err.println(makeRemap());
  1366. range.extractInstructionsInto(freshMethod, makeRemap(),
  1367. (getKind() != PreInitialization) &&
  1368. isFallsThrough());
  1369. if (getKind() == PreInitialization) {
  1370. addPreInitializationReturnCode(
  1371. freshMethod,
  1372. getSuperConstructorParameterTypes());
  1373. }
  1374. getEnclosingClass().addMethodGen(freshMethod);
  1375. return freshMethod;
  1376. }
  1377. private void addPreInitializationReturnCode(
  1378. LazyMethodGen extractedMethod,
  1379. Type[] superConstructorTypes)
  1380. {
  1381. InstructionList body = extractedMethod.getBody();
  1382. final InstructionFactory fact = getFactory();
  1383. BcelVar arrayVar = new BcelVar(
  1384. world.resolve(TypeX.OBJECTARRAY),
  1385. extractedMethod.allocateLocal(1));
  1386. int len = superConstructorTypes.length;
  1387. body.append(Utility.createConstant(fact, len));
  1388. body.append((Instruction)fact.createNewArray(Type.OBJECT, (short)1));
  1389. arrayVar.appendStore(body, fact);
  1390. for (int i = len - 1; i >= 0; i++) {
  1391. // convert thing on top of stack to object
  1392. body.append(
  1393. Utility.createConversion(fact, superConstructorTypes[i], Type.OBJECT));
  1394. // push object array
  1395. arrayVar.appendLoad(body, fact);
  1396. // swap
  1397. body.append(fact.SWAP);
  1398. // do object array store.
  1399. body.append(Utility.createConstant(fact, i));
  1400. body.append(fact.SWAP);
  1401. body.append(fact.createArrayStore(Type.OBJECT));
  1402. }
  1403. arrayVar.appendLoad(body, fact);
  1404. body.append(fact.ARETURN);
  1405. }
  1406. private Type[] getSuperConstructorParameterTypes() {
  1407. // assert getKind() == PreInitialization
  1408. InstructionHandle superCallHandle = getRange().getEnd().getNext();
  1409. InvokeInstruction superCallInstruction =
  1410. (InvokeInstruction) superCallHandle.getInstruction();
  1411. return superCallInstruction.getArgumentTypes(
  1412. getEnclosingClass().getConstantPoolGen());
  1413. }
  1414. /** make a map from old frame location to new frame location. Any unkeyed frame
  1415. * location picks out a copied local */
  1416. private IntMap makeRemap() {
  1417. IntMap ret = new IntMap(5);
  1418. int reti = 0;
  1419. if (thisVar != null) {
  1420. ret.put(0, reti++); // thisVar guaranteed to be 0
  1421. }
  1422. if (targetVar != null && targetVar != thisVar) {
  1423. ret.put(targetVar.getSlot(), reti++);
  1424. }
  1425. for (int i = 0, len = argVars.length; i < len; i++) {
  1426. ret.put(argVars[i].getSlot(), reti);
  1427. reti += argVars[i].getType().getSize();
  1428. }
  1429. if (thisJoinPointVar != null) {
  1430. ret.put(thisJoinPointVar.getSlot(), reti++);
  1431. }
  1432. // we not only need to put the arguments, we also need to remap their
  1433. // aliases, which we so helpfully put into temps at the beginning of this join
  1434. // point.
  1435. if (! getKind().argsOnStack()) {
  1436. int oldi = 0;
  1437. int newi = 0;
  1438. // if we're passing in a this and we're not argsOnStack we're always
  1439. // passing in a target too
  1440. if (hasThis()) { ret.put(0, 0); oldi++; newi+=1; }
  1441. //assert targetVar == thisVar
  1442. for (int i = 0; i < getArgCount(); i++) {
  1443. TypeX type = getArgType(i);
  1444. ret.put(oldi, newi);
  1445. oldi += type.getSize();
  1446. newi += type.getSize();
  1447. }
  1448. }
  1449. return ret;
  1450. }
  1451. /**
  1452. * The new method always static.
  1453. * It may take some extra arguments: this, target.
  1454. * If it's argsOnStack, then it must take both this/target
  1455. * If it's argsOnFrame, it shares this and target.
  1456. * ??? rewrite this to do less array munging, please
  1457. */
  1458. private LazyMethodGen createMethodGen(String newMethodName) {
  1459. Type[] parameterTypes = world.makeBcelTypes(getSignature().getParameterTypes());
  1460. int modifiers = Modifier.FINAL;
  1461. // XXX some bug
  1462. // if (! isExpressionKind() && getSignature().isStrict(world)) {
  1463. // modifiers |= Modifier.STRICT;
  1464. // }
  1465. modifiers |= Modifier.STATIC;
  1466. if (targetVar != null && targetVar != thisVar) {
  1467. TypeX targetType = getTargetType();
  1468. ResolvedMember resolvedMember = getSignature().resolve(world);
  1469. if (resolvedMember != null && Modifier.isProtected(resolvedMember.getModifiers()) &&
  1470. !samePackage(targetType.getPackageName(), getThisType().getPackageName()))
  1471. {
  1472. if (!targetType.isAssignableFrom(getThisType(), world)) {
  1473. throw new BCException("bad bytecode");
  1474. }
  1475. targetType = getThisType();
  1476. }
  1477. parameterTypes = addType(world.makeBcelType(targetType), parameterTypes);
  1478. }
  1479. if (thisVar != null) {
  1480. TypeX thisType = getThisType();
  1481. parameterTypes = addType(world.makeBcelType(thisType), parameterTypes);
  1482. }
  1483. // We always want to pass down thisJoinPoint in case we have already woven
  1484. // some advice in here. If we only have a single piece of around advice on a
  1485. // join point, it is unnecessary to accept (and pass) tjp.
  1486. if (thisJoinPointVar != null) {
  1487. parameterTypes = addTypeToEnd(LazyClassGen.tjpType, parameterTypes);
  1488. }
  1489. TypeX returnType;
  1490. if (getKind() == ConstructorCall) {
  1491. returnType = getSignature().getDeclaringType();
  1492. } else if (getKind() == PreInitialization) {
  1493. returnType = TypeX.OBJECTARRAY;
  1494. } else {
  1495. returnType = getSignature().getReturnType();
  1496. }
  1497. return
  1498. new LazyMethodGen(
  1499. modifiers,
  1500. world.makeBcelType(returnType),
  1501. newMethodName,
  1502. parameterTypes,
  1503. new String[0],
  1504. // XXX again, we need to look up methods!
  1505. // TypeX.getNames(getSignature().getExceptions(world)),
  1506. getEnclosingClass());
  1507. }
  1508. private boolean samePackage(String p1, String p2) {
  1509. if (p1 == null) return p2 == null;
  1510. if (p2 == null) return false;
  1511. return p1.equals(p2);
  1512. }
  1513. private Type[] addType(Type type, Type[] types) {
  1514. int len = types.length;
  1515. Type[] ret = new Type[len+1];
  1516. ret[0] = type;
  1517. System.arraycopy(types, 0, ret, 1, len);
  1518. return ret;
  1519. }
  1520. private Type[] addTypeToEnd(Type type, Type[] types) {
  1521. int len = types.length;
  1522. Type[] ret = new Type[len+1];
  1523. ret[len] = type;
  1524. System.arraycopy(types, 0, ret, 0, len);
  1525. return ret;
  1526. }
  1527. public BcelVar genTempVar(TypeX typeX) {
  1528. return new BcelVar(typeX.resolve(world), genTempVarIndex(typeX.getSize()));
  1529. }
  1530. // public static final boolean CREATE_TEMP_NAMES = true;
  1531. public BcelVar genTempVar(TypeX typeX, String localName) {
  1532. BcelVar tv = genTempVar(typeX);
  1533. // if (CREATE_TEMP_NAMES) {
  1534. // for (InstructionHandle ih = range.getStart(); ih != range.getEnd(); ih = ih.getNext()) {
  1535. // if (Range.isRangeHandle(ih)) continue;
  1536. // ih.addTargeter(new LocalVariableTag(typeX, localName, tv.getSlot()));
  1537. // }
  1538. // }
  1539. return tv;
  1540. }
  1541. // eh doesn't think we need to garbage collect these (64K is a big number...)
  1542. private int genTempVarIndex(int size) {
  1543. return enclosingMethod.allocateLocal(size);
  1544. }
  1545. public InstructionFactory getFactory() {
  1546. return getEnclosingClass().getFactory();
  1547. }
  1548. public SourceLocation getSourceLocation() {
  1549. return new SourceLocation(new File(getEnclosingClass().getFileName()), getSourceLine());
  1550. }
  1551. public BcelShadow getEnclosingShadow() {
  1552. return enclosingShadow;
  1553. }
  1554. public LazyMethodGen getEnclosingMethod() {
  1555. return enclosingMethod;
  1556. }
  1557. public boolean isFallsThrough() {
  1558. return fallsThrough;
  1559. }
  1560. }