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

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